VISSIM

从 VISSIM *.inpx 文件导入功能的扩展工具#

Caution

文档正在编写中 -- 更多文档即将推出...

待办事项:

  • 翻译成英文

SUMO 网络转换的扩展#

随着 PTV 公司商业微观交通仿真软件的第 6 版发布(该软件不仅在德语区用于可视化交通行为),文件格式已更改为基于 XML 的 .inpx 格式。然而,SUMO 工具 netconvert(用于将其他源格式的网络转换为 SUMO 网络)在 0.23.0 版本之前仍基于旧的 .inp 格式,因此必须使用更新的版本才能转换当前的 .inpx 格式网络。由于除了读取网络信息外,程序流程没有变化,因此使用 netconvert 转换 VISSIM 网络的操作对于用户来说保持不变。

在转换 .inpx 网络的过程中,通过读取 VISSIM 中的冲突区域定义,还会定义 SUMO 路口内的优先级。

此外,针对基于 XML 的 .inpx 格式,开发了额外的 Python 工具,用于在转换原始网络信息后,读取路线、流量、信号灯和检测器等信息。

使用方法#

调用 netconvert 处理 VISSIM 网络的命令如下:

netconvert --vissim-file=<VISSIM_FILE> --output-file=MySUMOFile.net.xml

在转换过程中会自动检查 VISSIM 网络是新的 inpx 格式还是旧的 inp 格式。因此,用户无需关心 VISSIM 网络的版本。但是,如果除了纯粹的网络转换外,还要使用额外的 Python 工具转换其他数据,则网络必须是 .inpx 格式。

示例#

根据网络的复杂程度,可能需要在转换后进行进一步的调整。下图展示了将 .inpx 网络转换为 SUMO 网络的示例。

Vissim_net.png SUMO_net.png

“路口转换”图展示了一个在 VISSIM 中创建并随后转换到 SUMO 的复杂交叉口。该图显示几何形状(和转弯关系)被正确转换。

TurningRelation_VISSIM.png TurningRelation_SUMO.png

根据 VISSIM 冲突区域确定优先级#

为了检查冲突区域的转换,创建了一个违反常规右侧通行优先规则的 VISSIM 交叉口。随后使用 netconvert 将 VISSIM 网络转换为 SUMO 网络。在“冲突区域”图中可以看到,左转车辆相对于直行车辆的优先权被正确转换。

冲突区域

conflArea_vissim.png conflArea_sumo.png

有关所示情况的数据可以在测试数据目录 tests/netconvert/import/leftist_conflictarea-prio/ 中找到,其中也包含相应的 README.md

路线和流量的转换#

路线和流量的定义是仿真的重要组成部分。Python 工具 convert_vissimXML_flows_statRoutes.py 能够解析 VISSIM 的路线和流量,并根据这些信息为转换后的网络创建 SUMO 路线文件。该文件后缀为 .rou.xml,在仿真时作为参数指定。转换过程中仅支持静态路线定义,即包含确切路线顺序的定义。调用方法如下:

convert_vissimXML_flows_statRoutes.py -V <vissim-file> -n <sumo-net-file> -o <output-filename>

VISSIM 路线定义#

流量在 .inpx 文件中通过 XML 标签 <timeIntervalVehVolume> 标识。流量始终分配给一条路段,并通过名称(可以为空)和唯一的 ID 定义。由于车辆流量随时间变化,流量会添加时间间隔,由车辆组成和交通流量定义。时间间隔的开始时间以毫秒为单位,交通流量的单位为 辆/小时 (Fz/h)。VISSIM 中的流量定义如下所示:

  <vehicleInput anmFlag="false" link="9" name="Parkplatz 30221" no="1">
     <timeIntVehVols>
        <timeIntervalVehVolume cont="false" timeInt="1 0" vehComp="6" volType="STOCHASTIC" volume="48.000000"/>
        <timeIntervalVehVolume cont="false" timeInt="1 900000" vehComp="6" volType="STOCHASTIC" volume="84.000000"/>
        <timeIntervalVehVolume cont="false" timeInt="1 1800000" vehComp="6" volType="STOCHASTIC" volume="120.040000"/>
        <timeIntervalVehVolume cont="false" timeInt="1 2700000" vehComp="6" volType="STOCHASTIC" volume="120.040000"/>
     </timeIntVehVols>
  </vehicleInput>

