![9973e27c0c92488b67699cdc4e8f01e0.png](https://i-blog.csdnimg.cn/blog_migrate/f7acffe34ca3f9d0aaa9f738348efe94.jpeg)
![45293ca5f6a35e1b34db7306df9e4296.gif](https://i-blog.csdnimg.cn/blog_migrate/e3a05612deb43e8520f4734fcb795aff.gif)
以往的大部分交通流仿真模型都是建立在交通流中只有一种车型的前提下,这显然与现实不符,所以本模型旨在建立基于元胞自动机的混合车流的交通流仿真模型。不过由于这两周课程有点紧,只在交通流中区分了汽车和卡车两种车辆类型,且两者只有车长和最大速度不同的区别。
本模型是在之前单向三车道模型的基础上更改形成。原理很简单且省事。简单说就是建立一个与汽车结构体内容完全相同的卡车结构体,引入flag参数,值可取1,0,分别代表汽车,卡车,这样做的好处是可以直接在原来为只有汽车写的函数稍作改动就可以直接用于卡车。需要做的一些改动比如,计算卡车后方车距要从卡车尾部算起,卡车换道还需要判断目标车道与尾部同列的位置是否有车以及卡车换道需要头部尾部都位置改变等,而还有很多是不需要改动的,比如换取与前车距离,车辆跟驰等。除此以外,卡车也采取了用固定车辆数和周期边界。
还是先贴代码,再说缺点哈。
脚本
%% 混合流模型
%% 此模型车辆从左向右运动,左右车道是以车辆前进方向的左右
clc;
clear;
%% 参数设置
lane_length = 200; %车道长度
car_rate = 0.1; %车辆占有率
truck_rate = 0.1; %卡车占有率
v_max = 5; %最大车速
v_max_truck = 3;%卡车最大速度
time_max = 1000; %仿真步长
time_span = 0.1; %仿真图片输出间隔
p_slowdown = 0.3; %随机慢化概率
p_changelane = 0.3; %驾驶员换道欲望
%% 开始仿真
main(lane_length,car_rate,v_max,time_max,time_span,p_slowdown,p_changelane,truck_rate,v_max_truck);
跟驰函数
function [space,car] = NaSch(space,car,v_max,lane_length,p_slowdown,car_number,flag)
for id = 1:car_number
%% 加速
car.v(id) = min(car.v(id)+1,v_max);
%% 获取车辆前空元胞数以及是否符合满足周期循环
[cycle,empty]=get_empty_front(id,car,v_max,lane_length,space);
%% 判断车辆是否满足周期边界条件
if cycle
%% 减速
car.v(id) = min( car.v(id) , empty );
%% 概率慢化
if rand(1) <= p_slowdown
car.v(id) = max( car.v(id)-1,0 );
end
%% 位置更新
if flag
space ( car.m(id),car.n(id) ) = 0;
car.n(id) = car.n(id) +car.v(id);
space ( car.m(id),car.n(id) ) = 1;
else
space ( car.m(id),car.n(id) ) = 0;
space ( car.m(id),car.n(id)-1 ) = 0;
car.n(id) = car.n(id) +car.v(id);
space ( car.m(id),car.n(id) ) = 1;
space ( car.m(id),car.n(id)-1 ) = 1;
end
else
%% 周期边界条件将头车以原速度道路最左边
if flag
space ( car.m(id),car.n(id) ) = 0;
car.n(id) = 1;
space ( car.m(id),car.n(id) ) = 1;
else
space ( car.m(id),car.n(id) ) = 0;
space ( car.m(id),car.n(id)-1 ) = 0;
car.n(id) = 2;
space ( car.m(id),car.n(id) ) = 1;
space ( car.m(id),car.n(id)-1 ) = 1;
end
end
end
end
主函数
%% 单向3车道主函数
%% 注意:在本模型中车辆位置信息由车道和列两个维度唯一确定
function []= main(lane_length,car_rate,v_max,time_max,time_span,p_slowdown,p_changelane,truck_rate,v_max_truck)
car_number = fix(1+(3*lane_length-1)*car_rate); %按车辆占有率算出的车辆数
truck_number = fix(1+(3*lane_length-1)*truck_rate);
%% 创建空间
space = zeros(3,lane_length);%元胞空间
car = struct('v',zeros(1,car_number),'m',zeros(1,car_number),'n',zeros(1,car_number));% 汽车车辆信息结构体从左到右为速度,车道,列
truck = struct('v',zeros(1,truck_number),'m',zeros(1,truck_number),'n',zeros(1,truck_number));% 卡车车辆车头信息结构体从左到右为速度,车道,列
%% 随机生成初始车辆信息
[space,car,truck] = initialize(space,car,truck,car_number,lane_length,v_max,truck_number,v_max_truck);
%% 显示初始仿真图
figure('name','汽车卡车混合车流','position',[241 132 560 420],'doublebuffer','on');%窗口名称,位置,双缓存)
space = -1*space;
H = imshow(space,[]);
title('汽车卡车混合车流','color','red');
space = -1*space;
%% 开始仿真
for time=1:time_max
%% 换道阶段
[car,space] = change_lane(space,car,car_number,p_changelane,v_max,lane_length,1);
[truck,space] = change_lane(space,truck,truck_number,p_changelane,v_max_truck,lane_length,0); %最后一位数字用于区分卡车换道还是汽车换道
%% 跟驰阶段
[space,car] = NaSch(space,car,v_max,lane_length,p_slowdown,car_number,1);
[space,truck] = NaSch(space,truck,v_max_truck,lane_length,p_slowdown,truck_number,0);
%% 显示仿真图
space = -1*space;
set(H,'CData',space);
pause(time_span);
space = -1*space;
end
end
初始化函数
function [space,car,truck] = initialize(space,car,truck,car_number,lane_length,v_max,truck_number,v_max_truck)
%% 随机生成初始汽车车辆信息
for id=1:car_number
%% 位置信息初始化
if id<=fix(car_number/3)
%% 最左边车道随机投放车辆
car.m(id) = 1;
car.n(id) = fix( 1+rand(1)*(lane_length-1) );
while space(car.m(id),car.n(id))==1
car.n(id) = fix( 1+rand(1)*(lane_length-1) );
end
space( 1,car.n(id) ) = 1;
elseif id<fix( (car_number*2)/3 )
%% 中间车道随机投放车辆
car.m(id) = 2;
car.n(id) = fix( 1+rand(1)*(lane_length-1) );
while space(car.m(id),car.n(id))==1
car.n(id) = fix( 1+rand(1)*(lane_length-1) );
end
space( 2,car.n(id) ) = 1;
else
%% 最右边车道投放车辆
car.m(id) = 3;
car.n(id) = fix( 1+rand(1)*(lane_length-1) );
while space(car.m(id),car.n(id))==1
car.n(id) = fix( 1+rand(1)*(lane_length-1) );
end
space( 3,car.n(id) ) = 1;
end
%% 速度信息初始化
car.v(id) = fix( 1+rand(1)*(v_max-1) );
end
%% 随机生成初始卡车车辆信息
for id=1:truck_number
%% 位置信息初始化
if id<=fix(truck_number/3)
%% 最左边车道随机投放车辆
truck.m(id) = 1;
truck.n(id) = fix( 1+rand(1)*(lane_length-1) );
while ( space(truck.m(id),truck.n(id))==1 || space(truck.m(id),max(truck.n(id)-1,1))==1) || truck.n(id)==1
truck.n(id) = fix( 1+rand(1)*(lane_length-1) );
end
space( 1,truck.n(id) ) = 1;
space(truck.m(id),truck.n(id)-1)=1;
elseif id<fix( (truck_number*2)/3 )
%% 中间车道随机投放车辆
truck.m(id) = 2;
truck.n(id) = fix( 1+rand(1)*(lane_length-1) );
while ( space(truck.m(id),truck.n(id))==1 || space(truck.m(id),max(truck.n(id)-1,1))==1) || truck.n(id)==1
truck.n(id) = fix( 1+rand(1)*(lane_length-1) );
end
space( 2,truck.n(id) ) = 1;
space(truck.m(id),truck.n(id)-1)=1;
else
%% 最右边车道投放车辆
truck.m(id) = 3;
truck.n(id) = fix( 1+rand(1)*(lane_length-1) );
while ( space(truck.m(id),truck.n(id))==1 || space(truck.m(id),max(truck.n(id)-1,1))==1) || truck.n(id)==1
truck.n(id) = fix( 1+rand(1)*(lane_length-1) );
end
space( 3,truck.n(id) ) = 1;
space(truck.m(id),max(truck.n(id)-1,1))=1;
end
%% 速度信息初始化
truck.v(id) = fix( 1+rand(1)*(v_max_truck-1) );
end
end
获取前车距函数
%用于求出cell_i与前方元胞空元胞数并判断是否需要执行周期边界条件,cycle返回值为1不需要,0需要
% 输出EmptyFront为输入车辆处元胞前方空元胞数(超过v_max按v_max算)
function [cycle,empty_front] = get_empty_front(id,car,v_max,lane_length,space)
empty_front = 0;
cycle=1;
if car.n(id)+v_max < lane_length-v_max %判断是否到边界(lane_length-v_max)
%% 求出车辆前方空元胞数
for front= ( car.n(id) + 1 ) : ( car.n(id) + v_max )
if space( car.m(id),front )==1
empty_front = front- (car.n(id)+1);
break;
end
empty_front = v_max;
end
else
%% 判断是否是头车
first = 1;
for front= min( ( car.n(id) + 1 ),lane_length ) :lane_length
if space( car.m(id),front )==1
empty_front = front- (car.n(id)+1); %不是头车就输出空格数
first =0;
break;
end
end
if first
%% 判断头车下一时间步是否可能移动到lane_length-1处
if car.n(id)+car.v(id)+1 >= lane_length-1
cycle = 0;
else
empty_front =v_max; %只要头车下一秒不到达lane_length前方空元胞数按v_max记
end
end
end
end
获取指定位置前后车距函数
%% 本函数用于求输入车辆前后车距
%% 输入参数m,n为一辆车的位置信息,输出该车所在车道前后车距,车距超过安全车距按安全车距算
function [empty_back,empty_front] = get_empty(m,n,v_max,space,lane_length,flag)
empty_back = 0;
empty_front = 0;
if flag %判断车辆类型
%% 求出汽车后方空元胞数
for back= n :-1: max(n-v_max ,1)
if space( m,back )==1
empty_back =n-back;
break;
end
empty_back = v_max;
end
else
%% 求出卡车后方空元胞数
for back= n-1 :-1: max(n-v_max ,1)
if space( m,back )==1
empty_back =n-1-back;
break;
end
empty_back = v_max;
end
end
%% 获取车辆前方空元宝数
for front= n: min(n+ v_max,lane_length)
if space( m,front )==1
empty_front = n-front;
break;
end
empty_front = v_max;
end
end
换道函数
%% 换道函数
function [car,space] = change_lane(space,car,car_number,p_changelane,v_max,lane_length,flag)
empty_safe = v_max; %安全车距
for id = 1:car_number
[cycle,empty]=get_empty_front(id,car,v_max,lane_length,space);%卡车与汽车前方空格数求取方法相同,不予区分
if cycle %执行周期边界条件车辆不换道
if car.m(id) == 1
%% 最左侧车道换道
%% 获取周边车距
[empty_right_back,empty_right_front] = get_empty(car.m(id)+1,car.n(id),v_max,space,lane_length,flag);%flag用于区分车辆类型,1为汽车
if car.v(id)<= empty
%% 前车阻碍对速度的追求
if empty_right_front>=empty_safe && empty_right_back>=empty_safe && space( car.m(id)+1,car.n(id) )==0 %右前,右后,旁边均安全
%% 满足安全条件换道
if flag
space (car.m(id),car.n(id)) =0;
car.m(id) = car.m(id)+1;
space (car.m(id),car.n(id)) =1;
else
if space( car.m(id)+1,max(car.n(id)-1,1) )==0 %卡车还有判断尾部目标车道位置是否有车
space (car.m(id),car.n(id)) =0;
space (car.m(id),car.n(id)-1) =0;
car.m(id) = car.m(id)+1;
space (car.m(id),car.n(id)) =1;
space (car.m(id),car.n(id)-1) =1;
end
end
end
else
%% 前车无影响
if rand(1)<p_changelane %概率换道
if empty_right_front>empty_safe && empty_right_back>empty_safe && space( car.m(id)+1,car.n(id) )==0 %右前,右后,旁边均安全
%% 满足安全条件换道
if flag
space (car.m(id),car.n(id)) =0;
car.m(id) = car.m(id)+1;
space (car.m(id),car.n(id)) =1;
else
if space( car.m(id)+1,max(car.n(id)-1,1) )==0 %卡车还有判断尾部目标车道位置是否有车
space (car.m(id),car.n(id)) =0;
space (car.m(id),car.n(id)-1) =0;
car.m(id) = car.m(id)+1;
space (car.m(id),car.n(id)) =1;
space (car.m(id),car.n(id)-1) =1;
end
end
end
end
end
elseif car.m(id) ==2
%% 中间车道换道
%% 获取周边车距
[empty_right_back,empty_right_front] = get_empty(car.m(id)+1,car.n(id),v_max,space,lane_length,flag);
[empty_left_back,empty_left_front] = get_empty(car.m(id)-1,car.n(id),v_max,space,lane_length,flag);
if car.v(id)<= empty
%% 前车阻碍对速度的追求
%% 向右换道
if empty_right_front>=empty_safe && empty_right_back>=empty_safe && space( car.m(id)+1,car.n(id) )==0 %右前,右后,旁边均安全
%% 右边满足安全条件换道
if flag
space (car.m(id),car.n(id)) =0;
car.m(id) = car.m(id)+1;
space (car.m(id),car.n(id)) =1;
else
if space( car.m(id)+1,max(car.n(id)-1,1) )==0 %卡车还有判断尾部目标车道位置是否有车
space (car.m(id),car.n(id)) =0;
space (car.m(id),car.n(id)-1) =0;
car.m(id) = car.m(id)+1;
space (car.m(id),car.n(id)) =1;
space (car.m(id),car.n(id)-1) =1;
end
end
%% 向左换道
elseif empty_left_front>=empty_safe && empty_left_back>=empty_safe && space( car.m(id)-1,car.n(id) )==0
%% 满足安全条件换道
if flag
space (car.m(id),car.n(id)) =0;
car.m(id) = car.m(id)-1;
space (car.m(id),car.n(id)) =1;
else
if space( car.m(id)-1,max(car.n(id)-1,1) )==0 %卡车还有判断尾部目标车道位置是否有车
space (car.m(id),car.n(id)) =0;
space (car.m(id),car.n(id)-1) =0;
car.m(id) = car.m(id)-1;
space (car.m(id),car.n(id)) =1;
space (car.m(id),car.n(id)-1) =1;
end
end
end
%% 前车不阻碍速度追求
else
%% 以一定几率向右换道
if rand(1)<p_changelane
if empty_right_front>empty_safe && empty_right_back>empty_safe && space( car.m(id)+1,car.n(id) )==0 %右前,右后,旁边均安全
%% 满足安全条件换道
if flag
space (car.m(id),car.n(id)) =0;
car.m(id) = car.m(id)+1;
space (car.m(id),car.n(id)) =1;
else
if space( car.m(id)+1,max(car.n(id)-1,1) )==0 %卡车还有判断尾部目标车道位置是否有车
space (car.m(id),car.n(id)) =0;
space (car.m(id),car.n(id)-1) =0;
car.m(id) = car.m(id)+1;
space (car.m(id),car.n(id)) =1;
space (car.m(id),car.n(id)-1) =1;
end
end
end
end
end
else
%% 最右侧车辆换道
%% 获取周边车距
[empty_left_back,empty_left_front] = get_empty(car.m(id)-1,car.n(id),v_max,space,lane_length,flag);
if car.v(id)<= empty
%% 前车阻碍对速度的追求
if empty_left_front>=empty_safe && empty_left_back>=empty_safe && space( car.m(id)-1,car.n(id) )==0 %右前,右后,旁边均安全
%% 满足安全条件换道
if flag
space (car.m(id),car.n(id)) =0;
car.m(id) = car.m(id)-1;
space (car.m(id),car.n(id)) =1;
else
if space( car.m(id)-1,max(car.n(id)-1,1) )==0 %卡车还有判断尾部目标车道位置是否有车
space (car.m(id),car.n(id)) =0;
space (car.m(id),car.n(id)-1) =0;
car.m(id) = car.m(id)-1;
space (car.m(id),car.n(id)) =1;
space (car.m(id),car.n(id)-1) =1;
end
end
end
else
%% 前车无影响
if rand(1)<p_changelane
if empty_left_front>empty_safe && empty_left_back>empty_safe && space( car.m(id)-1,car.n(id) )==0 %右前,右后,旁边均安全
%% 满足安全条件换道
if flag
space (car.m(id),car.n(id)) =0;
car.m(id) = car.m(id)-1;
space (car.m(id),car.n(id)) =1;
else
if space( car.m(id)-1,max(car.n(id)-1,1) )==0 %卡车还有判断尾部目标车道位置是否有车
space (car.m(id),car.n(id)) =0;
space (car.m(id),car.n(id)-1) =0;
car.m(id) = car.m(id)-1;
space (car.m(id),car.n(id)) =1;
space (car.m(id),car.n(id)-1) =1;
end
end
end
end
end
end
end
end
end
说一下缺点,其实很多。
1.车辆类型依然只有两种。
2.汽车与卡车的行为差别没有查阅相关文章进行很好的区分。
3.目前函数中汽车结构体先作为参数运行换道函数,这样造成汽车与卡车有换道冲突点(比如,汽车,卡车一左一右均向中间车道同一位置换道)时,总是汽车拥有优先占有权利,与现实不符。
4.目前的可视化运用在混合车流效果很不好,需要学习别的可视化方法以及做GUI。
最后还是希望有想法的小伙伴可以加我一起讨论学习哈。