拓冰建站拓冰建站
首页 / 资讯中心 / 正文

SUMO仿真环境下五种自适应交通信号控制算法对比与实践

简介本资源是一个面向交通工程研究者、智能交通系统开发者及强化学习实践者的SUMO仿真项目聚焦多策略自适应交通信号控制算法的实现与对比验证。项目集成DQN与DDPG两种深度强化学习方法并融合韦氏模型、最大压力算法及自组织交通灯控制等经典策略支持在微观交通仿真环境中评估不同控制逻辑对通行效率、延误与积压的影响。压缩包共54个文件含37个Python核心模块涵盖仿真接口、RL智能体、网络数据处理与结果可视化、5个Shell脚本用于训练、评估与环境清理、4张性能分析图及2个SUMO配置文件整体仅1.35MB轻量易部署。已有1321人学习下载提供开箱即用的完整实验框架从SUMO场景构建、算法训练到指标生成与图表绘制所有模块解耦清晰、命名规范便于二次开发与算法替换。 自适应交通信号控制这几年被提到得越来越多但大部分谈这个方向的文章都停留在概念层面要么贴一张配时公式要么放一段DQN的网络结构图。真正动手把几种算法放到同一个仿真环境里跑一遍、逐项对比各项指标、再把训练脚本和批量实验串起来做的人不算多。这个项目做的正是这件事在SUMO仿真平台上把韦伯斯特Webster定时配时、最大压力控制Max Pressure、自组织交通灯SOTL、DQN和DDPG五种信号控制算法全部实现统一在同一个路网上做对比整套代码用Python调TraCI接口、Shell脚本做批量训练和评测评测。如果你正在研究信号控制或者想找一个同时覆盖传统方法、强化学习方法和无模型自适应方法的技术参考项目这篇文章应该能帮你省下很多自己摸索的时间。1. 五套算法放进同一个项目核心目标与对比思路1.1 这个项目解决的真实问题是什么信号灯控制本质上是一个在线决策问题每个时刻面对不断变化的车流决定放行哪个方向、放行多久。传统做法是固定周期固定绿信比用一天里某几个时段的平均流量去标定信号配时方案一旦真实流量偏离标定值整个控制效果会迅速恶化。自适应控制的目标就是让信号灯能根据实时排队、到达流量、下游占用情况去动态调整相位和绿信比。项目把五类做法放在一起核心不是证明某一个算法“天下无敌”而是搞清楚三个问题传统理论方法Webster 定时配时在流量波动下的性能上限在哪里不需要学习的自适应策略Max Pressure、SOTL能不能追平甚至超过强化学习算法强化学习DQN、DDPG在状态设计、动作空间、奖励函数都比较合理的前提下到底能比无学习方法提升多少代价又是什么。1.2 为什么用SUMO当试验场SUMO是德国宇航中心开源的微观交通仿真软件支持连续路网建模、随机车流生成、排放模型、TraCI接口。选择它有几个很实际的考虑完全免费没有授权限制跑实验不需要向公司申请licenseTraCI允许外部Python程序在每次仿真步内读取车辆状态、改变信号灯相位正好适合做闭环控制算法验证支持命令行无界面运行可以很轻松地用Shell批量启动多个仿真实例训练几十个episode也不用一直开着GUI社区活跃常见问题基本都能搜到现成的解法。对比商业软件VissimSUMO在微观行为的精细度上稍有差距但对于验证信号控制算法来讲完全够用甚至因为Python生态更完善做强化学习接入反而更顺手。1.3 实验场景怎么搭我在复现过程中用的是单交叉口四相位经典场景东西南北四个进口道每个方向包含直行和左转车道右转不单独控制信号相位按照南北直行、南北左转、东西直行、东西左转四相位轮转车流按泊松分布随机生成每个方向的平均到达率在600800 veh/h之间波动仿真步长设为1秒单次仿真时长3600秒模拟一小时的高峰流。把路网规模控制在这个级别是为了保证DQN和DDPG的训练在普通PC上几个小时内能跑完。多交叉口的场景不是不能做但状态空间、动作空间和奖励设计都会复杂几个量级作为项目起步阶段单交叉口是最合理的验证场。后续要扩展也是在这个基础上往多路口、干线协调方向走。2. 两个经典基线Webster配时与Max Pressure的落地细节2.1 Webster公式从流量比到固定相位时长Webster配时是信号控制里最经典的定时方法它假设车流平稳、交叉口不饱和用各相位关键车道的流量比来算出最优周期和绿信比。核心公式如下# webster_calculation.py def webster_timing(flows, saturation_flow1800, lost_time3.0): flows: 各相位关键车道到达流率 (veh/h) saturation_flow: 饱和流率 (veh/h/ln) lost_time: 每相位损失时间 (s) num_phases len(flows) y [f / saturation_flow for f in flows] Y sum(y) L num_phases * lost_time C_opt (1.5 * L 5) / (1 - Y) green_times [(C_opt - L) * yi / Y for yi in y] return C_opt, green_times参数取值举个例子四个关键方向流量分别是 650、520、700、580 veh/h饱和流率取1800 veh/h每相位损失时间3秒那么流量比Y 0.361 0.289 0.389 0.322 1.361这个值已经逼近1说明交叉口接近饱和最优周期 C_opt (1.5×12 5) / (1 - 1.361) 已经变成负数说明Webster公式在这个场景下失真了。实际中流量比Y不能太接近1一般要求Y 0.9。所以我在项目里把平均到达率整体下调到500700 veh/h得到Y约0.9周期约80秒再按绿信比分配到四个相位。在SUMO的tlLogic里就是一组固定phase表运行时完全不做调整。Webster的问题很明显它不是闭环控制没有实时反馈流量波动一旦超过标定区间红灯方向可能空放绿灯方向却排队溢出。把它当基线是为了给其它算法一个“最朴素做法”的参照物。2.2 最大压力控制用状态差决定放行谁Max Pressure控制来自背压路由思想名字里“最大压力”指的是每个候选相位对应一组待放行车道的排队压力和下游可用空间之差选择压力最大的相位放行。它天然会避开下游已经堵死的方向这是它比固定配时强很多的地方。在SUMO里的简化实现# max_pressure.py import traci def get_lane_queue_vehicles(lane_id): vehicles traci.lane.getLastStepVehicleIDs(lane_id) queue 0 for veh_id in vehicles: speed traci.vehicle.getSpeed(veh_id) if speed 0.1: queue 1 return queue def compute_phase_pressure(upstream_lanes, downstream_lanes): up_pressure sum(get_lane_queue_vehicles(l) for l in upstream_lanes) down_pressure sum(get_lane_queue_vehicles(l) for l in downstream_lanes) return up_pressure - down_pressure def choose_next_phase(phase_candidates): pressures [] for cand in phase_candidates: p compute_phase_pressure(cand[upstream], cand[downstream]) pressures.append(p) return int(argmax(pressures))关键细节是下游压力。很多人第一次实现Max Pressure只算上游排队忽略了“下游是否还有空档”结果会出现一个方向绿灯一直放行、下游路段被顶死的情况。加了 down_pressure 之后算法会倾向于把绿灯给“上游有车、下游有空”的相位整个交叉口的吞吐量反而上去了。实际运行时还必须加两个约束最小绿灯时间和最大绿灯时间。最小绿灯时间保证行人和已经启动的车辆安全通过最大绿灯时间防止某一个相位被连续选中导致其它方向饿死。我在项目里设的是 min_green10秒max_green60秒。2.3 无学习基线的共同局限Max Pressure和SOTL虽然自适应但都没有“记忆”不会根据历史流量变化去调整参数。它们对瞬时状态反应灵敏却谈不上最优。Max Pressure对排队检测的准确性要求很高SUMO里的getLastStepVehicleIDs拿到的是车道上的车辆集合需要自己过滤静止车辆如果检测频率太低切换会滞后排队会长起来。这两个方法的价值是给强化学习做一个性能下限的参照如果RL学了半天还不如Max Pressure那问题多半出在状态或奖励设计上而不是神经网络结构。3. DQN在离散相位控制里的完整训练链路3.1 状态空间、动作空间与奖励函数设计DQN处理的是离散动作所以它天然适合“选相位”这个场景。动作空间直接设置为四相位切换但为了减少频繁切换我在动作空间里增加了“保持当前相位”这一项一共有5个动作。信号控制中动作空间的设计非常影响训练效果如果动作只能让相位强制跳到下一个模型没有机会维持当前绿灯就会在仿真里出现绿灯刚亮就切走的抖动现象。状态空间方面项目里选择了以下特征四个相位分别对应的上游车道排队车辆数当前相位编号当前相位已经持续的时间最近60秒各方向的平均到达流量。为什么选这些排队数反映当前的拥堵程度相位持续时间决定是否需要切换到达流量反映趋势性的需求变化。这四类信息已经能覆盖单交叉口信号控制的主要决策依据再加高维信息反而会让DQN更难收敛。奖励函数是DQN信号控制项目的灵魂。我的设计是def compute_reward(queue_vehicles, waiting_times, switch_flag): total_wait sum(waiting_times) total_queue sum(queue_vehicles) switch_penalty 2.0 if switch_flag else 0.0 reward -0.4 * total_wait - 0.3 * total_queue - switch_penalty return reward加 switch_penalty 是因为如果不惩罚频繁切换DQN会倾向于每几秒钟就换相位造成车辆刚加速就遇红灯整体通行效率大幅下降。3.2 网络结构与训练流程网络结构本身不复杂三层MLP加ReLU激活隐藏层128个神经元输出5个动作的Q值。这个规模在单交叉口场景下完全足够不需要上CNN也不需要Attention。训练流程里最重要的几个超参buffer_size 20000 batch_size 64 gamma 0.95 learning_rate 1e-3 target_update_freq 500 epsilon_start 1.0 epsilon_min 0.05 epsilon_decay 0.995gamma0.95这个值值得说一下。信号控制是典型的长时决策问题但决策影响的时间尺度其实不长一个相位周期也就60到90秒所以折扣因子不需要设得非常大。设成0.99甚至更高时累计回报波动会明显变大训练更难稳定。训练循环和TraCI的交互顺序是这样# train_dqn.py 核心循环伪代码 for episode in range(EPISODES): traci.load([-n, net_file, -r, route_file]) # 重载仿真 state get_state() while step EPISODE_STEPS: action epsilon_greedy(state, epsilon) execute_action(action) # traci.trafficlight.setPhase / setPhaseDuration traci.simulationStep() # 推进1秒 next_state get_state() reward compute_reward(...) replay_buffer.push((state, action, reward, next_state, done)) if len(replay_buffer) batch_size: update_q_network() state next_state重载仿真这一步特别容易被新手忽略。如果不重置SUMO下一个episode会接着上一个的运行状态继续状态空间直接被污染训练曲线会乱成一团。3.3 换几个随机种子再下结论DQN在信号控制场景里最大的问题是训练方差大。同一套代码同一个路网随机种子不同最好的情况平均等待时间能降到20秒以内最差的情况可能比Webster还差。为了避免被随机性误导我的做法是每个配置跑三个不同随机种子取平均值。最终收敛好的DQN agent表现大约是平均等待时间比Webster下降25%到30%最大排队长度下降20%左右。但注意这是对训练流量分布有效。如果测试时流量大幅偏离训练分布DQN的表现会明显下滑这是强化学习样本外泛化问题的直接体现也是后面要提到的多场景训练方案的出发点。4. DDPG的连续控制思路相位时长决策实战4.1 为什么在信号控制里要用连续动作DQN的动作是选相位但真实交叉口控制的另一个维度是“相位持续时长”这是个连续变量。比如当前南北直行绿灯已经亮了20秒是继续放3秒还是继续放12秒DQN没法直接输出这个值只能通过离散动作间接实现。DDPG的优势就在这里它可以直接输出连续动作比如“当前相位延长时间的比例”然后映射成具体的秒数。这让控制变得更平滑——绿灯不是按整秒或整相位跳变而是可以根据实时排队情况微调时长。4.2 动作映射、噪声音与网络结构DDPG在信号控制里的实现首先要解决动作映射问题。我采用的做法是Actor网络输出动作 a ∈ [0,1]映射为相位延长时间 delta a * 15秒当前相位绿灯时间达到 min_green 后持续延长 delta 秒当延长时间累计超过 max_green强制切换到下一个相位。注意DDPG不负责“切换方向”它只决定当前相位是否继续延长。切换方向仍然由一个底层规则来处理比如当另一相位的压力差超过阈值时。这套“上层优化时长、底层规则选相位”的分层架构在实践中比让DDPG直接输出四相位切换要稳定很多。网络结构用的PyTorch大概长这样class Actor(nn.Module): def __init__(self, state_dim, action_dim): super().__init__() self.fc1 nn.Linear(state_dim, 128) self.fc2 nn.Linear(128, 128) self.fc3 nn.Linear(128, action_dim) def forward(self, state): x torch.relu(self.fc1(state)) x torch.relu(self.fc2(x)) return torch.tanh(self.fc3(x)) * 0.5 0.5 # 映射到[0,1]DDPG探索用的是Ornstein-Uhlenbeck噪声而不是DQN的epsilon-greedy。这是因为动作本身是有连续性的这一秒延长5秒下一秒大概率是延长4.5秒到5.5秒之间OU噪声能保证探索轨迹在时域上的相关性不会像高斯噪声那样每步独立跳变导致控制动作剧烈抖动。4.3 实测下来DDPG的坑比想象中多必须说实话在单交叉口这个场景里DDPG并没有显著优于DQN。我复现出来的结果是两者平均等待时间差不多DDPG偶尔在流量波动大的配置里更平缓但训练时间几乎是DQN的两倍因为每一步都要更新两套网络Actor和Critic还要额外做目标网络软更新。还有几个容易踩的问题奖励尺度极其敏感。同一个奖励函数DQN学得动DDPG可能完全学不动。需要把reward压缩到-1到1的区间附近否则Critic的Q值估计会非常不稳定。相位延长动作太容易导致饿死。如果某方向持续有车DDPG会倾向于一直延长这个方向的绿灯其它方向排队甚至溢出。必须把 max_green 这个约束写死并且在奖励函数里增加对最大排队长度的惩罚项。目标网络软更新参数tau。经验上 tau 取0.005比0.001更合适更新太慢会导致策略和评价脱节。5. 不靠神经网络的智能自组织交通灯的阈值机制5.1 局部占用驱动的相位切换规则自组织交通灯SOTL的思路跟强化学习完全相反它不学全局最优策略只根据局部车流占用状态做反应。核心规则很简单当前相位绿灯时间大于最小绿灯时间后系统开始检测其它方向的排队情况如果某个非当前相位方向的车道排队车辆数超过阈值并且当前相位方向的车已经基本放空就切换相位如果所有方向都没有达到阈值就一直保持当前绿灯直到最大绿灯时间强制切换。用代码表达更清楚# sotl.py def sotl_should_switch(phase, green_time, queues, other_queues): MIN_GREEN 10 MAX_GREEN 60 SWITCH_Q_THRESHOLD 5 if green_time MIN_GREEN: return False if green_time MAX_GREEN: return True if max(other_queues) SWITCH_Q_THRESHOLD: return True return False这个机制的价值在于它是自适应的但完全没有神经网络、没有训练过程。它自己会形成一种“谁的车多就放谁”的行为实际效果在车流波动场景下经常能干掉定时配时。5.2 阈值参数整定的经验SOTL的阈值看起来只有两三个实际调起来需要一点耐心。我最初用的阈值是排队车辆数大于3就切换结果低频流量下车流刚聚集就被放行绿灯频繁切换反而增加了停车次数。后来把阈值提到5同时把最小绿灯时间设成10秒效果才稳定下来。一个比较可靠的标定思路是先用Webster配时跑一段基准仿真统计每个方向排队车辆的平均数和标准差然后取“平均值 1倍标准差”作为SOTL的切换阈值。这样至少保证阈值跟路网的规模是匹配的而不是拍脑袋定的数字。5.3 SOTL和Max Pressure的本质差异很多人会把SOTL和Max Pressure混为一谈它们都属于无模型自适应方法但决策依据完全不同Max Pressure比较的是“上游排队与下游空间的差值”是压力梯度驱动SOTL比较的是“其它方向的排队是否超过阈值”是局部触发驱动。Max Pressure避免了向堵塞方向放行SOTL则简单得多只关心“有没有车在等”。在高流量场景下Max Pressure的吞吐量通常优于SOTL因为压力梯度能感知下游瓶颈在中低流量场景SOTL反应快、计算量接近零两者差距很小。这个对比也解释了为什么项目要把SOTL放进算法集如果某个RL算法的表现连SOTL都打不过那说明它根本不是在学习什么有效策略只是把随机动作和流量变化拟合在一起。6. 同台实测指标怎么定、数据怎么比、结论怎么读6.1 评价指标的选取评价信号控制算法不能只盯一个指标。单一指标很容易掩盖问题比如只优化平均等待时间可能导致个别方向长时间等待的“公平性问题”。项目里我同时统计了四个指标平均等待时间所有车辆在交叉口停止等待的累计时间平均值是最直观的用户感知指标平均行程时间从车辆进入路网到离开路网的穿越时间包含行驶时间和停车时间平均停车次数每辆车在交叉口前从高速减速到低速再重新加速的次数反映驾驶体验和油耗最大排队长度仿真过程中任意时刻任意方向的排队最大值反映交叉口是否接近溢出风险。SUMO里通过TraCI可以很方便地统计这些数据# eval_metrics.py travel_times [traci.vehicle.getTravelTime(v) for v in traci.vehicle.getIDList()] waiting_times [traci.vehicle.getWaitingTime(v) for v in traci.vehicle.getIDList()] stops [traci.vehicle.getStopState(v) for v in traci.vehicle.getIDList()]注意getWaitingTime返回的是最近一次运动状态之前的累积等待时间不是从进入路网开始的总等待所以要在每个仿真步采样后自行累加。6.2 五套算法的实测数据对比下面是单交叉口场景下的复现数据方向车流均值为600 veh/h随机种子固定测试集与训练集流量分布保持一致示例数据实际会有随机波动算法平均等待时间(s)平均行程时间(s)平均停车次数最大排队长度(veh)Webster定时配时34.258.71.812Max Pressure27.652.31.49SOTL25.149.81.58DQN22.447.61.28DDPG23.848.51.39这个表只能代表某一种车流分布下的情况换个随机种子、换个流量强度排名会变。但如果只看整体趋势有几点非常明确6.3 结果背后的机理分析Websters垫底是必然的它完全不响应流量变化属于“睁眼瞎”控制Max Pressure和SOTL作为无学习自适应方法已经能明显改善通行效率而且不需要任何训练时间DQN和DDPG在测试集和训练集分布一致时能取得最优成绩但优势没有想象中大——和SOTL比平均等待时间也就下降了10%左右。更值得关注的是泛化能力。我把测试车流从600 veh/h提高到900 veh/h结果让 DQN 和 DDPG 的平均等待时间反弹幅度明显高于SOTL和Max Pressure。这说明强化学习方法的性能高度依赖训练分布而这在真实场景里恰恰是个棘手问题现实中早高峰、晚高峰、平峰流量变化极大一个只在600 veh/h下训练过的模型很难直接部署到全天场景。解决思路是在多个流量档位上交替训练让经验回放池同时覆盖低中高三种状态分布。7. 从0复现整套工程目录结构、TraCI联动与Shell批量实验7.1 解压后的工程结构这个项目打包成zip后目录结构大概是这样的SUMO-Adaptive-TSC/ ├── nets/ │ ├── intersection.net.xml # SUMO路网文件 │ ├── intersection.sumocfg # SUMO仿真配置文件 │ └── routes.rou.xml # 车流生成文件 ├── src/ │ ├── base_controller.py # 控制器公共基类 │ ├── webster.py # Webster定时配时实现 │ ├── max_pressure.py # Max Pressure实现 │ ├── sotl.py # 自组织交通灯实现 │ ├── train_dqn.py # DQN训练脚本 │ ├── train_ddpg.py # DDPG训练脚本 │ └── eval_all.py # 统一评测脚本 ├── scripts/ │ ├── run_all.sh # 一键跑完整套对比 │ └── eval_all.sh # 批量评测脚本 └── logs/ # 训练日志与指标输出在动手写代码之前先把路网文件和车流文件准备好。SUMO路网文件可以用 netedit 图形化画也可以直接用 XML 手写一个最小交叉口。新手建议先用 netedit 画一遍保存后对照 XML 理解每个connection和tlLogic的含义后面调试TraCI时能少踩很多坑。7.2 TraCI连接和动态配时的核心操作无论哪种算法跟SUMO交互的方式都一样先启动SUMO服务再用Python的traci库连接。启动命令sumo-gui -n nets/intersection.net.xml -r nets/routes.rou.xml --remote-port 8813对应Python端import traci traci.init(port8813)运行时最常用的几个TraCI接口traci.trafficlight.getPhase(tl1)获取当前信号灯相位编号traci.trafficlight.setPhase(tl1, next_phase)直接切换相位traci.trafficlight.setPhaseDuration(tl1, duration)延长当前相位的剩余时间traci.lane.getLastStepVehicleIDs(lane_id)获取车道上当前车辆列表用于计算排队长度traci.vehicle.getWaitingTime(veh_id)获取车辆累计等待时间。这几个接口基本覆盖了信号控制算法的所有交互需求。DQN和DDPG在每次仿真步里拿到这些数据计算状态、奖励、动作然后通过setPhase和setPhaseDuration把决策写回路网。7.3 Shell脚本批量跑实验的正确姿势训练强化学习算法必须跑多个随机种子否则偶然性太大。手工一个个运行不现实用Shell脚本批量处理是标准做法#!/bin/bash # scripts/run_all.sh seed_list(1 2 3 4 5) for seed in ${seed_list[]} do echo Running DQN with seed $seed python src/train_dqn.py --seed $seed --episodes 2000 \ --log_dir logs/dqn_seed${seed} logs/dqn_seed${seed}.log 21 done for seed in ${seed_list[]} do echo Running DDPG with seed $seed python src/train_ddpg.py --seed $seed --episodes 2000 \ --log_dir logs/ddpg_seed${seed} logs/ddpg_seed${seed}.log 21 done wait echo All training processes finished.一个很容易被忽略的坑如果多个训练进程同时使用同一个输出目录日志文件和数据文件会被互相覆盖跑完发现自己辛辛苦苦训了几小时的模型丢了。一定要在启动参数里按seed分隔子目录。另外默认情况下SUMO仿真可能同时启动多个GUI窗口占用大量内存。在批处理脚本里应该用sumo而不是sumo-gui启动并加上--no-warnings和--quit-on-end参数让进程跑完自动退出。8. 实测踩坑记录版本兼容、训练不稳定和仿真细节8.1 SUMO版本差异导致的API不兼容不同版本的SUMO对TraCI接口的支持差异不小。项目最早在SUMO 1.12上开发部分接口在迁移到1.20版本后行为有了变化。最典型的是traci.lane.getWaitingTime在旧版本里返回单位是秒新版本里某些情况下返回的是毫秒导致奖励函数数量级完全错乱训练直接发散。建议开发阶段固定SUMO版本并且用虚拟环境管理不要把系统全局的环境搞混。跨版本迁移时先用一个小demo脚本测试常用接口的输出格式确认无误再跑全套训练。8.2 DQN训练不稳定的三个根因训练曲线上下乱跳是DQN在信号控制项目里最常见的现象。我排查下来有三个根因奖励函数数量级不对。等待时间累加动辄几十上百网络输出层如果不做归一化或裁剪损失函数数值会非常大梯度更新步长过大导致震荡。解决方法是先统计一个episode的reward范围然后做标准化。epsilon衰减太快。信号控制的状态空间不算复杂但是reward信号延迟较长如果epsilon衰减太快网络还在探索阶段就已经进入利用为主的阶段后面很难找到更优策略。我用的是每episode衰减0.995500个episode后epsilon才降到0.08左右。目标网络更新频率太低。更新频率500步算一个合理起点如果发现前期训练正常、后期震荡可以尝试降低到200步或300步。8.3 仿真细节上最容易忽略的问题信号控制算法对仿真本身的设置非常敏感我踩过的坑包括--step-length设置。步长设为1秒是通用选择但如果你做DDPG相位时长决策0.5秒的步长会让控制更细腻训练时间也翻倍。建议先把算法逻辑跑通再考虑步长精度。随机种子固定。SUMO的路网文件、路由文件、仿真参数里都可以指定随机种子。不固定的话每次实验的车流都不同算法对比就失去了控制变量意义。训练时固定测试时再换新种子来测泛化。信号灯相位与路网连接的一致性。netedit画路网时生成的tlLogic相位顺序有时候跟TraCI里读到的相位编号不一致。实现算法前先打印每个相位的关联车道确认相位索引和车道方向一一对应否则状态设计全错。这套工程做下来我最深的体会是“算法胜负”远没有“实验流程”重要。DQN和DDPG调参三个月得出的结论可能只是“在这个路网、这个随机种子、这个奖励函数下”的结论而把Webster、Max Pressure、SOTL这些基线实现好把评测流程脚本化得到的是一个可以反复用的实验平台。后续想扩展多交叉口协调控制、加入黄灯和全红清空期、甚至换成多智能体强化学习框架都只需要在这个工程上增量开发。做自适应信号控制先别急着追新算法把基线和评测工具做扎实后面每一步都省力。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门