路线决策在 VISSIM 中通过其起点进行汇总。从一条路段可以发出多条静态路线,通向不同的目标路段。这由属性 destLink 给出。对于每条路线,像流量一样,会设定时间间隔,定义该路线流量的相对比例。路线的路径由所经过的路段序列给出,由 XML 标签 <linkSeq> 引导。路线定义示例如下:

<vehicleRoutingDecisionStatic allVehTypes="true" anmFlag="false" combineStaRoutDec="false" link="9" name="Parkplatz 30221" no="1" pos="1.000000">
     <vehicleRouteStatic destLink="205" destPos="20.916000" name="" no="113" relFlow="2 0:4.000000, 2 900000:6.990000, 2 1800000:9.990000, 2 2700000:9.990000, 2 3600000:12.660000, 2 4500000:16.330000, 2 5400000:20.990000, 2 6300000:15.660000, 2 7200000:16.660000, 2 8100000:16.330000">
        <linkSeq>
           <intObjectRef key="10381"/>
           <intObjectRef key="269"/>
           <intObjectRef key="10154"/>
           <intObjectRef key="117"/>
           <intObjectRef key="10150"/>
           <intObjectRef key="76"/>
           <intObjectRef key="10145"/>
        </linkSeq>
     </vehicleRouteStatic>
  </vehicleRoutingDecisionStatic>

SUMO 路线定义#

在 SUMO 中,可以定义类似 VISSIM 的路线,即多条路线从一个共同的起点汇总。分布中的每条路线通过其路段序列及其概率定义。所有路线的概率之和必须始终为 1,对路线分布的引用通过其唯一的 ID 进行:

<routeDistribution id="81_900.0">
   <route edges="81 83 210 211 268 117 76 115 213 212 114 265 203 204 263 109 52 188 297 190 296 186 70 298 238 299 124" id="163" probability="0.372751499001"/>
   <route edges="81 83 210 211 268 117 76 115 213 212 114 265 203 204 263 109 52 188 297 190 296 186 70 298 238 299 239 72 " id="181" probability="0.125916055963"/>
   <route edges="81 83 210 211 268 117 76 115 213 212 114 265 203 204 263 109 52 188 297 190 296 186 181 184" id="187" probability="0.171219187209"/>
   <route edges="81 83 215 216 217 272 16" id="193" probability="0.211192538308"/>
   <route edges="81 83 210 211 268 13" id="195" probability="0.11892071952"/>
</routeDistribution>

此外,路线定义还包括车辆类型分布。这些分布给出了定义的车辆类型的属性和概率,并且必须事先定义。与路线分布一样,引用也是通过唯一的 ID 进行的:

<vTypeDistribution id="6">
   <vType accel="3.500000" id="t1001_D6" length="4.454081632653061" maxSpeed="14.722222222222221" probability="0.900000"/>
   <vType accel="7.300000" id="t1002_D6" length="10.086636363636364" maxSpeed="14.722222222222221" vClass="truck" probability="0.100000"/>
</vTypeDistribution>

车辆流量也在路线文件中定义。像在 VISSIM 中一样,流量是针对特定时间间隔设定的。重要的是,流量必须按时间升序排序,否则无法正确读取。此外,每个流量还分配有一个先前定义的路线分布、一个车辆类型分布以及一个 ID。SUMO 中的流量定义如下:

<flow begin="0.0" color="1,1,0" end="900.0" id="fl81_st0.0" route="81_0.0" type="6" vehsPerHour="94.56"/>
<flow begin="900.0" color="1,1,0" end="1800.0" id="fl81_st900.0" route="81_900.0" type="6" vehsPerHour="120.08"/>
<flow begin="1800.0" color="1,1,0" end="2700.0" id="fl108_st1800.0" route="108_1800.0" type="6" vehsPerHour="161.88"/>

有关定义路线和流量的一般信息,请参见 https://sumo.dlr.de/docs/Definition_of_Vehicles,_Vehicle_Types,_and_Routes.html(最后检查日期 2015.07.28)。

实现#

通过工具 convert_vissimXML_flows_statRoutes.py 进行转换时,会采用以下 VISSIM 属性:

  • 静态路线决策
  • 流量
  • 车辆类型
    • 速度
    • 长度
    • 最大加速度
    • 车辆组成

