3、交通需求生成:用flowrouter和duarouter搞定交通流

大家好,我是老张。今天咱们聊聊交通需求生成这块。说实话,很多新手在SUMO里卡住的地方,就是不知道怎么把路网和车流串起来。你路网画得再漂亮,没有车跑,那就是个空城计。

我个人习惯把交通需求生成分成两派:静态路线和动态OD流。前者适合小场景测试,后者才是仿真实战的标配。咱们一个一个说。

3.1 先搞懂.rou.xml文件长啥样

路线文件,后缀是.rou.xml。说白了,它就是告诉SUMO:什么车、从哪出发、走哪条路、什么时候出发。

一个最简单的例子:

<routes>
    <vType id="car" accel="2.6" decel="4.5" sigma="0.5" length="4.5" maxSpeed="50"/>
    <vehicle id="v0" type="car" depart="0">
        <route edges="edge1 edge2 edge3"/>
    </vehicle>
</routes>

嗯,这里要注意:depart是出发时间,单位秒。edges里写的是路网中的edge ID,顺序不能乱。我在项目中遇到过有人把edge写反了,结果车直接逆行——SUMO虽然不会报警,但仿真结果全废了。

3.2 定义车辆类型(vType)——别小看这一步

很多教程把vType一笔带过,但我得说,vType是仿真精度的基石。你想想看,一辆卡车和一辆小轿车的加速度能一样吗?

参数 含义 典型值(小车) 典型值(卡车)
accel 最大加速度 (m/s²) 2.6 1.2
decel 最大减速度 (m/s²) 4.5 2.5
sigma 驾驶不完美度 (0~1) 0.5 0.3
length 车辆长度 (m) 4.5 10.0
maxSpeed 最高速度 (m/s) 50.0 30.0
我的小技巧:sigma值设成0.5左右最接近真实驾驶。设成0就是完美机器人,设成1就是醉驾。我曾经在测试自动驾驶算法时,故意把sigma调高到0.8,用来模拟人类驾驶员的随机性——效果出奇的好。

3.3 用duarouter生成静态路线

duarouter是SUMO自带的路线计算工具。你给它一个OD对(起点-终点),它帮你算最短路径。适合场景固定的仿真。

用法很简单:

duarouter --net-file mynet.net.xml \
          --route-files trips.xml \
          --output-file routes.rou.xml

这里的trips.xml长这样:

<trips>
    <trip id="t0" depart="0" from="edge1" to="edge5"/>
    <trip id="t1" depart="10" from="edge2" to="edge8"/>
</trips>
避坑指南:我曾经在项目里用duarouter生成上千条路线,结果发现所有车都挤在同一条路上。为什么?因为duarouter默认用最短路径,而我的路网里有一条路特别短。后来我加了权重参数才解决。记住:最短路径 ≠ 最真实路径。

3.4 用flowrouter处理动态OD流

flowrouter就高级多了。它适合做宏观交通流生成。你给它一个OD矩阵,它自动生成车流,还能考虑路网容量。

基本用法:

flowrouter.py --net-file mynet.net.xml \
              --flows-file flows.xml \
              --output-file routes.rou.xml \
              --flow-output flows.xml

flows.xml示例:

<flows>
    <flow id="f1" from="edge1" to="edge5" begin="0" end="3600" number="500"/>
    <flow id="f2" from="edge2" to="edge8" begin="0" end="3600" number="300"/>
</flows>

这里number="500"表示1小时内发500辆车。flowrouter会自动分配每辆车的出发时间,避免扎堆。

3.5 随机交通流生成——实战中最常用的

说实话,我90%的项目都用随机流。因为真实交通就是随机的。SUMO里生成随机流有两种方式:

  1. 用flow标签配合random参数:适合简单场景
  2. 用Python脚本生成:适合复杂需求

先看第一种:

<flow id="random_flow" type="car" from="edge1" to="edge5" 
      begin="0" end="3600" probability="0.1"/>

probability="0.1"表示每秒有10%的概率发一辆车。这个参数我特别喜欢,因为它能模拟出车流忽密忽疏的效果。

第二种,用Python脚本生成随机路线:

import random
import xml.etree.ElementTree as ET

routes = ET.Element("routes")
vType = ET.SubElement(routes, "vType", id="car", accel="2.6", decel="4.5", sigma="0.5")

for i in range(100):
    depart = random.uniform(0, 3600)
    veh = ET.SubElement(routes, "vehicle", id=f"v{i}", type="car", depart=str(depart))
    route = ET.SubElement(veh, "route", edges="edge1 edge2 edge3")

tree = ET.ElementTree(routes)
tree.write("random_routes.rou.xml")
核心要点:随机流生成时,出发时间用均匀分布还是泊松分布?我个人建议用泊松分布。因为真实的车流到达时间服从泊松分布,而不是均匀分布。你想想看,如果每10秒整整齐齐发一辆车,那还是真实交通吗?

3.6 本章知识体系总览

下面这张图,是我自己总结的交通需求生成流程。建议你保存下来,写脚本时对照着看:

交通需求生成核心流程 路网文件 .net.xml OD需求 trips.xml / flows.xml 车辆类型定义 vType参数 工具选择 duarouter(静态) / flowrouter(动态) 路线文件 .rou.xml 随机流生成:Python脚本 / probability参数 / 泊松分布
我的建议:刚开始学的时候,先用duarouter跑通一个简单案例。等熟悉了,再上flowrouter和随机流。别一上来就搞复杂场景——我见过太多人把路网和路线搞混,debug到崩溃。

好了,这一章的内容就到这。交通需求生成是仿真的灵魂,你花多少功夫都不为过。下一章咱们聊聊怎么让这些车跑起来,以及如何采集仿真数据。

可可精品资料库