![03d287b988d809d6f6d98ffb41e7f96d.png](https://i-blog.csdnimg.cn/blog_migrate/4869899402d90a29a855a1f34d65bbc7.png)
![e2b9e50ee754ab0be2f39f30ff0abe35.gif](https://i-blog.csdnimg.cn/blog_migrate/ea2a9152f210e6a1da6824b5a6f9f6ed.gif)
本模型为包含一条变速车道和出入匝道的快速路交织区仿真模型。
![ab9dcf4fa1b5b3c8f16a4af6c66cae89.png](https://i-blog.csdnimg.cn/blog_migrate/2df28fe572ac7bae82ba4bdf32ec9341.jpeg)
换道规则和不含出入匝道的路段的区别在于换道分为自由换道和强制换道。车辆在不同区域有不同换道状态,而车辆本身又有出匝道和直行(入匝道车辆归为直行车辆)两种状态,共同决定车辆换道行为。在自由换道区域(1,2,3,7,8,10,11,12车道)内按照普通路段换道规则换道,且不区分出匝道和直行车辆,即,若前车阻碍车辆对速度的追求则必定换道,且优先左换道,若前车无影响则概率左换道,而为了编程方便,规定两车道交界处,即,下一时间步将会驶出所在车道的车辆不允许换道。而强制换道区域(4,5,6,9,15)内换道规则因车辆状态的不同而不同,直行状态车辆任然按自由换道区域内车辆换道规则换道,出匝道车辆换道规则为,4车道中出匝道车辆强制向5车道换道,5车道车辆强制向6车道换道,6车道出匝道车辆不允许换道,这符合现实生活中车辆提前驶入靠变速车道车道的情况。其中,15车道车辆中为直行状态车辆(入匝道车辆)换道规则与出匝道车辆换道规则相反。
跟驰规则和NaSch模型基本规则相同,区分是驶出所在车道会驶入下一车道。
边界条件依然是周期边界条件,四个驶出车道,四个驶入车道,一一对应。
还是先贴代码,再说缺点哈。
脚本
%% 交织区仿真
clc;
clear;
%% 参数设置
lane_length = 100; %车道长度
car_rate = 0.2;%车道占有率
time_span = 0.1;%图片输出时间间隔
p_out = 0.5;%车辆出匝道概率
v_max = 5;%最大速度
time_max = 1000;%仿真步长
p_changelane = 0.3;%车辆换道概率
p_slowdown = 0.3;%随机慢化概率
%% 调用函数
main(v_max,lane_length,time_span,p_out,car_rate,time_max,p_changelane,p_slowdown);
跟驰函数
function [lanes,car] = NaSch(lanes,car,v_max,lane_length,p_slowdown,car_number,p_out)
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,lanes);
%% 判断车辆是否满足周期边界条件
if cycle %0是头车,1非头车
%% 减速
car.v(id) = min( car.v(id) , empty );
%% 概率慢化
if rand(1) <= p_slowdown
car.v(id) = max( car.v(id)-1,0 );
end
%% 位置更新
lanes ( car.lane(id),car.n(id) ) = 0; %位置更新前元胞变为无车
car.n(id) = car.n(id) +car.v(id);
lanes ( car.lane(id),car.n(id) ) = 1;
else
if car.lane(id)==10||car.lane(id)==11||car.lane(id)==12||car.lane(id)==13
%% 10,11,12,13执行周期边界条件
switch car.lane(id)
case 10
lanes(car.lane(id),car.n(id)) =0;
car.lane(id) = 1;
car.n(id) = 1;
lanes(car.lane(id),car.n(id)) = 1;
if rand(1)<p_out
car.state(id) = 1;%概率驶出匝道
end
case 11
lanes(car.lane(id),car.n(id)) =0;
car.lane(id) = 2;
car.n(id) = 1;
lanes(car.lane(id),car.n(id)) = 1;
if rand(1)<p_out
car.state(id) = 1;%概率驶出匝道
end
case 12
lanes(car.lane(id),car.n(id)) =0;
car.lane(id) = 3;
car.n(id) = 1;
lanes(car.lane(id),car.n(id)) = 1;
if rand(1)<p_out
car.state(id) = 1;%概率驶出匝道
end
case 13
lanes(car.lane(id),car.n(id)) =0;
car.lane(id) = 14;
car.n(id) = 1;
lanes(car.lane(id),car.n(id)) = 1;
car.state(id) = 0;%状态更改为直行
end
elseif car.lane(id)==1||car.lane(id)==2||car.lane(id)==3||car.lane(id)==4||car.lane(id)==5||car.lane(id)==6||car.lane(id)==7||car.lane(id)==8||car.lane(id)==9
%% 1,2,3,4,5,6,7,8,9驶入另一条车道
[~,empty_next] = get_empty(car.lane(id)+3,1,v_max,lanes,lane_length);%获得与驶入车道前车的距离
%% 减速
car.v(id) = min( car.v(id) , empty+empty_next );
%% 概率慢化
if rand(1) <= p_slowdown
car.v(id) = max( car.v(id)-1,0 );
end
%% 位置更新
if car.v(id)<=empty
%% 仍在当前车道
lanes(car.lane(id),car.n(id)) = 0;
car.n(id) = car.n(id)+car.v(id) ;
lanes(car.lane(id),car.n(id)) = 1;
else
%% 驶入下一车道
lanes(car.lane(id),car.n(id)) = 0;
car.lane(id) = car.lane(id)+3;
car.n(id) = 1+car.v(id)-empty;
lanes(car.lane(id),car.n(id)) = 1;
end
else
if car.lane(id) ==14
%15车道首个元胞无车则驶入,否则在入口等待
if lanes(15,1)==0
lanes(car.lane(id),car.n(id))=0;
car.lane(id)=15;
car.n(id)=1;
lanes(car.lane(id),car.n(id))=1;
else
lanes(14,car.n(id))=0;
car.n(id)=lane_length;
lanes(car.lane(id),car.n(id))=1;
end
else
%15车道头车在11车道首个元胞无车则驶入,否则在出口等待
if lanes(13,1)==0
lanes(car.lane(id),car.n(id))=0;
car.lane(id)=13;
car.n(id)=1;
lanes(car.lane(id),car.n(id))=1;
else
lanes(car.lane(id),car.n(id))=0;
car.n(id)=lane_length;
lanes(car.lane(id),car.n(id))=1;
end
end
end
end
end
end
主函数
function main(v_max,lane_length,time_span,p_out,car_rate,time_max,p_changelane,p_slowdown)
%% 空间,车道,车辆状态初始化
car_number = fix(14*lane_length*car_rate); %车辆数
[space,lanes,car]=initialiaze (v_max,lane_length,p_out,car_number);
%% 显示初始图像
H = imshow (space,[-1,0]);
%% 开始仿真
for time = 1:time_max
%% 换道
[car,lanes] = change_lane(lanes,car,car_number,p_changelane,v_max,lane_length);
%% 跟驰
[lanes,car] = NaSch(lanes,car,v_max,lane_length,p_slowdown,car_number,p_out);
%% 车道状态更新
space(1,1:lane_length) = lanes(1,:);
space(2,1:lane_length) = lanes(2,:);
space(3,1:lane_length) = lanes(3,:);
space(1,lane_length+1:2*lane_length) = lanes(4,:);
space(2,lane_length+1:2*lane_length) = lanes(5,:);
space(3,lane_length+1:2*lane_length) = lanes(6,:);
space(1,2*lane_length+1:3*lane_length) = lanes(7,:);
space(2,2*lane_length+1:3*lane_length) = lanes(8,:);
space(3,2*lane_length+1:3*lane_length) = lanes(9,:);
space(1,3*lane_length+1:4*lane_length) = lanes(10,:);
space(2,3*lane_length+1:4*lane_length) = lanes(11,:);
space(2,3*lane_length+1:4*lane_length) = lanes(12,:);
space(5:end,3*lane_length) = lanes(13,:)';
space(end:-1:5,2*lane_length+1) = lanes(14,:)';%注意此处的转置和元素反取
space(4,2*lane_length+1:3*lane_length) = lanes(15,:);
%% 输出图像
space = -1*space;
set(H,'CData',space);
pause(time_span);
space = -1*space;
end
end
初始化函数
function [space,lanes,car]=initialiaze (v_max,lane_length,p_out,car_number)
%% 创建空间
space = zeros(4+lane_length,4*lane_length);
%非车道空间状态为0.1
space(4:end,1:2*lane_length)=0.1;
space(5:end,2*lane_length+1:3*lane_length-1)=0.1;
space(4:end,3*lane_length+1:4*lane_length)=0.1;
%创建车道矩阵
lanes = zeros(15,lane_length);%每行储存对应编号车道位置信息
%% 车辆结构体的创建
car = struct('v',zeros(1,car_number),'lane',zeros(1,car_number),'n',zeros(1,car_number),'state',zeros(1,car_number));
%依次为速度,所在车道编号,所在车道元胞位置,行驶状态
%% 车辆状态初始化
for a =1:14
%向 a 车道随机投放车辆
for id = fix(car_number/14)*(a-1)+1 : fix(car_number/14)*a
car.lane(id) = a;
car.n(id) = fix( 1+rand(1)* (fix(lane_length-1) ) );
lanes( car.lane(id),car.n(id) ) = 1; %有车状态为1
car.v(id) = fix( 1+rand(1)*(v_max-1) );%随机生成速度
if rand(1)<p_out
car.state(id) = 1;%出匝道车辆state值为1
end
end
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,lanes)
empty_front = 0;
cycle=1;
if car.n(id) < lane_length-v_max %判断是否到边界(lane_length-v_max)
%% 求出车辆前方空元胞数
front = car.n(id) + 1;
while front~=car.n(id) + v_max
if lanes( car.lane(id),front )==1
empty_front = front- (car.n(id)+1);
break;
end
front = front +1;
end
if front == car.n(id) + v_max
empty_front = v_max;
end
else
%% 判断是否是头车,非头车必定无法驶出车道
front= min( ( car.n(id) + 1 ),lane_length );
while front ~=lane_length
if lanes( car.lane(id),front )==1
empty_front = front- min( ( car.n(id) + 1 ),lane_length ); %不是头车就输出空格数
break;
end
front = front +1;
end
if front == lane_length %前方无车则可能驶出车道
empty_front = lane_length-car.n(id);
cycle = 0;
end
end
end
获取指定位置与前后首车距离
%% 本函数用于求输入车辆前后车距
%% 输入参数m,n为一辆车的位置信息,输出该车所在车道前后车距,车距超过安全车距按安全车距算
function [empty_back,empty_front] = get_empty(m,n,v_max,lanes,lane_length)
empty_back = 0;
empty_front = 0;
%% 求出车辆后方空元胞数
for back= n :-1: max(n-v_max ,1)
if lanes( m,back )==1
empty_back =n-back;
break;
end
empty_back = v_max;
end
%% 获取车辆前方空元宝数
for front= n: min(n+ v_max,lane_length)
if lanes( m,front )==1
empty_front = front-n;
break;
end
empty_front = v_max;
end
end
右侧车辆换道函数
function [lanes,car] = change_lane_right(id,lanes,car,v_max,lane_length,p_changelane,empty_safe)
%右侧车道车辆换道函数
[~,empty]=get_empty_front(id,car,v_max,lane_length,lanes);%获取前方车距
[empty_left_back,empty_left_front] = get_empty(car.lane(id)-1,car.n(id),v_max,lanes,lane_length);
if empty<min(car.v(id)+1,v_max)
%% 前车阻碍车辆对速度的追求
if empty_left_front>=empty && empty_left_back>=empty_safe && lanes( car.lane(id)-1,car.n(id) )==0 %旁边车道距离更大,左后,旁边均安全
%% 满足安全条件换道
lanes(car.lane(id),car.n(id)) =0;
car.lane(id) = car.lane(id)-1;
lanes(car.lane(id),car.n(id)) =1;
end
else
%% 前车无影响则概率换道
if rand(1)<p_changelane
if empty_left_front>=empty && empty_left_back>=empty_safe && lanes( car.lane(id)-1,car.n(id) )==0 %旁边车道距离更大,左后,旁边均安全
%% 满足安全条件换道
lanes(car.lane(id),car.n(id)) =0;
car.lane(id) = car.lane(id)-1;
lanes(car.lane(id),car.n(id)) =1;
end
end
end
end
中间车辆换道函数
function [lanes,car] = change_lane_middle(id,lanes,car,v_max,lane_length,p_changelane,empty_safe)
%中间车道换道
%% 获取周边车距
[~,empty]=get_empty_front(id,car,v_max,lane_length,lanes);%获取前方车距
[empty_right_back,empty_right_front] = get_empty(car.lane(id)+1,car.n(id),v_max,lanes,lane_length);
[empty_left_back,empty_left_front] = get_empty(car.lane(id)-1,car.n(id),v_max,lanes,lane_length);
if empty<min(car.v(id)+1,v_max)
%% 前车阻碍车辆对速度的追求
%% 优先左换道
if empty_left_front>=empty && empty_left_back>=empty_safe && lanes( car.lane(id)-1,car.n(id) )==0 %旁边车道距离更大,左后,旁边均安全
%% 满足左换道安全条件换道
lanes(car.lane(id),car.n(id)) =0;
car.lane(id) = car.lane(id)-1;
lanes(car.lane(id),car.n(id)) =1;
elseif empty_right_front>=empty && empty_right_back>=empty_safe && lanes( car.lane(id)+1,car.n(id) )==0 %旁边车道距离更大,右后,旁边均安全
%% 满足右换道安全条件换道
lanes(car.lane(id),car.n(id)) =0;
car.lane(id) = car.lane(id)+1;
lanes(car.lane(id),car.n(id)) =1;
end
else
%% 前车无影响则概率向左换道
if rand(1)<p_changelane
if empty_left_front>=empty && empty_left_back>=empty_safe && lanes( car.lane(id)-1,car.n(id) )==0 %旁边车道距离更大,左后,旁边均安全
%% 满足安全条件换道
lanes(car.lane(id),car.n(id)) =0;
car.lane(id) = car.lane(id)-1;
lanes(car.lane(id),car.n(id)) =1;
end
end
end
end
左侧车辆换道函数
function [lanes,car] = change_lane_left(lanes,car,id,v_max,lane_length,p_changelane,empty_safe)
%% 获取周边车距
[~,empty]=get_empty_front(id,car,v_max,lane_length,lanes);%获取前方车距
[empty_right_back,empty_right_front] = get_empty(car.lane(id)+1,car.n(id),v_max,lanes,lane_length);
if empty<min(car.v(id)+1,v_max)
%% 前车阻碍车辆对速度的追求
if empty_right_front>=empty && empty_right_back>=empty_safe && lanes( car.lane(id)+1,car.n(id) )==0 %旁边车道距离更大,右后,旁边均安全
%% 满足安全条件换道
lanes(car.lane(id),car.n(id)) =0;
car.lane(id) = car.lane(id)+1;
lanes(car.lane(id),car.n(id)) =1;
end
else
%% 前车无影响则概率换道
if rand(1)<p_changelane
if empty_right_front>=empty && empty_right_back>=empty_safe && lanes( car.lane(id)+1,car.n(id) )==0 %旁边车道距离更大,右后,旁边均安全
%% 满足安全条件换道
lanes(car.lane(id),car.n(id)) =0;
car.lane(id) = car.lane(id)+1;
lanes(car.lane(id),car.n(id)) =1;
end
end
end
end
换道函数
function [car,lanes] = change_lane(lanes,car,car_number,p_changelane,v_max,lane_length)
empty_safe = v_max; %安全车距
for id=1:car_number
if car.lane(id)==1||car.lane(id)==2||car.lane(id)==3||car.lane(id)==7||car.lane(id)==8||car.lane(id)==10||car.lane(id)==11||car.lane(id)==12
%% 自由换道区域:1,2,3,7,8,10,11,12
[cycle,~]=get_empty_front(id,car,v_max,lane_length,lanes);%判断是否驶出所在车道
if cycle %驶出车道车辆不允许换道
%% 非驶出所在车道车辆
if car.lane(id) == 1||car.lane(id) ==7||car.lane(id) ==10
%% 左侧车道换道
[lanes,car] = change_lane_left(lanes,car,id,v_max,lane_length,p_changelane,empty_safe);
elseif car.lane(id)==2||car.lane(id)==8||car.lane(id)==11
%% 中间车道换道
[lanes,car] = change_lane_middle(id,lanes,car,v_max,lane_length,p_changelane,empty_safe);
else
%% 右侧车道换道
[lanes,car] = change_lane_right(id,lanes,car,v_max,lane_length,p_changelane,empty_safe);
end
end
elseif car.lane(id)==4||car.lane(id)==5||car.lane(id)==6||car.lane(id)==9||car.lane(id)==15
%% 强制换道区域
switch car.lane(id)
%% 6,9车道直行车辆只能向左变道,出匝道车辆不变道
case 6
if car.state(id)==0%1是出匝道车辆,0是直行车辆
[lanes,car] = change_lane_right(id,lanes,car,v_max,lane_length,p_changelane,empty_safe);
end
case 9
if car.state(id)==0%1是出匝道车辆,0是直行车辆
[lanes,car] = change_lane_right(id,lanes,car,v_max,lane_length,p_changelane,empty_safe);
else
%% 9中出匝道车辆强制向15换道
[empty_right_back,empty_right_front] = get_empty(15,car.n(id),v_max,lanes,lane_length);
if empty_right_front>=1 && empty_right_back>=fix(v_max/2) && lanes(15,car.n(id))==0%15车道前方有距离且后方距离大于等于最大车速一半且旁边无车即可换道
%% 强制换道
lanes(9,car.n(id)) = 0;
car.lane(id) = 15;
lanes(9,car.n(id)) = 1;
end
end
case 4
if car.state(id)==0%1是出匝道车辆,0是直行车辆
%% 4车道直行车辆只能向右变道
[lanes,car] = change_lane_left(lanes,car,id,v_max,lane_length,p_changelane,empty_safe);
else
%% 强制向5换道
[empty_right_back,empty_right_front] = get_empty(5,car.n(id),v_max,lanes,lane_length);
if empty_right_front>=1 && empty_right_back>=fix(v_max/2) && lanes(5,car.n(id))==0%5车道前方有距离且后方距离大于等于最大车速一半且旁边无车即可换道
%% 强制换道
lanes(4,car.n(id)) = 0;
car.lane(id) = 5;
lanes(5,car.n(id)) = 1;
end
end
case 5
if car.state(id)==0
[lanes,car] = change_lane_middle(id,lanes,car,v_max,lane_length,p_changelane,empty_safe);
else
%% 强制向6换道
[empty_right_back,empty_right_front] = get_empty(6,car.n(id),v_max,lanes,lane_length);
if empty_right_front>=1 && empty_right_back>=fix(v_max/2) && lanes(6,car.n(id))==0%6车道前方有距离且后方距离大于等于最大车速一半且旁边无车即可换道
%% 强制换道
lanes(5,car.n(id)) = 0;
car.lane(id) = 6;
lanes(6,car.n(id)) = 1;
end
end
case 15
%% 15车道入匝道车辆强制向9换道,出匝道车辆不换道
if car.state(id)==0%此处0为入匝道车辆
[empty_right_back,empty_right_front] = get_empty(9,car.n(id),v_max,lanes,lane_length);
if empty_right_front>=1 && empty_right_back>=fix(v_max/2) && lanes(9,car.n(id))==0%9车道前方有距离且后方距离大于等于最大车速一半且旁边无车即可换道
%% 强制换道
lanes(15,car.n(id)) = 0;
car.lane(id) = 9;
lanes(9,car.n(id)) = 1;
end
end
end
end
end
end
目前缺点其实很多,只说几个,因为本人专业知识也很短缺。
1.没有设定车辆必须在到达某个位置前完成强制换道,同时,也没有考虑车辆无法完成强制换道的情况。
2.没有考虑混合车种,且只能模拟恒定密度情况的交通流。
3.强制换道规则合理性可能比较差,只参考了一篇论文中的强制换道规则,以及为了编程方便,先采取的强制换道规则是目标车道与前车距离大于等于一个元胞,与目标车道后车距离大于等于最大车速一半且目标车道旁边无车既可强制换道。
最后还是希望有小伙伴可以加我一起学习哈。