由于在 VISSIM 中,速度、加速度和长度是概率分布,因此必须从数据中计算平均值。此外,请注意流量必须按时间排序,以保证正确的转换。在编辑流量时,也必须注意时间顺序。该工具会生成一个 .rou.xml 文件,其中包含 SUMO 仿真所需的所有相关路线信息。随后必须将此文件添加到 SUMO 配置文件中。

信号灯程序的转换#

额外的工具 tls_vissimXML2SUMO.py 能够解析 VISSIM 信号灯,并将这些信息添加到转换后的 SUMO 网络中。调用方法如下:

tls_vissimXML2SUMO.py -V <vissim-file> -S <sumo-file> -o <output-filename>

信号灯定义:VISSIM#

在 VISSIM 中,每个创建的信号灯都会生成一个额外的 .sig 文件。该文件包含定义的信号灯程序的所有相关信息(如信号序列和信号顺序)。信号灯的其余定义位于相关网络的现有 .inpx 文件中。下面通过一个示例展示这些文件的结构。

.inpx 文件#

.inpx 文件中,信号灯通过 XML 标签 <signalController> 标识。转换为 SUMO 格式所需的属性是相关的 .sig 文件以及定义的信号组列表。信号组可以分配给多个车道,并由信号序列定义。这些可以在子元素 <signalOutputConfigurationElement> 的属性中找到。VISSIM 中的信号灯定义如下所示:

<signalController active="true" cycTm="0.000000" cycTmIsVar="true" debug="false" guiFile="VISSIG_GUI.dll" name="VLSA 301 (WienerStr./JudendorferStr.)" no="301" offset="0.000000" progFile="VISSIG_Controller.dll" progNo="1" scDetRecFile="VISSIM_302.ldp" scDetRecShortNam="false" sigTmsTabAutoConfig="true" supplyFile1="vissig.config" supplyFile2="TestsiteGraz_v01301.sig" supplyFile3="" type="FIXEDTIME">
     <sGs>
        <signalGroup amber="0.000000" greenFlsh="0.000000" minGreen="0.000000" minRed="0.000000" name="11GR" no="1" redAmber="0.000000" type="NORMAL"/>
        < ... >
        <signalGroup amber="0.000000" greenFlsh="0.000000" minGreen="0.000000" minRed="0.000000" name="14R" no="8" redAmber="0.000000" type="NORMAL"/>
     </sGs>
     <wttFiles>
        <intObjectRef key="1"/>
     </wttFiles>
     <sigTmsTabConfig>
        <signalOutputConfigurationElement configName="SIGGRP" detPort="0" sg="301 1" title="" varNo="1" wttFilename="vissim"/>
        <signalOutputConfigurationElement configName="SIGGRP" detPort="0" sg="301 2" title="" varNo="2" wttFilename="vissim"/>
     </sigTmsTabConfig>
  </signalController>

.inpx 文件中还有所有信号灯的信号灯定义。这些分配给路段的一个车道,并属于先前定义的信号组:

<signalHeads>
     <signalHead allPedTypes="true" allVehTypes="true" complRate="1.000000" dischRecAct="false" isBlockSig="false" lane="223 1" localNo="6" name="" no="1" pos="98.115000" sg="305 6" slowDownDist="3.000000" type="CIRCULAR" vAmberBlock="0.000000"/>
     <signalHead allPedTypes="true" allVehTypes="true" complRate="1.000000" dischRecAct="false" isBlockSig="false" lane="276 3" localNo="5" name="" no="2" pos="82.377000" sg="305 5" slowDownDist="3.000000" type="CIRCULAR" vAmberBlock="0.000000"/>
  </signalHeads>

.sig 文件#

信号相位在 .sig 文件中通过其 ID 引用。哪个 ID 属于哪个相位,在文件开头定义如下:

 <signaldisplays>
     <display id="1" name="Red" state="RED"/>
     <display id="2" name="Red/Amber" state="REDAMBER"/>
  </signaldisplays>

此外,VISSIM 使用固定的信号序列来定义信号程序,这些也可以在 .sig 文件的开头找到。这些定义了相位的顺序,引用通过各自的 ID 进行:

