MATLAB红绿灯状态机仿真与AVI录像系统 📅 发布时间:2026/9/12 13:10:42 👁 浏览次数: 简介这是一份面向交通工程、智能交通系统初学者及MATLAB仿真入门者的红绿灯控制教学资源聚焦十字路口多相位信号灯协同切换逻辑建模与动态可视化。资源包含完整的MATLAB仿真程序与配套操作录像帮助用户理解交通流建模、定时控制策略实现及GUI交互设计要点。压缩包共5个文件4个核心M函数主控脚本Runme.m、红绿灯状态管理tLamps.m、交通灯逻辑trafficLamp.m、路网地图map.m1个AVI格式操作录像总大小3.81MB结构精简、模块职责明确便于逐层调试与原理复现。已有1496人学习下载配套录像使用Windows Media Player即可播放清晰演示环境配置特别强调当前文件夹路径设置、程序运行流程与界面响应效果有效规避常见路径错误与初始化异常问题是开展交通控制仿真实验的实用入门套件。1. 用 MATLAB 搭建可复现、可验证、带录像回放的十字路口红绿灯仿真系统你不需要部署真实硬件也能让红绿灯“跑起来”——这不是演示动画而是基于交通流逻辑、时间约束与状态机建模的闭环仿真系统。它能模拟东西向直行/左转、南北向直行/左转四组通行权的时序分配支持相位切换延时、黄灯过渡、行人请求响应等关键行为并自动生成带时间戳的 AVI 录像文件供教学复盘或方案比对。适合交通工程初学者理解信号配时原理也适用于控制算法工程师验证 PID、模糊逻辑或强化学习策略在交叉口场景下的响应特性。本方案不依赖 Simulink Stateflow 或第三方工具箱纯用 MATLAB 基础语法 Image Processing Toolbox Video Writer 实现所有代码可在 R2018b 及以上版本直接运行且录像帧率、分辨率、标注文字均可按需调整。2. 构建红绿灯状态机模型从相位定义到时间驱动切换逻辑红绿灯不是简单循环亮灭而是受控于一套明确的相位Phase与阶段Stage关系。一个标准四路十字路口通常采用两相制Phase 1东西通行与 Phase 2南北通行每相内又细分为“绿→黄→红”三段。但实际工程中需支持左转专用相位、全红清空、行人过街请求等扩展能力因此我们采用显式状态机建模而非硬编码 if-else 链。2.1 定义相位结构体与时间参数表MATLAB 中用结构体struct封装各相位属性既清晰又便于后期扩展。以下为最小可行配置已适配国内常见配时规范绿灯30s、黄灯3s、全红2s% 定义相位参数表单位秒 phases struct(... name, {EastWest, NorthSouth}, ... green_duration, [30, 30], ... yellow_duration, [3, 3], ... all_red_duration, [2, 2], ... left_turn_enabled, [true, true], ... % 是否启用左转专用相位 left_turn_green, [15, 15] ... % 左转绿灯时长若启用 );提示left_turn_enabled设为true时系统将自动插入左转相位如 EW 左转绿灯 → EW 直行绿灯 → NS 左转绿灯 → NS 直行绿灯总周期延长设为false则退化为标准两相制。该字段直接影响phase_sequence的生成逻辑。2.2 生成动态相位序列与状态跳转表相位切换不能靠pause()硬等待必须基于仿真时钟t_sim实时判断。我们预生成完整周期内的状态跳转点transition points避免每帧重复计算% 计算单周期总时长含左转扩展 cycle_duration sum(phases.green_duration) sum(phases.yellow_duration) sum(phases.all_red_duration); if phases.left_turn_enabled(1) cycle_duration cycle_duration phases.left_turn_green(1); end if phases.left_turn_enabled(2) cycle_duration cycle_duration phases.left_turn_green(2); end % 构建状态跳转时间轴cumsum 累加生成断点 t_breakpoints [0]; t_breakpoints(end1) t_breakpoints(end) phases.left_turn_green(1); % EW 左转 t_breakpoints(end1) t_breakpoints(end) phases.green_duration(1); % EW 直行 t_breakpoints(end1) t_breakpoints(end) phases.yellow_duration(1); % EW 黄灯 t_breakpoints(end1) t_breakpoints(end) phases.all_red_duration(1); % EW 全红 t_breakpoints(end1) t_breakpoints(end) phases.left_turn_green(2); % NS 左转 t_breakpoints(end1) t_breakpoints(end) phases.green_duration(2); % NS 直行 t_breakpoints(end1) t_breakpoints(end) phases.yellow_duration(2); % NS 黄灯 t_breakpoints(end1) t_breakpoints(end) phases.all_red_duration(2); % NS 全红 % 对应状态标签用于绘图与日志 state_labels {EW_Left, EW_Straight, EW_Yellow, All_Red_EW, ... NS_Left, NS_Straight, NS_Yellow, All_Red_NS};2.2.1 状态映射函数将仿真时间映射为当前灯色核心函数get_light_state(t_sim, t_breakpoints, state_labels)返回结构体包含各方向灯色red,yellow,green及是否允许通行is_clearing true表示黄灯或全红清空function state get_light_state(t_sim, t_breakpoints, state_labels) t_cycle mod(t_sim, t_breakpoints(end)); % 归一化到单周期内 idx find(t_breakpoints t_cycle, 1, last); % 找到最后一个小于等于 t_cycle 的断点索引 state.label state_labels{idx}; % 根据 label 设置各方向灯色简化版实际需按国标细化 switch state.label case {EW_Left, EW_Straight} state.EW green; state.NS red; case EW_Yellow state.EW yellow; state.NS red; case All_Red_EW state.EW red; state.NS red; state.is_clearing true; case {NS_Left, NS_Straight} state.EW red; state.NS green; case NS_Yellow state.EW red; state.NS yellow; case All_Red_NS state.EW red; state.NS red; state.is_clearing true; otherwise state.EW red; state.NS red; end end该函数每帧调用一次输出结果直接驱动后续绘图与录像逻辑。注意is_clearing字段用于触发“清空检测”——当为true时系统可记录当前路口车辆数用于后续配时优化。3. 实现可视化界面与实时录像用 patch 绘制灯组 VideoWriter 录制 AVI仿真效果必须“看得见、存得下”不能仅靠命令行打印状态。我们采用axespatch绘制高对比度灯组避免plot或rectangle的抗锯齿模糊问题并通过VideoWriter逐帧写入带时间戳的 AVI 文件。3.1 构建十字路口静态布局与灯组坐标使用固定像素坐标定义灯组位置确保录像中比例稳定。此处以 640×480 分辨率为例东西向车道居中水平排列南北向垂直居中fig figure(Name, 十字路口红绿灯仿真, NumberTitle, off, ... MenuBar, none, ToolBar, none, Resize, off); ax axes(Parent, fig, Position, [0.1, 0.1, 0.8, 0.8]); set(ax, XLim, [0, 640], YLim, [0, 480], XTick, [], YTick, []); hold on; box on; % 绘制道路灰色填充 road_eastwest [100, 100, 540, 540; 220, 260, 260, 220]; fill(road_eastwest(1,:), road_eastwest(2,:), [0.7, 0.7, 0.7], EdgeColor, none); road_northsouth [220, 220, 260, 260; 100, 540, 540, 100]; fill(road_northsouth(1,:), road_northsouth(2,:), [0.7, 0.7, 0.7], EdgeColor, none); % 定义灯组中心坐标单位像素 light_pos struct(... EW_North, [320, 380], ... % 东向/西向北侧灯面向东行驶车辆 EW_South, [320, 100], ... % 东向/西向南侧灯面向西行驶车辆 NS_West, [120, 240], ... % 南向/北向西侧灯面向北行驶车辆 NS_East, [520, 240] ... % 南向/北向东侧灯面向南行驶车辆 ); % 初始化四个灯组每个含红黄绿三灯 lights containers.Map({EW_North,EW_South,NS_West,NS_East}, ... {struct(red,[],yellow,[],green,[]), ... struct(red,[],yellow,[],green,[]), ... struct(red,[],yellow,[],green,[]), ... struct(red,[],yellow,[],green,[])});3.1.1 绘制单个灯组用 patch 实现高亮圆灯每个灯由三个同心圆组成颜色由get_light_state输出动态更新function draw_light(ax, center, color_state, light_name) % center: [x, y] 像素坐标color_state: red/yellow/green r 12; % 灯半径 theta linspace(0, 2*pi, 64); % 绘制背景灰圈直径2*r x_bg center(1) r * cos(theta); y_bg center(2) r * sin(theta); fill(x_bg, y_bg, [0.3,0.3,0.3], EdgeColor, k, LineWidth, 0.5); % 绘制当前激活灯实心圆 x_on center(1) 0.7*r * cos(theta); y_on center(2) 0.7*r * sin(theta); switch color_state case red fill(x_on, y_on, [0.9, 0.1, 0.1], EdgeColor, r, LineWidth, 1); case yellow fill(x_on, y_on, [0.9, 0.9, 0.1], EdgeColor, y, LineWidth, 1); case green fill(x_on, y_on, [0.1, 0.8, 0.1], EdgeColor, g, LineWidth, 1); end % 添加方向标签小字体 text(center(1), center(2)20, light_name, FontSize, 8, ... HorizontalAlignment, center, Color, k); end此函数在主循环中被调用四次传入对应灯组坐标与状态确保视觉反馈严格同步于逻辑状态。3.2 启动录像写入器并配置帧率AVI 录像需在仿真开始前初始化关键参数包括帧率FrameRate、编解码器CompressionMethod和分辨率必须与axes尺寸一致vid VideoWriter(traffic_simulation.avi, Motion JPEG AVI); vid.FrameRate 10; % 10 fps 足够捕捉切换过程降低文件体积 vid.Quality 95; open(vid); % 主仿真循环总时长 120 秒覆盖 2 个完整周期 t_sim 0; dt 0.1; % 仿真步长秒决定状态刷新密度 while t_sim 120 % 获取当前状态 current_state get_light_state(t_sim, t_breakpoints, state_labels); % 清除旧灯组 cla(ax); hold on; % 重绘道路 fill(road_eastwest(1,:), road_eastwest(2,:), [0.7, 0.7, 0.7], EdgeColor, none); fill(road_northsouth(1,:), road_northsouth(2,:), [0.7, 0.7, 0.7], EdgeColor, none); % 绘制各方向灯组 draw_light(ax, light_pos.EW_North, current_state.EW, EW↑); draw_light(ax, light_pos.EW_South, current_state.EW, EW↓); draw_light(ax, light_pos.NS_West, current_state.NS, NS←); draw_light(ax, light_pos.NS_East, current_state.NS, NS→); % 添加时间戳与相位标签 title_str sprintf(t %.1f s | 当前相位: %s, t_sim, current_state.label); title(title_str, FontSize, 12, FontWeight, bold); % 捕获当前帧并写入录像 frame getframe(fig); writeVideo(vid, frame); % 更新仿真时间 t_sim t_sim dt; % 实时刷新界面可选影响性能 drawnow limitrate; end close(vid); disp(录像已保存为 traffic_simulation.avi);注意getframe(fig)捕获的是整个 figure 窗口因此axes的Position必须预留边距如[0.1,0.1,0.8,0.8]否则时间戳可能被裁切。若需更高画质可将vid.Quality提至 100但文件体积增大约 3 倍。4. 参数化配置与多场景验证修改配时、添加行人请求、导出 CSV 日志仿真价值在于可变性。本节提供三个高频需求的落地方法快速调整配时方案、模拟行人过街按钮触发、导出结构化日志供 Excel 分析。4.1 一键切换配时方案用结构体数组管理多套参数将不同场景早高峰、平峰、晚高峰的配时封装为结构体数组主循环前选择即可% 定义三套配时方案 schemes struct(... name, {Morning_Rush, Midday, Evening_Rush}, ... phases, {... struct(green_duration,[45,25],yellow_duration,[3,3],all_red_duration,[2,2],left_turn_enabled,[true,false]), ... struct(green_duration,[30,30],yellow_duration,[3,3],all_red_duration,[2,2],left_turn_enabled,[true,true]), ... struct(green_duration,[25,45],yellow_duration,[3,3],all_red_duration,[2,2],left_turn_enabled,[false,true]) ... }); % 选择方案例如Midday selected_scheme schemes.phases{2}; phases selected_scheme;只需修改selected_scheme索引无需改动主逻辑。left_turn_enabled字段自动触发相位序列重生成确保逻辑一致性。4.2 模拟行人请求在黄灯阶段插入随机请求事件真实路口存在行人按钮按下后下一周期延长某方向绿灯。我们在仿真中用rand模拟请求概率并在get_light_state中增加响应逻辑% 在主循环中添加请求生成每 5 秒检查一次 if mod(floor(t_sim), 5) 0 rand 0.3 % 30% 概率触发 pedestrian_request NS; % 随机请求南北向 end % 修改 get_light_state 函数在 NS 直行绿灯结束前若收到请求则延长 5 秒 if ~isempty(pedestrian_request) strcmp(current_label, NS_Straight) ... (t_cycle t_breakpoints(6)-5 t_cycle t_breakpoints(6)) state.NS green; % 延长绿灯 state.EW red; end该机制使仿真更贴近实际且可通过修改rand 0.3控制请求频次用于测试信号控制器的响应鲁棒性。4.3 导出结构化日志CSV 记录每帧状态与统计指标录像用于宏观观察CSV 用于定量分析。在主循环中追加日志写入log_file simulation_log.csv; fid fopen(log_file, w); fprintf(fid, time_sec,phase_label,EW_light,NS_light,vehicle_count_EW,vehicle_count_NS\n); % 主循环内追加 vehicle_count_EW round(20 10*sin(t_sim/10)); % 模拟车流波动 vehicle_count_NS round(15 8*cos(t_sim/12)); fprintf(fid, %.1f,%s,%s,%s,%d,%d\n, ... t_sim, current_state.label, current_state.EW, current_state.NS, ... vehicle_count_EW, vehicle_count_NS); fclose(fid); disp(日志已导出至 simulation_log.csv);生成的 CSV 可直接用 Excel 绘制“绿灯利用率 vs 车流量”散点图或导入 Python 用 pandas 分析相位延误。5. 关键参数调优与常见失效排查帧率卡顿、录像黑屏、相位错乱的根因定位仿真运行不等于功能正确。本节聚焦三个高频故障点给出可立即执行的诊断命令与修复路径。5.1 录像黑屏或花屏检查 axes 尺寸与 VideoWriter 分辨率匹配黑屏最常见原因是getframe(fig)捕获区域超出axes绘图区。验证方法% 运行前执行 fig_pos get(fig, Position); % 返回 [x,y,width,height] ax_pos get(ax, Position); % 返回 [left,bottom,width,height] 归一化值 actual_ax_width ax_pos(3) * fig_pos(3); % 计算实际像素宽 actual_ax_height ax_pos(4) * fig_pos(4); % 计算实际像素高 fprintf(Axes 实际尺寸: %.0f x %.0f 像素\n, actual_ax_width, actual_ax_height);若actual_ax_width≠ 640 或actual_ax_height≠ 480则需调整axes(Position, [...])中的width/height值或在VideoWriter初始化时显式设置Sizevid VideoWriter(traffic_simulation.avi, Motion JPEG AVI); vid.FrameRate 10; vid.Size [640, 480]; % 强制指定尺寸忽略 figure 自动缩放 open(vid);5.2 相位切换错乱验证时间断点累积误差长时间仿真300 秒可能出现mod(t_sim, t_breakpoints(end))因浮点误差导致断点越界。修复方式是每周期重置t_cyclecycle_len t_breakpoints(end); t_cycle t_sim - floor(t_sim / cycle_len) * cycle_len; % 替代 mod() idx find(t_breakpoints t_cycle, 1, last);同时在t_breakpoints末尾显式添加cycle_len值避免find返回空t_breakpoints [t_breakpoints, cycle_len]; % 确保最后一个断点等于周期长5.3 界面卡顿或 CPU 占用过高禁用非必要渲染drawnow limitrate限制刷新率但若仍卡顿可关闭实时渲染仅录像% 注释掉 drawnow仅保留录像写入 % drawnow limitrate; % 或改用更低频刷新 if mod(floor(t_sim), 1) 0 % 每秒刷新一次界面 drawnow limitrate; end此外VideoWriter的Quality参数是性能关键Quality70可降低 40% CPU 占用而视觉差异肉眼难辨。参数推荐值效果说明FrameRate10高于 15 fps 对红绿灯切换无意义徒增文件体积Quality70–8570 为性能与画质平衡点95 仅用于最终汇报录像CompressionMethodMotion JPEG AVI兼容性最好Matlab 各版本均支持避免MPEG-4在旧版本报错最后若需导出高清 1080p 录像不要直接放大axes尺寸而应重建light_pos坐标系并重设vid.Size [1920,1080]否则灯组会因像素插值模糊。本文还有配套的精品资源点击获取