资讯动态

基于MATLAB的三车道元胞自动机交通流仿真

发布时间:2026/9/16 10:07:07 来源:尧图企业网站定制
简介面向交通工程、智能交通和复杂系统仿真领域的本科高年级学生、研究生及相关从业者这份源码工程以元胞自动机方法搭建三车道交通流仿真模型完整涵盖车辆生成、跟驰/换道决策、随机慢化及位置更新等核心环节可直接用于教学演示、毕业设计或科研预研。压缩包体积小巧共9个文件以8个m函数脚本和1个AVI操作演示视频组成核心代码按功能拆分为若干独立子函数主程序入口清晰便于分步调试和二次开发。已有1109人浏览学习作者还配有操作录像可大幅降低上手门槛。下载内容包含一整套可运行的三车道交通流模拟仿真样例既能快速复现车辆换道与拥堵演化场景也能在建模基础上调整参数、扩展规则同时操作演示视频覆盖环境配置、运行方式与常见注意事项适合Matlab 2021a及以上版本使用帮助使用者有效避开路径设置、子函数误运行等典型问题。1. 三车道交通流模拟为什么值得用元胞自动机重写一遍高速公路三车道明明没有物理障碍车流却会无缘无故走走停停。流体力学模型能算出平均流量但解释不了“幽灵拥堵”是怎么成核的。元胞自动机用离散的格点、车辆速度和几条简单规则把这种涌现现象直接跑出来这就是这个标题的核心价值在 MATLAB 里实现三车道元胞自动机并通过代码操作演示视频直观展示每一步参数变化带来的交通流演化。这个项目适合两类人一类是交通工程、计算机仿真相关专业的学生需要课程设计或论文里的仿真图和基本图数据另一类是刚接触元胞自动机的工程师想用最少代码理解“换道规则 跟车规则”如何影响流量。下面从元胞自动机的规则讲起到 MATLAB 实现再到流量-密度验证最后给出从三车道向外扩展的方向。2. 元胞自动机交通流模型的核心规则与三车道扩展2.1 从 NaSch 模型说起四条规则如何撑起交通流仿真交通流元胞自动机的起点是 NaSch 模型它把道路切成等长的格子每格要么空着要么被一辆车占据。时间步通常取 1 秒格子长度取 7.5 米速度用“每时间步经过的格子数”表示。三车道不过是在这个基础上有三条并行的格子行但跟车规则完全相同。每个时间步每辆车依次执行四步加速如果当前速度小于最大速度则v v 1安全减速计算同一车道前车与本车的空格数gap令v min(v, gap)随机慢化以概率pSlow让速度减 1这是模拟驾驶员不可能完全保持一致的行为位置更新pos pos v。随机慢化最容易被人忽略但它是“走走停停”现象的关键。没有这一条车流会始终保持着完全均匀的分布加进去之后很小的扰动会被后续车辆放大形成自发的拥堵波。在 MATLAB 里写出来就是一个简短函数function vNew nashStep(v, gap, vMax, pSlow) vNew min(v 1, vMax); % 加速 vNew min(vNew, gap); % 安全减速 if vNew 0 rand() pSlow vNew vNew - 1; % 随机慢化 end end这个函数是单辆车一步内的速度更新。v是当前速度gap是同车道前车与本车之间的空格数vMax是道路限速对应的格子数pSlow是随机慢化概率。调用时注意gap必须用更新前的车辆位置计算不能用上一步已经移动过的位置否则会出现两辆车同时占用一个格子的错误。三车道比单车道多出来的不是跟车规则而是车辆可以选择换道。严格地说NaSch 的同步更新要求先基于旧位置算完所有车的速度再统一移动。上面的写法是按顺序处理的适合先跑通流程要保证严格的同步可以在函数里把速度和位置分两个循环完成。2.2 三车道换道规则什么时候换、往哪条车道换三车道模型中换道是每个时间步在“加速”之前执行的动作。我一般把换道决策简化为三个条件当前车道不满足期望速度即当前车道前车间距小于车辆期望速度目标车道前方有更宽的间隙能比当前车道跑得更快目标车道后方没有追尾风险后车间隙大于一个安全阈值。具体参数可以按下面的表格设置。表中内容同时对应代码里stepTraffic函数中的判断变量。判断条件表达式常见取值当前车道不满足gap min(vel1, vMax)gap由前车位置计算目标车道前方更宽gapF gapgapF为目标车道前车间距目标车道后方安全gapB vMax安全阈值一般取vMax到vMax1换道概率rand() pLanepLane 0.1 ~ 0.4换道方向我通常优先尝试内车道即从右往左换。国内高速公路左侧为快车道所以超车后应回到右侧车道仿真为了简化可以只允许慢车向左换道快车不主动向右换。这个偏好可以用候选车道顺序调整。下面这段代码是换道判断片段% 换道判断片段 if gap min(vel1, vMax) for newLane [lane1, lane-1] if newLane 1 || newLane 3 continue; end if gapF gap gapB vMax rand() pLane break; % 执行换道 end end end这里gapF和gapB分别代表目标车道前车和后车与本车的距离。注意pLane不等于“每辆车每步都换道”它只是条件满足后的概率。实际仿真中如果pLane取 0.2那么每辆车平均 5 次满足条件才会换 1 次这个值调得越大车道间的流量分配越均匀但过大也会引发频繁换道带来的扰动。还有一个容易被忽略的细节目标车道后车的“后车间隙”必须考虑周期边界。如果目标车道上没有落后于本车的车辆gapB应该是无穷大而不是零。后文中laneGap子函数返回的gapB Inf就是这个意思。2.3 边界条件与初始化周期边界才能跑出流量统计规律三车道交通流仿真有两种常见边界开边界和周期边界。开边界在路段两端设置进车和出车逻辑适合模拟高速匝道附近的车流周期边界把首尾相连成环形路车辆数不变适合研究固定密度下交通流的基本图。标题里的三车道模拟仿真绝大多数情况采用周期边界因为不需要额外处理“入口排队”和“出口消散”。周期边界下的初始化没有太多技巧但要保证车辆位置不能重叠。我一般先把车辆均匀随机撒在三车道上初始速度设为 0然后先跑 200 到 500 步“暖机”等车间距和速度分布稳定后再开始统计数据。L 600; % 路段格点数 N 180; % 总车辆数 cars zeros(N, 4); cars(:, 1) (1:N); % 车辆编号 cars(:, 2) randi(3, N, 1); % 所在车道 1/2/3 cars(:, 3) randi(L, N, 1); % 位置 cars(:, 4) 0; % 初始速度代码中的四列分别对应车辆 ID、车道、位置和速度。randi(3,N,1)随机选择车道randi(L,N,1)随机选择位置。这里如果 N 取得太大比如超过 3L 的 80%初始位置重叠概率会显著上升需要加一个查重循环把冲突车辆移到空位上。实际仿真里密度最好不要超过 0.6。3. 在 MATLAB 中搭建三车道仿真框架数据结构到动画显示3.1 用矩阵还是结构体车辆表是四列就够写 MATLAB 交通流仿真第一件事是决定用什么数据结构保存车辆。用结构体数组cars struct(pos,{},vel,{})可读性好但每次访问字段都有解释开销用 N×4 矩阵存车辆表配合sortrows排序性能更好代码也更接近 C 语言实现。四列的用途再强调一次id用于调试时追踪单车轨迹lane是 1 到 3 的车道编号pos是格点位置vel是当前速度。在后面的stepTraffic函数中所有计算都围绕这四列展开。因为每辆车在路面上是不断移动的每次更新前我都先对车辆表排序function cars sortCars(cars) cars sortrows(cars, [2 3]); % 先按车道升序再按位置升序 endsortrows(cars,[2 3])的含义是先按第 2 列车道排序再在同一车道内按第 3 列位置排序。这样后面寻找“前车”时只需要在连续的一段索引里找下一个元素不必每次都用find扫描全表。不过要记住排序后的cars行号会变。如果你需要把统计结果写回原始车辆 ID排序前要先把id复制一份出来或者排序后直接用id关联。3.2 一个函数跑完换道、加速、随机慢化和移动把前面两章的规则拼到一起就成了三车道仿真的核心更新函数。下面这个stepTraffic函数是经过简化的版本保留周期边界和换道判断适合直接抄到脚本里调试function cars stepTraffic(cars, L, vMax, pSlow, pLane) N size(cars, 1); cars sortrows(cars, [2 3]); newCars cars; for i 1:N lane cars(i,2); pos cars(i,3); vel cars(i,4); % 当前车道前车间距 idxSame find(cars(:,2) lane); k find(idxSame i, 1); if k numel(idxSame) gap cars(idxSame(k1),3) - pos - 1; else gap L - pos - 1 cars(idxSame(1),3); end % 换道判断并更新前车间距 newLane lane; if gap min(vel1, vMax) for cand [lane1, lane-1] if cand 1 || cand 3 continue; end [gapF, gapB] laneGap(cars, cand, pos, L); if gapF gap gapB vMax rand() pLane newLane cand; gap gapF; % 换道后改用目标车道前车间距 break; end end end % NaSch 速度更新 v1 min(vel1, vMax); v1 min(v1, gap); if v1 0 rand() pSlow v1 v1 - 1; end newCars(i,2) newLane; newCars(i,4) v1; end % 同步移动位置 newCars(:,3) newCars(:,3) newCars(:,4); newCars(:,3) mod(newCars(:,3)-1, L) 1; cars newCars; end function [gapF, gapB] laneGap(cars, lane, pos, L) idx find(cars(:,2) lane); if isempty(idx) gapF L; gapB Inf; return; end posL cars(idx,3); ahead posL(posL pos); if isempty(ahead) gapF L - pos - 1 posL(1); else gapF ahead(1) - pos - 1; end behind posL(posL pos); if isempty(behind) gapB Inf; else gapB pos - behind(end) - 1; end end这个函数我拆成两部分主函数处理每辆车的换道和速度更新子函数laneGap计算目标车道的前后间隙。主函数里的idxSame是在排序后车辆表中寻找同一车道的所有行find(idxSamei,1)找到当前车辆在这段索引中的位置这样gap就是严格按周期边界计算的前车间距。换道判断放在速度更新之前而且依据的是更新前的旧状态。优点是车辆不会出现“边换道边滑行”的逻辑混乱缺点是严格同步更新要求所有车辆换道决策互不依赖如果你希望研究高密度下换道对稳定性的影响需要把换道和速度更新放进同一个旧状态的两遍扫描。newCars(:,3) mod(newCars(:,3)-1, L) 1是 MATLAB 里处理周期位置的标准写法。先减 1 用mod得到 0 到 L-1 的值再加 1 变回 1 到 L。直接用mod(..., L)在位置等于 L 时会变成 0会让车辆消失。3.3 绘制三车道动画用 plot 还是 imagescMATLAB 动画显示有两种常用方案imagesc把道路画成像素图三层车道对应三行高亮块plot把车辆画成散点三个车道用不同的y坐标。我推荐用plot因为车辆数量到几百辆时plot的刷新性能明显好于imagesc而且能方便地按车道染色。一个最小可用的绘图函数如下function drawTraffic(cars, L) clf; colors {#D95319, #0072BD, #EDB120}; for lane 1:3 pos cars(cars(:,2) lane, 3); y lane * ones(size(pos)); plot(pos, y, s, MarkerSize, 7, ... MarkerFaceColor, colors{lane}); hold on; end xlim([1 L]); ylim([0 4]); set(gca, YTick, [1 2 3]); pause(0.01); end这里plot(pos, y, s)用方块表示车辆MarkerFaceColor给不同车道填充不同颜色。车道 1 在图像底部车道 3 在顶部符合一般车道编号顺序。pause(0.01)不是必要的但在循环里加一个短暂停顿可以让 MATLAB 图形窗口有足够时间重绘。配套的代码操作演示视频通常就是基于这个函数录的按下F5后主循环每步调用一次stepTraffic每 10 步调用一次drawTraffic窗口里的车辆就能像流水一样向前移动。录制前记得把pause调大比如0.05否则视频里每秒几十帧反而看不清换道细节。主循环L 600; N 180; vMax 5; pSlow 0.2; pLane 0.2; T 1200; cars [ (1:N), randi(3,N,1), randi(L,N,1), zeros(N,1) ]; for t 1:T cars stepTraffic(cars, L, vMax, pSlow, pLane); if mod(t, 10) 0 drawTraffic(cars, L); end end上面的mod(t,10)0是“每 10 步画一帧”的常见控制办法。如果画每一帧窗口绘制会成为仿真瓶颈密度一大帧率掉到个位数每 10 步画一帧画面仍然连贯性能会好很多。3.4 为什么我不用车道矩阵而用车辆表有一段时期流行的实现是把道路存成road zeros(3,L)元素值代表车上速度。这种方案有个隐蔽的问题当两辆车同时进入同一个空格时矩阵无法保存两辆车的信息只能把后车剔掉。虽然可以在更新前用“目标单元格是否已占用”来避免但处理逻辑比车辆表复杂。车辆表则天然能表示“重叠”因为每辆车是一行即使位置暂时相同ID 也不会丢。当然重叠在真实交通中不该出现所以在更新逻辑里要靠gap和换道安全条件去避免。从调试角度看车辆表能直接打印某一辆车的完整轨迹矩阵方案要额外维护 ID 表才能做到。这个取舍在论文和课程设计里都会遇到我的建议是短路段用矩阵简化代码长路段、大密度场景用车辆表保证正确性。4. 仿真参数标定与实验设计流量-密度图、拥堵识别与稳定性验证4.1 四个核心参数vMax、pSlow、pLane和密度代码跑起来后要回答“这个仿真对不对”先看四个参数。很多课程设计项目直接把网上代码复制下来第一次运行发现全堵住或全空荡问题都出在参数和密度不匹配上。参数含义常用范围现象vMax最大速度单位格/时间步3~5太小流量上不去太大刹车距离不够pSlow随机慢化概率0.1~0.3越大波动和拥堵越早出现pLane换道概率0.1~0.4越小三条车道流量差越大N车辆总数取3*L*密度密度 0.5 容易形成全局拥堵vMax有一个物理换算关系若一格 7.5 米一个时间步 1 秒那么vMax5大致对应 135 km/h。交通仿真论文里常看到vMax5或者vMax3分别代表高速和城市快速路。改变vMax时要同步调整pSlow否则参数组合会偏离真实驾驶行为。pSlow是模拟驾驶员随机踩刹车的行为。它和“密度”互相作用密度低时pSlow只让车流略慢密度超过 0.3 后一个小的随机慢化就可能波及后方十几辆车形成拥堵波。4.2 计算基本图流量-密度曲线怎么画基本图是交通流仿真最重要的验证工具。横轴是密度纵轴是流量流量可以用流量 密度 × 平均速度计算。注意这里的密度是归一化密度即N / (3*L)单位是“每格车辆数”。在 MATLAB 里按不同密度重复仿真统计稳定阶段的平均速度就能得到一条完整的流量-密度曲线L 600; densities 0.05:0.05:0.6; flows zeros(size(densities)); for idx 1:numel(densities) N round(densities(idx) * 3 * L); cars [ (1:N), randi(3,N,1), randi(L,N,1), zeros(N,1) ]; % 跳过暖机阶段 for t 1:500 cars stepTraffic(cars, L, 5, 0.2, 0.2); end % 统计阶段 vSum 0; for t 1:1000 cars stepTraffic(cars, L, 5, 0.2, 0.2); vSum vSum mean(cars(:, 4)); end vAvg vSum / 1000; flows(idx) densities(idx) * vAvg; end plot(densities, flows, -o); xlabel(密度); ylabel(流量);这个脚本里vSum累加每个时间步所有车的平均速度最后除以 1000 得到统计时段平均速度。把mean(cars(:,4))乘以归一化密度得到的就是该密度下的平均流量。画出来的曲线通常先增后减峰值所在的密度就是临界密度超过临界密度后流量下降进入拥堵区间。如果曲线一开始就下降或者峰值出现在密度 0.1 以下大概率是L太短或者暖机时间不够。要注意统计时间内的前 500 步暖机不能省。初始车辆均匀摆放车辆之间有大量“虚拟空隙”如果不暖机前几百步流量会异常偏高。这是新手最容易犯错的地方——提前统计等于把非稳态数据混进了基本图。4.3 排查“换道死锁”和动画卡顿的技巧三车道仿真跑起来有时候会“钉在原处”不动表现形式是整个车流静止。首先检查是不是密度超过 0.5 导致自然堵塞如果密度只有 0.1 却堵死要怀疑换道规则里gapB算错。gapB代表目标车道后方车辆与本车的距离。如果写成gapB vel而不是gapB vMax本车会频繁插到慢车前方后车来不及减速两格距离内车辆相互交错最终堵死。另一个常见问题是换道时用了更新后的cars位置导致同一时间步里前车还没移动后车已经“预判”出更大的间隙。动画卡顿的排查不看drawTraffic内部先看有没有在循环里调用drawnow。MATLAB 的drawnow会强制刷新图形事件每帧调用会损失超过一半性能。正确策略是像上一章那样用mod(t,10)控制每十步刷新一次或者用animatedline渐进式添加点。代码操作演示视频录制时也可以采用同样的策略视频帧率 30fps那么主循环里pause(0.03)刚好与帧率匹配不会丢帧。另一个值得注意的性能点stepTraffic里的find(cars(:,2)lane)每次时间步会对每一辆车扫描一遍全表总复杂度是 O(N^2)。N 到三百左右问题不大N 超过一千时就要改成按车道预分组或者一次性用accumarray把车辆索引分组存储。这个优化写在文章里供你参考初版不需要模拟演示视频里的场景规模一般也在几百辆车以内。5. 从三车道到更高可信度时空图、数据导出与应用扩展5.1 用时空图快速定位模型错误流量-密度图只能告诉你宏观上对不对不能告诉你哪辆车在哪条车道上出了错。时空图是更细的验证工具横轴是位置纵轴是时间图上的点表示某时刻某格被车辆占用。这样能直接看到堵塞波是如何向后传播的。最小实现是每个时间步记录一次指定车道的占用状态spacetime zeros(T, L); for t 1:T cars stepTraffic(cars, L, vMax, pSlow, pLane); occ zeros(1, L); occ(cars(cars(:,2) 2, 3)) 1; spacetime(t, :) occ; end imagesc(spacetime);这里展示的是 2 号车道的时空图。如果时空图里出现斜向上的亮条纹说明车辆整齐地低速行驶没有自组织现象斜向下的条纹才是真实的堵塞波传播方向与车流方向相反。出现水平亮带时说明有一段路总是堵住大概率是换道规则或随机慢化参数不合理。5.2 把统计结果和车辆轨迹导出成 CSV论文图表不能只靠截图我一般会把仿真输出导出成两个文件一个存流量-密度基本图数据一个存每辆车的最终位置和速度。MATLAB 里直接用writematrixwritematrix(flows, flow_density.csv); writematrix(cars, cars_final.csv);writematrix在 R2020b 及以后版本可用旧版本用csvwrite。导出前先确认cars矩阵的列顺序免得把 ID 和车道写反。5.3 三车道模型的下一个目标开放边界和匝道周期边界适合研究基本图但真实高速公路不是闭环。如果题目要求加入收费站、上匝道或信号灯需要把周期边界改为开放边界左端按概率生成车辆右端删除超过路段的车辆。核心改动集中在stepTraffic外增加一个入口计数器而不是修改跟车规则。改好之后你会看到三车道模型在开放边界下的涌入-涌出关系比闭环复杂得多这也是从“演示”走向“研究”必经的一步。最后给你一个录制演示视频时的实用小技巧在drawTraffic里把三条车道画成三条静态参考线车辆用实心方块覆盖在上面用exportgraphics(gcf,frame.png)逐帧导出比直接录屏更清晰连续帧用ffmpeg拼成 mp4文件体积比实时录屏小一半。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价