<signalsequences>
   <signalsequence id="5" name="Red-Red/Amber-Green-Flashing Green-Amber">
      <state display="1" isFixedDuration="false" isClosed="true" defaultDuration="1000" />
      <state display="2" isFixedDuration="true" isClosed="true" defaultDuration="1000" />
      <state display="3" isFixedDuration="false" isClosed="false" defaultDuration="5000" />
      <state display="5" isFixedDuration="true" isClosed="false" defaultDuration="4000" />
      <state display="4" isFixedDuration="true" isClosed="true" defaultDuration="3000" />
   </signalsequence>
   <signalsequence id="12" name="Off-Green">
      <state display="7" isFixedDuration="false" isClosed="true" defaultDuration="1000" />
      <state display="3" isFixedDuration="false" isClosed="false" defaultDuration="5000" />
   </signalsequence>
</signalsequences>

随后是所有信号程序及其周期时间的定义:

<prog id="1" cycletime="80000" switchpoint="0" offset="13000" intergreens="0" fitness="0.000000" vehicleCount="0" name="Morgenprogramm S 2.7"/>

信号组的定义包括红灯和绿灯阶段的开始时间,以及位于相关信号序列中的其余阶段的时间长度:

<sg sg_id="1" signal_sequence="5">
   <cmds>
      <cmd display="3" begin="13000" />
      <cmd display="1" begin="46000" />
   </cmds>
   <fixedstates>
      <fixedstate display="2" duration="2000" />
      <fixedstate display="5" duration="4000" />
      <fixedstate display="4" duration="3000" />
   </fixedstates>
</sg>

信号灯定义:SUMO#

与 VISSIM 不同,SUMO 不需要为每个信号灯提供额外的文件;所有信号灯及其程序的定义都写入现有的网络文件中,该文件也包含所有图形信息。下面解释 SUMO 中示例性的信号灯定义。

在 SUMO 网络文件中,信号灯通过 XML 元素节点 <tlLogic> 标识。可以分配属性 idtypeoffsetprogramID,但在转换时仅定义 idprogramID。信号灯的 ID 必须与分配的交叉口 ID 相同(junction id = tlLogic id),programID 描述开关程序的名称。属性 type 恒定设置为 “static”,这意味着相位具有固定的时间长度。信号灯的时间偏移由属性 offset 指定,也恒定设置为 0.00。作为子元素,可以找到开关的各个相位,由秒数的时间跨度和状态标识。states 的每个字母定义一个车道的当前状态:

<tlLogic id="69" type="static" programID="Tagesprogramm S 5.3" offset="0.00">
   <phase duration="20.00" state="Grrr"/>
   <phase duration="20.00" state="yyyy"/>
   <phase duration="100.00" state="rGGG"/>
   <phase duration="100.00" state="yyyy"/>
</tlLogic>

哪个 state-Index 分配给哪个车道,是在相关的 Connection 中通过其 linkIndex 定义的。此外,受信号灯影响的每个 Connection 都必须分配给该信号灯。为此,将相应信号灯的 ID 分配给属性 tl

<connection dir="r" from="117" fromLane="0" to="88" toLane="0" via=":69_1_0" tl="69" linkIndex="2" state="o"/>
<connection dir="s" from="117" fromLane="0" to="76" toLane="0" via=":69_2_0" tl="69" linkIndex="3" state="o"/>
<connection dir="s" from="117" fromLane="1" to="76" toLane="1" via=":69_2_1" tl="69" linkIndex="1" state="o"/>
<connection dir="r" from="89" fromLane="0" to="76" toLane="0" via=":69_0_0" tl="69" linkIndex="0" state="o"/>

放置信号灯的 junction 也必须定义为此类型。这通过属性 type 完成,该属性确定交叉口的控制方式。如果给 junction 分配了信号灯,则 type 必须设置为 “traffic_light”:

<junction id="69" incLanes="89_0 117_0 117_1" intLanes=":69_0_0 :69_1_0 :69_2_0 :69_2_1" shape="3276.61,1952.22 3277.64,1946.15 3275.74,1944.30 3269.32,1943.27 3265.23,1952.29 3274.96,1953.43" type="traffic_light" x="3273.91" y="1947.87">
   <request cont="0" foes="1100" index="0" response="1100"/>
   <request cont="0" foes="0000" index="1" response="0000"/>
   <request cont="0" foes="0001" index="2" response="0000"/>
   <request cont="0" foes="0001" index="3" response="0000"/>
</junction>

此外,SUMO 可以为一个信号灯定义多个程序。这是通过定义每周自动开关(简称 WAUT)来实现的。通过属性 startProg 确定仿真开始时应选择哪个程序。该起始程序从 VISSIM .inpx 文件中获取,信号程序的分配通过其 ProgramID 进行。在仿真期间,信号程序可以在 GUI 中手动更改,也可以通过子元素 <wautSwitch> 在指定时间点更改:

