堵住的路口,单靠绿灯无法疏通。在开源交通仿真器 SUMO 中,测试一套更好的信号控制器,需要把几个各司其职的部分连起来:路网、试图使用路网的车辆、时钟,以及改变灯色的代码。沿着这些联系梳理,才能看清控制器究竟控制着什么,以及为何行程时间数据颇为亮眼时,最严重的排队仍会落在统计视野之外。[1][4][9]
SUMO 对单辆汽车及车辆之间的相互作用建模。配套工具负责生成路网、准备交通需求,外部程序则可以在仿真运行期间介入。Davide Andrea Guastella 及其同事撰写的一篇独立教程,将准备工作分成了清楚的步骤:导入道路、定义出行、分配路线、配置输出。地图上的街道看起来熟悉,只是交通实验的起点。[1][2]
路口内部也有空间
设想这样一次实验:某个进口方向开始排队时,控制器就延长该方向的绿灯时间。这个实验仅作假设;照片标示的是一处真实研究场地,文中没有声称这套控制器已在此部署。
SUMO 从 --net-file 读取路网,从 --route-files 读取交通需求。附加文件可以包含信号控制程序、检测器及其他基础设施。路线文件通常按需逐步读取,因此车辆出发记录必须按时间排序。这些输入各有分工:道路通向何处,与有多少人使用这条道路,是两项不同的信息。[3]
停车线之间的空间同样重要。SUMO 通常用内部车道表示车辆穿越路口的过程。关闭内部连接后,车辆仍会遵守信号灯和通行优先权规则,但越过停车线后就直接跳到路口另一侧。路口内部的停车等待与车辆相互阻挡,也随之从模型中消失。[4]
对于上面设想的控制器,这项变化影响很大。若研究的是车辆堵在路口中央的情形,去掉内部空间,就等于去掉了部分研究现象。因此,动画看起来通畅,原因可以只是模型更简单,未必是绿灯时长决策更好。这一推断来自文档所述的模型行为,未对某个具体控制器的性能作出判断。
外部程序推进仿真时间
TraCI,即交通控制接口(Traffic Control Interface),通过 TCP 将外部客户端连接到 SUMO。仿真器开放了读取和修改状态的操作。例如,客户端可以查看检测器数据,决定是否延长绿灯,再调用 simulationStep() 推进仿真,然后观察新的状态。[5]
这次调用也是一个同步点。多个客户端同时参与时,只有所有客户端都请求进入下一步,仿真才会继续;每个客户端还要指定自己的执行顺序。由此,控制器与其他参与的应用共用一个时钟,各自的命令按明确的先后次序执行。若有一个客户端停止抵达同步点,其他客户端也得等待,无法独自推进后续交通仿真。[5]
时间分辨率由另一项设置决定。SUMO 默认每一步推进一秒仿真时间,--step-length 可以缩短这个间隔。步进更频繁,车辆插入路网、变换车道,以及默认设置下调整速度的机会也更多。缩短间隔会同时改变模型的执行过程与计算开销,因此应作为实验设置记录下来,仅将它当作让动画更平滑的调节项会遗漏这些影响。[3]
使用 TraCI 后,结束仿真的责任也发生了变化:服务端会忽略 --end,由客户端负责关闭仿真。getMinExpectedNumber() 可以辅助判断交通需求是否已经耗尽、车辆是否已经全部离开。控制循环需要明确的停止条件。[5]
绿灯切换要经过过渡相位
SUMO 的交通信号灯状态,描述的是控制车道间连接的各个信号。一个进口方向可以包含多个行驶流向,所以仅凭道路名称还不足以选定对应的信号灯,还要看连接索引。[6]
文档介绍的自适应控制方法,是在仿真器中保留一套信号控制程序。先把绿灯相位设得足够长,控制器决定结束绿灯时,再用 traci.trafficlight.setPhase() 进入相应的黄灯过渡相位。随后,SUMO 可以依照配置运行黄灯和全红相位,再进入下一次绿灯。脚本决定何时结束该进口方向的放行,信号控制程序则保留完整的过渡次序。[6]
还有一个更直接的接口:setRedYellowGreenState()。调用之后,SUMO 会保持指定的状态,直到收到后续指令或切换信号控制程序。此时,每个相位及其过渡都由脚本负责。这两个 API 分给控制器的工作各不相同:前者选择进入哪个过渡相位,后者负责给出整套随时间变化的信号状态。[6]
对于上面以排队为例的实验,我会先采用一套经过审查的相位程序,只调整是否延长绿灯的决策。这样可以避免一次错误的相位过渡,在未经察觉的情况下变成另一项实验。
跨进程通信也要花时间
反复发送 TraCI 请求,需要跨越进程边界。当这部分开销值得关注时,可以用 libsumo 将仿真器作为库来调用,其 API 与 TraCI 十分接近。Python 脚本通常可以使用 import libsumo as traci,同时仍需遵循文档列出的差异。[7]
这种部署方式有相应的约束。Libsumo 的类型处理更严格,图形界面(GUI)运行存在限制,多客户端的安排也有所不同;Python 若要并行运行多个仿真实例,需要使用多进程。熟悉的函数名称,并不能保证现有的所有程序协同方式都可原样迁移。[7]
对一个小型研究团队而言,合理的推进顺序是先把一个路口研究清楚,再测量批量运行时的时间花在了哪里。迁移到 libsumo 可以处理通信开销。至于模型中遗漏的转向流向、合成交通需求与真实街道是否相符,仍须分别补全和验证。
还在等待的车辆也要计入
最后一道交接发生在结果文件中。当车辆出发位置的空间不足时,SUMO 会推迟该车辆进入路网的时间。车辆先在插入队列中等待,最终的 departDelay 会记录它等待进入路网所花的时间。因此,输入模型的交通需求量,与已经在路网内行驶的交通量,应分开看待。[8]
TripInfo 还有一项区别:默认情况下,车辆抵达目的地后才会生成行程记录。仿真停止时仍在途中的车辆,只有启用 --tripinfo-output.write-unfinished、输出未完成行程,才会出现在记录里。[9]
假设两个控制器各运行同样长的一段固定时间,其中一个很快放行了流量较小的进口方向,却让繁忙方向持续拥堵。若只比较已经完成的行程,那些容易完成的出行就会改善统计结果,仍被堵住的车辆则被遗漏。这是输出规则所隐含的样本选择问题,仅凭这一点,还不能认定 SUMO 本身给出了错误的测量值。
查看已完成行程时,应一并查看仍未完成行程的车辆和进入路网前的延误。还要明确选择测量什么:waitingTime 记录车辆接近静止的时间,timeLoss 则包括车辆以低于自身理想速度行驶所损失的时间。它们回答的是不同的问题。[9]
那篇独立教程强调真实交通需求数据,也为实验补上了最后一项约束:除了看起来熟悉的路网,还需要有关哪些人会出行的证据。[2] 应将这些输入、控制器与所用的 SUMO 发布版本一并保存;在线手册描述的是持续开发中的版本,而下载的发布版附带各自的文档。[1] 控制器可以推进仿真时钟。至于这次实验能说明真实路口的哪些情况,仍有待研究者判断。
来源
- Eclipse SUMO,《SUMO 用户文档》——项目范围、许可,以及开发版与发布版文档的区别;查阅日期:2026 年 10 月 15 日。
- Guastella、Montero-Porras、Morales-Hernández 与 Bontempi,《Traffic Modeling with SUMO: a Tutorial》,2025 年 1 月 31 日修订——独立学术教程,介绍仿真实验准备、交通需求数据与输出。
- SUMO,《Basic Definition》——路网、路线与附加文件,增量加载及仿真步长设置。
- SUMO,《Intersections》——内部车道及关闭内部连接后的影响。
- SUMO,《TraCI》——客户端/服务端架构、客户端执行顺序、同步步进与关闭仿真。
- SUMO,《Traffic Lights》——连接索引、相位选择、过渡程序与直接状态控制。
- SUMO,《Libsumo》——库接口、Python 导入兼容性及运行限制。
- SUMO,《VehicleInsertion》——空间约束、插入队列与出发延误。
- SUMO,《TripInfo》——抵达后触发的行程记录、未完成行程、等待时间与时间损失。
- 德国航空航天中心,《DLR research intersection in Braunschweig》——研究场地的照片与介绍;图片署名:Jenoptic / DLR。