有时间序列的脚本编写

技术注解 #57
2021年3月

作者:Tessa Hayman

Tessa Hayman指导你通过Python脚本处理时间序列的复杂性,并解释了如何以一种可以在用户界面中可视化的方式创建你的自定义时间序列。

什么是时间序列?

时间序列是一组与一个目标有关的数据,这些数据随时间变化。 例如,一个路段的流量计数将被存储在一个时间序列中,每个检测间隔的值,例如15分钟。

在Aimsun Next中,你可以在一个目标的时间序列标签中查看时间序列。 举例,一个副本:

一个时间序列是GKTimeSerie类别的一个目标,它被存储在一个属性中,即GKColumn,它所指向的目标的。 你可以从这个目标读取标准差、最大值、最小值、平均值和RMS: GKTimeSerie

每个GKTimeSerie h都有一个相对应的描述目标 (GKTSDescription). 这包含它所适用的时间序列的持续时间、开始和结束时间、间隔等信息。

这个GKTimeSerieIndex 目标是用来访问一个时间序列的特定区间,你想为其读取或写入一个值。 要指定第5个区间,你可以使用 GKTimeSerieIndex(4) 因为编号从0开始。

如何从一个时间序列中读取数据

T从一个目标中取得间序列,你可以调用getDataValueTS() ,将存储它的GKColumn作为参数。

如果你想从一个目标的时间序列中直接获得一个区间的值,你可以调用方法 getDataValueInTS(),除了存储时间序列的GKColumn,还将GKTimeSerieIndex作为参数。

注意getDataValueInTS() 返回一个元组,其中第一项是时间序列的值,第二项是偏差。

要找到一个列的名称,你可以在检索数据库或运行模型后在类型窗口中寻找。 例如,下面是以下的输出: GKSection。

该名称由以下部分组成:

  • 静态还是动态
  • 目标类型
  • 输出名称
  • 副本ID
  • 车辆类型ID (或0代表所有的车辆)
  • 车道数字 (或0代表所有车道)

例如,要读取一个副本一个间隔一个路段上的密度,可以使用以下函数。 请注意,第一个区间被标记为0,第二个区间被标记为1,以此类推。

				
					def readdensity( section, interval, replicationid, lanenumber, vehicleid=0 ):
column = model.getColumn( "DYNAMIC::GKSection_density_"+str(replicationid)+"_"+str(vehicleid)+"_"+str(lanenumber) )
	(value, deviation) = section.getDataValueInTS( column, GKTimeSerieIndex(interval) )
	return value

				
			

如何向时间序列写入数据

为了创建新的时间序列,我们必须:

  • 创建存储与给定类型的每个目标相关的时间序列的列
  • 创建一个时间序列描述(GKTSDescription),它至少需要定义开始时间、结束时间、时间序列的时间间隔、以及可选择性的空值以及如何计算整个时期的汇总值
  • 在循环浏览目标的同时,循环浏览间隔时间,并调用方法 setDataValueInTS() 来填充该区间的数值。

例如,下面的脚本为节点创建了一个时间序列,其中存储了一天中该时间段活动的控制计划的周期时间。 它以15分钟的时间间隔囊括了主控制计划所涵盖的时期。 你必须把它分配到“主控制计划”的菜单中,并通过右击主控制计划运行它。

				
					fromDate = QDateTime(QDate().currentDate(), target.initialTime())
toDate = fromDate.addSecs(target.duration().toSeconds()[0])
interval = GKTimeDuration(0, 15, 0)
fromDate = fromDate.addSecs(interval.toSeconds()[0])

type = model.getType("GKNode")
column = type.getColumn( "GKNode::cycle_%s" % target.getId(), GKType.eSearchOnlyThisType )
if column == None:
	column = type.addColumn( "GKNode::cycle_%s" % target.getId(), GK.BuildContents("Cycle Time", target), GKColumn._GKTimeSerie, GKColumn.eExternal )
column.setConversion(GK.eConversionUndefined, "", "")

tsDescription = GKTSDescription.getCreateDescription( column, "cycleTime" )
tsDescription.setAggregationType(GK.eAggregationUndefined)
tsDescription.setNullValue(-1)
tsDescription.setTime(fromDate, toDate, interval)

now = fromDate
while now <= toDate:
	fromTime = now.time().second()+now.time().minute()*60+now.time().hour()*3600
	for node in model.getCatalog().getObjectsByType(type).itervalues():
		controlJunction = target.getControlJunction(node.getId(), fromTime, fromTime+1)[0]
		if controlJunction != None:
			cycle = controlJunction.getCycle()
			node.setDataValueInTS(column, GKTimeSerieIndex(tsDescription.getInterval(now)), cycle, 0.0, tsDescription)
	now = now.addSecs(interval.toSeconds()[0])

				
			

注意一个列用GK.BuildContents创建,以便正确设置发起目标,在这种情况下是选定的主控制计划。

如果列和时间序列描述定义正确,时间序列将出现在信号灯节点的对话框中。

如果你对多个主控制计划运行脚本,你可以使用时间序列图来快速发现差异,例如工作日的周期和周末的周期。

  • 有问题吗? 请联系我们。

    我们在这里提供帮助!

  • 有问题吗? 请联系我们。

    我们在这里提供帮助!

分享