<WAUT refTime="0" id="myWAUT" startProg="weekday_night">
   <wautSwitch time="21600" to="weekday_day"/>
   <wautSwitch time="79200" to="weekday_night"/>
</WAUT>

有关信号灯定义的更详细描述,请参见 https://sumo.dlr.de/docs/Simulation/Traffic_Lights.html(最后检查日期 2015.07.28)。

实现#

与其他工具不同,这里还必须读取所有为每个信号灯自动生成的 .sig 文件。这些文件必须像 VISSIM 要求的那样,位于与 .inpx 文件相同的文件夹中。在转换所有信号灯开关图后,将用信号灯的信息补充先前转换的 SUMO .net 文件。会读取所有可以通过 WAUT 切换的信号程序。仿真开始时选择的默认程序在 VISSIM 网络的 .inpx 文件中定义,并从中获取。

示例#

311_vissim.png 311_sumo.png

这里可以看到通过 VISSIM 和 SUMO 的图形界面对比两个信号程序。该图显示实现的信号组是一致的。然而,由于 VISSIM 中存在绿灯闪烁状态,而 SUMO 中未定义该状态,因此在转换时必须将其简化为绿灯。此外,可以看到并非所有 VISSIM 中的信号组都在转换到 SUMO 时被采用。这些虽然在 VISSIM 中定义,但未分配给任何路段,因此对仿真没有影响。

感应线圈和行程时间测量的转换#

Python 脚本 convert_detectors2SUMO.py 能够从 VISSIM 网络中读取感应线圈和行程时间测量,并将其添加到先前通过 netconvert 转换的 SUMO 网络中。转换后会生成一个额外的 .add.xml 文件,随后必须将其添加到 SUMO 的仿真配置文件中。调用方法如下:

convert_detectors2SUMO.py -V <vissim-file> -S <sumo-file> -o <output-filename>

检测器定义 VISSIM#

断面测量在 VISSIM 中通过 XML 标签 <dataCollectionPoint> 标识。各个检测器的位置由路段的相应车道及其里程标给出:

<dataCollectionPoint lane="108 1" name="301.41" no="1" pos="162.558473"/>
<dataCollectionPoint lane="262 4" name="301.12" no="10" pos="32.960054"/>

行程时间测量在 VISSIM 中不是基于车道,而是基于路段。为此,需设定路段以及起点和终点的里程标:

<vehicleTravelTimeMeasurement name="Wienerstrasse_Sueden" no="1">
   <start link="207" pos="239.836000"/>
   <end link="126" pos="12.867000"/>
</vehicleTravelTimeMeasurement>

检测器定义 SUMO#

感应线圈在 SUMO 中的定义类似于 VISSIM 中的断面测量。定位时同样指定车道和里程标。但是,还可以定义数据聚合的时间间隔。

<inductionLoop file="ind_out.xml" period="900" id="1_301.41" lane="108_0" pos="162.554736186"/>
<inductionLoop file="ind_out.xml" period="900" id="33_359.21" lane="123_0" pos="28.1962390136"/>

与感应线圈一样,行程时间测量也是通过聚合的时间间隔及其位置定义的。但在 SUMO 中,与 VISSIM 不同,行程时间测量不需要涉及整条路段,因为可以定义应考虑哪些车道。

<entryExitDetector file="time_out.xml" period="900" id="1">
   <detEntry lane="207_0" pos="239.753789696"/>
   <detEntry lane="207_1" pos="241.370532161"/>
   <detExit lane="126_0" pos="23.2884507277"/>
   <detExit lane="126_1" pos="23.2873152316"/>
</entryExitDetector>

实现#

由于在网络转换过程中,VISSIM 中的连接路段被汇总为 SUMO 的 junctions,路段长度无法精确保留。这导致里程标也不再匹配。因此,需要确定 VISSIM 中的检测器坐标,然后将其转换为 SUMO 坐标。为了确定 SUMO 中的里程标,随后会在路段上寻找距离先前确定的坐标最近的点。

转换行程时间测量时出现的另一个问题是,测量必须始终定义为一个封闭区域,而在 VISSIM 中并非如此。如果车辆通过行程时间测量的终点,但从未到达起点,则会在仿真期间产生错误消息。