重發一下之前誤刪的一篇~
目前大多數元胞自動機模型并沒有考慮前車速度,大多數同向行駛的模型中車輛都是處在一個完全跟車的狀態,無論前車是加速還是減速,后車駕駛者都只是根據自己的車速判斷是減速跟馳還是變換車道來尋求尋求更合理的行駛狀態。顯然這與實際不符。
駕駛者是一個有自主意識的個體,每個個體都存在差異,即在駕駛過程中都有各自的偏好。對于不同駕駛員有不同的駕駛特性,駕駛員的駕駛特性是受其心理,生理,性格影響的及其復雜的駕駛行為偏好。對駕駛行為起到關鍵作用的有,反應時間,駕駛員對冒險駕駛行為的偏好,這兩點都是引起交通事故的重要因素。駕駛員反應時間越長越易與前車發生碰撞;駕駛員對冒險行為的偏好越高,在駕駛時約越易采取偏激行為,引發交通事故。但值得注意的是,部分駕駛員對冒險駕駛行為的偏好是出于自身性格因素,但也有很大部分駕駛員對冒險駕駛行為的偏好是出于自身駕駛技術較高,也就是駕駛技術較高的駕駛員采取偏激駕駛行為的概率大于新手駕駛員,這是符合常識的。
因此,本模型引入駕駛員反應時間,冒險偏好參數,以及考慮前車速度來使元胞自動機在快速路模型的模擬中更加接近現實。其中,近似認為一個駕駛員其反應時間與冒險偏好參數之和為1。也就是說,用駕駛員反應時間來粗略代表其駕駛技術水平,而認為隨著其駕駛水平提高,其對冒險駕駛行為的偏好相應增高。而對前車速度的考慮則通過定義駕駛需要空間和駕駛員預估空間來實現。其中,駕駛需要空間是指,車輛此時刻速度+車輛反應時間*車輛此時速度,即,車輛可以保持速度行為而不發生碰撞所需要的空間;駕駛員預估空間是指,車輛與前車距離+駕駛員冒險偏好參數*前車速度,即,駕駛員對未來車前距離的預估。
依據以上思路,對NaSch模型的加速規則進行更改:
當駕駛需要空間<駕駛員預估空間時,車輛進行減速,即,車輛速度在車輛現速度與駕駛員預估空間減去反應時間走過的距離之間取小。相應的,換道決策過程是,當車輛駕駛所需空間<駕駛員預估空間,而旁邊車道的駕駛員預估空間大于本車道時,將以概率換道,這里的概率換道也是模擬駕駛員特性,反應其對速度的追求。
綜上,考慮了反應時間后,后車對前方行駛空間要求相對NaSch模型變大,而考慮前車速度讓后車在加減速判斷時放大了車間距這個概念,而反應時間和駕駛員對前方空間的預估都和駕駛員特性有關,這和實際情況是符合的。而駕駛員對冒險偏好參數是初始化的時候就隨機生成不變的,代表不同駕駛員的不同性格,這與實際相符。而反應時間和冒險偏好參數之和為1,是方便編程之舉,但粗略來說,也是和實際大致符合的。
值得注意的是,本模型中依據采取先換道再跟馳的方法,而換道是有順序的,跟馳無順序,也就是說換道是一輛車換道結束之后,下一輛車再換道,這必然造成一輛車的換道行為將影響之后車輛的換道行為;而跟馳則不然,所有車輛執行完加減速及隨機慢化后,同時位置更新,即,所有車輛在一個時間步內行進時無影響。車輛換道對其他車輛換道,跟馳產生影響是符合實際情況的,而在一個時間步對應現實時間比較小的情況下,車輛跟馳行為間無影響也是符合現實的。
除此以外,本模型中頭車不受前車影響而減速,也不換道,這也是與實際相符的。
引入前車速度使本模型與NaSch有很大的區別,一是一個位置可能會出現兩輛車,所以在位置更新時要防止碰撞而多做一個判斷;另一個是一個時間步內可以有多輛車駛出車道。
最后,本模型車輛換道時沒有考慮目標車道后車影響,但實際換道時肯定受到與后車距離以及后車速度的綜合影響,但其影響明顯小于前車影響,而為了編程方便并沒有考慮。
貼代碼哈。
主函數
%% 考慮駕駛員特性和前車速度的單向3車道模型
clc;
clear;
%% 參數設置
lane_length = 100; %車道長度
car_rate = 0.1; %車輛占有率
v_max = 5; %最大車速
time_max = 1000; %仿真步長
time_span = 0.1; %仿真圖片輸出間隔
p_slowdown = 0.3; %隨機慢化概率
p_changelane = 0.8; %滿足換道條件換道概率%% 隨機生成初始車輛信息
[space,car,car_number] = initialize(car_rate,lane_length,v_max);%% 顯示初始仿真圖
figure('doublebuffer','on');%開啟雙緩存
space = -1*space;
H = imshow(space,[]);
title('考慮駕駛員特性及前車速度的單向3車道模型','color','red');
space = -1*space;%% 開始仿真
for time=1:time_max%% 換道階段[car,space] = change_lane(space,car,car_number,p_changelane,lane_length,v_max);%% 跟馳階段[space,car] = follow(space,car,v_max,lane_length,p_slowdown,car_number);%% 顯示仿真圖space = -1*space;set(H,'CData',space);pause(time_span);space = -1*space;
end
初始化函數
function [space,car,car_number] = initialize(car_rate,lane_length,v_max)
car_number = fix(1+(3*lane_length-1)*car_rate); %按車輛占有率算出的車輛數
%% 創建空間
space = zeros(3,lane_length);%元胞空間
car = struct('v',zeros(1,car_number),'m',zeros(1,car_number),'n',zeros(1,car_number),'r',zeros(1,car_number),'a',zeros(1,car_number));
% 車輛信息結構體從左到右為速度,車道,列,反應時間,駕駛員對冒險駕駛行為的偏好
%% 隨機生成初始車輛信息
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))==1car.n(id) = fix( 1+rand(1)*(lane_length-1) );endspace( 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))==1car.n(id) = fix( 1+rand(1)*(lane_length-1) );endspace( 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))==1car.n(id) = fix( 1+rand(1)*(lane_length-1) );endspace( 3,car.n(id) ) = 1;end%% 車速及駕駛員特性初始化car.v(id) = fix( 1+rand(1)*(v_max-1) ); %速度初始化car.r(id) = rand(1); %隨機生成駕駛員反應時間和對冒險駕駛行為的偏好參數,均為0到1間數字car.a(id) = 1-car.r(id);end
end
換道函數
function [car,space] = change_lane(space,car,car_number,p_changelane,lane_length,v_max)
%換道函數
for id=1:car_number[cycle,empty]=get_empty_front(car.m(id),car.n(id),lane_length,space);%獲取前方車距if cycle %頭車不換道v_front = car.v( logical( (car.n==(car.n(id) +empty+1)) .* (car.m==car.m(id)) ) );%獲取前車速度if car.m(id) == 1 %左側車道換道[cycle_right,empty_right_front] = get_empty_front(car.m(id)+1,car.n(id),lane_length,space);%獲取右側車道車距if cycle_rightv_front_right = car.v( logical( (car.n==(car.n(id) +empty_right_front+1)) .* (car.m==car.m(id)+1) ));%獲取右前車速度elsev_front_right = v_max;end%% 換道決策if empty+car.a(id)*v_front < car.v(id)*(1+car.r(id))%% 前車阻礙車輛對速度的追求if (v_front_right*car.a(id)+empty_right_front) > (empty+car.a(id)*v_front) && space( car.m(id)+1,car.n(id) )==0 %旁邊車道距離更大且旁邊無車%% 滿足安全條件換道if rand(1)<p_changelane %滿足換道條件以概率換道space(car.m(id),car.n(id)) =0;car.m(id) = car.m(id)+1;space(car.m(id),car.n(id)) =1;endendendelseif car.m(id) == 2 %中間車道換道[cycle_right,empty_right_front] = get_empty_front(car.m(id)+1,car.n(id),lane_length,space);%獲取右側車道車距[cycle_left,empty_left_front] = get_empty_front(car.m(id)-1,car.n(id),lane_length,space);%獲取左側車道車距%獲取右前車速度if cycle_rightv_front_right = car.v( logical( (car.n==(car.n(id) +empty_right_front+1)) .* (car.m==car.m(id)+1) ));elsev_front_right = v_max;end%獲取左前車速度if cycle_leftv_front_left = car.v( logical( (car.n==(car.n(id) +empty_left_front+1)) .* (car.m==car.m(id)-1) ));elsev_front_left = v_max;end%% 換道決策if empty+car.a(id)*v_front < car.v(id)*(1+car.r(id))%% 前車阻礙車輛對速度的追求%% 優先左換道if (v_front_left*car.a(id)+empty_left_front) > (empty+car.a(id)*v_front) && space( car.m(id)-1,car.n(id) )==0 %旁邊車道距離更大且旁邊無車%% 滿足安全條件換道if rand(1)<p_changelane %滿足換道條件以概率換道space(car.m(id),car.n(id)) =0;car.m(id) = car.m(id)-1;space(car.m(id),car.n(id)) =1;endelse%左換道條件不滿足則右換道if (v_front_right*car.a(id)+empty_right_front) > (empty+car.a(id)*v_front) && space( car.m(id)+1,car.n(id) )==0 %旁邊車道距離更大且旁邊無車%% 滿足安全條件換道if rand(1)<p_changelane %滿足換道條件以概率換道space(car.m(id),car.n(id)) =0;car.m(id) = car.m(id)+1;space(car.m(id),car.n(id)) =1;endendendendelse %右側車道換道[cycle_left,empty_left_front] = get_empty_front(car.m(id)-1,car.n(id),lane_length,space);%獲取左側車道車距if cycle_leftv_front_left = car.v( logical( (car.n==(car.n(id) +empty_left_front+1)) .* (car.m==car.m(id)-1) ));%獲取左前車速度elsev_front_left = v_max;end%% 換道決策if empty+car.a(id)*v_front < car.v(id)*(1+car.r(id))%% 前車阻礙車輛對速度的追求if (v_front_left*car.a(id)+empty_left_front) > (empty+car.a(id)*v_front) && space( car.m(id)-1,car.n(id) )==0 %旁邊車道距離更大且旁邊無車%% 滿足安全條件換道if rand(1)<p_changelane %滿足換道條件以概率換道space(car.m(id),car.n(id)) =0;car.m(id) = car.m(id)-1;space(car.m(id),car.n(id)) =1;endendendendend
end
跟馳函數
function [space,car] = follow(space,car,v_max,lane_length,p_slowdown,car_number)
%跟馳函數
cycle = zeros(1,car_number);%儲存車輛是否為頭車
for id = 1:car_number%% 加速car.v(id) = min(car.v(id)+1,v_max);%% 獲取車輛前空元胞數以及是否符合滿足周期循環[cycle(id),empty]=get_empty_front(car.m(id),car.n(id),lane_length,space);%% 減速if cycle %頭車不受前車影響而減速if cycle(id) %獲取前車速度v_front = car.v( logical( (car.n==(car.n(id) +empty+1)) .* (car.m==car.m(id)) ) );%獲取前車速度elsev_front = v_max;endcar.v(id) = min (car.v(id) , fix(empty+car.a(id)*v_front-car.v(id)*car.r(id)) );%車速不能超過駕駛員預估空間end%% 概率慢化if rand(1) <= p_slowdowncar.v(id) = max( car.v(id)-1,0 );end
end%% 位置更新e = 2;f = 2;g = 2;for id = 1:car_numberif car.n(id)+v_max >= lane_length %會駛出車道%% 周期邊界條件將頭車以原速度道路最左邊if cycle(id)==0 %頭車if car.n(id)+car.v(id)>lane_lengthspace ( car.m(id),car.n(id) ) = 0;car.n(id) = 1;space ( car.m(id),car.n(id) ) = 1;endelse %非頭車if car.n(id)+car.v(id)>lane_lengthspace ( car.m(id),car.n(id) ) = 0;switch car.m(id)case 1car.n(id) = e;e = e+1;case 2car.n(id) = f;f = f+1;case 3car.n(id) = g;g = g+1;endspace ( car.m(id),car.n(id) ) = 1;end endspace ( car.m(id),car.n(id) ) = 0;car.n(id) = car.n(id) +car.v(id);while space ( car.m(id),car.n(id) ) == 1car.n(id) = car.n(id) -1;endspace ( car.m(id),car.n(id) ) = 1;else %不可能駛出車道space ( car.m(id),car.n(id) ) = 0; car.n(id) = car.n(id) +car.v(id);while space ( car.m(id),car.n(id) ) == 1car.n(id) = car.n(id) -1;endspace ( car.m(id),car.n(id) ) = 1;endend
end
獲取前車距離及判斷是否頭車函數
%用于求m車道n列的前車距以及判斷是否為頭車,cycle值為0是頭車
function [cycle,empty_front] = get_empty_front(m,n,lane_length,space)
empty_front = 1;
cycle=1;
if n+1 < lane_length%求前車距while space(m,n+empty_front) == 0if n+empty_front<lane_lengthempty_front = empty_front+1;elsecycle = 0;empty_front = empty_front+1;break;endend empty_front = empty_front-1;
elseempty_front = 0;cycle = 0;
end
end
本來開專欄只是做個筆記,但陸續也有幾個小伙伴加我,和他們交流發現了之前發的幾個代碼的好幾處錯誤,所以希望看到代碼中的錯誤或是某部分代碼怎樣寫更好,希望大家能指點一二,十分感謝!
參考文獻
李杰;楊曉芳;付強.分析駕駛行為的快速路交通流元胞自動機模型[J].物流科技,2018,v.41;No.280,69-73.
本模型主要思路就是上面這篇文章,加上知乎的編輯器我不太會用,所以我就沒標引用的地方。公式編輯器編輯的公式也沒法復制,所以一直都是文字敘述。總之這次模型就是基于上面文章的思路改的,但我感覺這篇文章有前后矛盾的地方,可以交流哈。