4、交通需求建模:车辆类型定义(.vtype.xml)、交通流定义(.flow.xml)、路线定义(.rou.xml)
好,咱们进入第四章。这一章可以说是整个SUMO仿真的“灵魂”所在——交通需求建模。说白了,就是告诉SUMO:路上跑的是什么车?它们从哪来、到哪去?怎么个跑法?
我个人习惯把这三兄弟称为“铁三角”:.vtype.xml(车辆类型)、.flow.xml(交通流)、.rou.xml(路线)。缺一个,仿真就跑不起来。嗯,咱们一个一个拆开讲。
核心逻辑:车辆类型定义“车长什么样”,交通流定义“车怎么来”,路线定义“车往哪走”。三者通过ID关联,形成一个完整的交通需求。
4.1 车辆类型定义(.vtype.xml)
先说说车辆类型。你想想看,仿真里如果所有车都长一个样、跑一个速度,那还仿真个啥?所以我们需要定义不同类型的车辆。
我在项目中遇到过这样一个坑:有一次做交叉口仿真,所有车都用默认参数,结果仿真出来的排队长度跟实际差了30%。后来才发现,是没区分小轿车和公交车——公交车又长又慢,排队当然不一样。
<!-- vtype.xml 示例 -->
<vType id="car" length="4.5" maxSpeed="60" accel="2.6" decel="4.5" sigma="0.5" color="blue"/>
<vType id="bus" length="12.0" maxSpeed="40" accel="1.2" decel="3.0" sigma="0.3" color="red"/>
<vType id="truck" length="10.0" maxSpeed="50" accel="1.5" decel="3.5" sigma="0.4" color="green"/>
这里几个关键参数我解释一下:
- length:车身长度,单位米。小轿车一般4.5米,公交车12米,卡车10米。
- maxSpeed:最大速度,单位km/h。注意SUMO内部用的是m/s,但这里写km/h它会自动转换。
- accel/decel:加速度和减速度。公交车加速慢,所以设小一点。
- sigma:驾驶员的“不完美程度”。0表示完美驾驶,1表示随机乱开。我一般设0.5,比较真实。
- color:仿真时车辆的颜色,方便区分。
小技巧:如果你做的是传感器仿真,建议给不同类型的车加上不同的“传感器配置”属性。比如自动驾驶轿车可以加激光雷达,普通车就不加。这个后面章节会细讲。
4.2 交通流定义(.flow.xml)
车辆类型定义好了,接下来就是告诉SUMO:这些车什么时候出现?出现多少?这就是交通流干的事。
说白了,交通流就是“车流的水龙头”。你拧多大、拧多久,决定了路上有多少车。
<!-- flow.xml 示例 -->
<flows>
<flow id="flow_car_1" type="car" begin="0" end="3600" number="500" from="edge_in" to="edge_out"/>
<flow id="flow_bus_1" type="bus" begin="300" end="3600" period="600" from="edge_in" to="edge_out"/>
<flow id="flow_truck_1" type="truck" begin="0" end="3600" probability="0.1" from="edge_in" to="edge_out"/>
</flows>
这里有几个关键属性:
| 属性 | 含义 | 示例 |
|---|---|---|
| begin / end | 车流开始和结束时间(秒) | begin="0" end="3600" 表示仿真第1小时 |
| number | 总共生成多少辆车 | number="500" 表示生成500辆 |
| period | 每多少秒生成一辆车 | period="600" 表示每10分钟一辆 |
| probability | 每秒生成的概率(0~1) | probability="0.1" 表示每秒10%概率 |
| from / to | 起始边和目的边 | from="edge_in" to="edge_out" |
注意:number、period、probability这三个属性是互斥的,只能选一个。我曾经犯过同时写number和period的错,结果SUMO直接报错,排查了半天才发现。
4.3 路线定义(.rou.xml)
路线定义是最后一块拼图。它告诉SUMO:车辆从哪条路进去,经过哪些路段,最后从哪出去。
我个人习惯把路线定义和车辆类型、交通流分开写,这样结构清晰。当然你也可以全部写在一个文件里,但项目大了以后会很难维护。
<!-- rou.xml 示例 -->
<routes>
<vType id="car" length="4.5" maxSpeed="60" accel="2.6" decel="4.5" sigma="0.5" color="blue"/>
<vType id="bus" length="12.0" maxSpeed="40" accel="1.2" decel="3.0" sigma="0.3" color="red"/>
<route id="route_main" edges="edge_in edge_mid edge_out"/>
<route id="route_side" edges="edge_in edge_side edge_out"/>
<flow id="flow_car_main" type="car" begin="0" end="3600" number="500" route="route_main"/>
<flow id="flow_bus_main" type="bus" begin="300" end="3600" period="600" route="route_main"/>
<flow id="flow_truck_side" type="truck" begin="0" end="3600" probability="0.1" route="route_side"/>
</routes>
看到没?这里我把vType、route、flow全部写在一个.rou.xml文件里了。这样做的好处是:一个文件搞定所有,适合小项目。但如果是大型仿真,我建议还是分开写,然后用<include>引入。
<!-- 使用include引入 -->
<routes>
<include href="#" aria-disabled="true" data-keke-missing-local-link="1" onclick="return false"/>
<include href="#" aria-disabled="true" data-keke-missing-local-link="1" onclick="return false"/>
<route id="route_main" edges="edge_in edge_mid edge_out"/>
</routes>
4.4 实战:把三兄弟串起来
好,理论讲完了,咱们来点实际的。假设我们要仿真一个十字路口,有直行和左转两种车流,该怎么写?
我记得有一次做项目,甲方要求仿真早高峰的十字路口。我一开始只定义了直行车流,结果仿真出来的拥堵位置跟实际完全对不上。后来加了左转车流,才匹配上。你看,细节决定成败。
<!-- 完整示例:十字路口交通需求 -->
<routes>
<!-- 车辆类型 -->
<vType id="car" length="4.5" maxSpeed="60" accel="2.6" decel="4.5" sigma="0.5" color="blue"/>
<vType id="suv" length="4.8" maxSpeed="55" accel="2.2" decel="4.0" sigma="0.4" color="green"/>
<!-- 路线 -->
<route id="route_straight" edges="north_entry north_mid south_mid south_exit"/>
<route id="route_left" edges="north_entry north_mid west_mid west_exit"/>
<!-- 交通流 -->
<flow id="flow_straight" type="car" begin="0" end="3600" number="800" route="route_straight"/>
<flow id="flow_left" type="suv" begin="0" end="3600" number="200" route="route_left"/>
</routes>
避坑指南:我曾经把路线里的边顺序写反了,结果车辆一出生就往反方向跑。所以写路线时,一定要按照车辆行驶的方向,从入口到出口依次列出边ID。
4.5 小结
这一章咱们把交通需求建模的“铁三角”讲透了。你想想看,有了车辆类型、交通流和路线,SUMO就知道路上跑什么车、什么时候来、往哪走了。这就是仿真的基础。
下一章咱们会讲如何把这些文件加载到SUMO里,以及如何用netedit可视化查看。嗯,到时候见。
核心要点回顾:
- .vtype.xml:定义车辆物理属性和行为参数
- .flow.xml:定义车流的时间分布和数量
- .rou.xml:定义车辆的行驶路径
- 三者通过ID关联,缺一不可
- 大型项目建议用<include>拆分文件