路网基础:从现实道路到SUMO的数字映射
做交通仿真这么多年,我越来越觉得一个道理——仿真结果的可靠性,90%取决于路网建得对不对。你想想看,路网都不对,后面的车流生成、信号配时全是白搭。今天我们就来聊聊SUMO的路网基础,把那些看似枯燥的概念掰开揉碎讲清楚。
路网概念解析:仿真世界的骨架
路网是什么?说白了,就是现实道路在计算机里的数字孪生。在SUMO里,路网由三个核心要素构成:节点(Node)、边(Edge)和车道(Lane)。我习惯把节点想象成路口,边想象成路段,车道就是路段上的每一条行车轨迹。
举个例子,你家小区门口那条双向四车道的路,在SUMO里就是一条边(Edge),这条边上有4条车道(Lane),两端各连着一个节点(Node)。嗯,就是这么个对应关系。
核心要点:SUMO的路网是有向图。每条边都有方向,从from节点指向to节点。这一点和很多GIS路网不一样,刚开始接触时容易搞混。
SUMO路网文件结构(.net.xml)
.net.xml文件是SUMO路网的"身份证"。它用XML格式存储了所有路网信息。我刚开始学SUMO时,第一件事就是打开一个.net.xml文件看看里面到底长什么样。
一个典型的.net.xml文件结构如下:
<?xml version="1.0" encoding="UTF-8"?>
<net version="1.16" junctionCornerDetail="5">
<location netOffset="0.00,0.00" convBoundary="0.00,0.00,1000.00,1000.00"
projParameter="!"/>
<edge id="gneE0" from="node0" to="node1" priority="1">
<lane id="gneE0_0" index="0" speed="13.89" length="500.00"
shape="0.00,0.00 500.00,0.00"/>
<lane id="gneE0_1" index="1" speed="13.89" length="500.00"
shape="0.00,3.20 500.00,3.20"/>
</edge>
<junction id="node0" type="priority" x="0.00" y="0.00">
<request index="0" foes="0" cont="0"/>
</junction>
</net>
看到没?文件主要分三块:<location>定义坐标系,<edge>定义路段,<junction>定义节点。我建议你把这个结构记在脑子里,调试路网时经常需要手动改这些参数。
节点(Node)与边(Edge)的定义
节点就是路口的抽象。每个节点有一个唯一ID,还有类型(type)。常见的节点类型有:
- priority:优先通行路口,默认主路优先
- traffic_light:信号灯控制路口
- right_before_left:右侧先行规则路口
- dead_end:死胡同或道路尽头
我在项目中遇到过一个问题:把一个小路口设成了priority类型,结果仿真时车辆互不相让,堵成一锅粥。后来改成right_before_left就顺畅了。所以节点类型的选择,直接影响交通流的运行逻辑。
边是连接节点的路段。每条边有from和to属性,指定起点和终点节点。边的属性还包括:
| 属性 | 含义 | 示例值 |
|---|---|---|
| id | 唯一标识 | gneE0 |
| from | 起点节点ID | node0 |
| to | 终点节点ID | node1 |
| priority | 道路优先级(数值越大越优先) | 1, 2, 3 |
| numLanes | 车道数量 | 2 |
| speed | 限速(m/s) | 13.89(约50km/h) |
小技巧:我习惯在命名节点和边时用有意义的名称,比如"node_main_gate"、"edge_road_A"。虽然SUMO自动生成的gneE0也能用,但调试时你会感谢自己的命名习惯。
车道(Lane)与连接(Connection)配置
车道是车辆实际行驶的"轨道"。每条边包含若干条车道,车道有索引号(index),从0开始编号。0号车道通常是靠右行驶的最右侧车道(中国靠右行驶)。
车道的核心属性:
- speed:该车道的限速,可以不同于边的默认限速
- length:车道长度,通常与边一致
- shape:车道几何形状,用一系列坐标点描述
- allow/disallow:允许/禁止的车辆类型
我曾经在做一个公交专用道项目时,用disallow="private"属性把最右侧车道设为公交专用,私家车不能走。效果立竿见影,公交车通行效率提升了30%。
连接(Connection)定义了车辆从一个车道到另一个车道的转向关系。没有连接,车辆到了路口就不知道往哪走。连接的定义在.net.xml中通常放在<connection>标签里:
<connection from="gneE0" to="gneE1" fromLane="0" toLane="0" dir="r"/>
<connection from="gneE0" to="gneE2" fromLane="1" toLane="0" dir="l"/>
这里dir属性表示转向方向:r右转,l左转,s直行,t掉头。嗯,要注意的是,掉头(t)在很多路网里是被禁止的,除非你明确配置了。
避坑指南:我曾经犯过一个低级错误——只配了直行连接,忘了配左转。结果仿真时所有左转车辆在路口原地打转,永远到不了目的地。检查了整整两个小时才发现是连接没配全。所以,每个车道到每个目标车道的连接都要显式定义,除非你确定不需要。
知识体系总览
下面这张图是我自己总结的路网核心逻辑,你看一眼就能明白各个要素之间的关系:
这张图把路网的核心逻辑串起来了。你从节点出发,节点之间用边连接,边上划分车道,车道之间通过连接定义转向关系。说白了,整个路网就是一张有向图,节点是顶点,边是弧段,车道是弧段上的细节,连接是弧段之间的转换规则。
我的建议:刚开始做路网时,别急着用netedit画图。先手动画一个小路网的.net.xml文件,把节点、边、车道、连接都写一遍。这个过程会让你对路网结构有刻骨铭心的理解。我当年就是这么过来的,虽然花了半天时间,但之后看任何路网文件都像看老朋友一样亲切。
好了,路网基础就聊到这儿。记住一句话:路网是仿真的地基,地基不牢,地动山摇。下一节我们聊聊如何用netedit可视化编辑路网,到时候我会分享一些我踩过的坑和总结的技巧。