為什麼高速公路會無故塞車?用 JavaScript 模擬交通流體力學

2026年1月14日 · wemee (with AI assistant)

simulation physics traffic idm javascript
為什麼高速公路會無故塞車?用 JavaScript 模擬交通流體力學

前言

在高速公路開車時,我常常在想:我能不能保持車速穩定?

譬如前車減速了,但我其實不必急著跟著煞車——因為在我逼近到危險距離之前,他可能就已經加速離開了。又譬如塞車時,前車起步衝刺,但我也不必猛踩油門追上去——反正他待會又會因為前方壅塞而停下來。

這種「不急著反應」的駕駛方式,其實就是交通工程中所謂的「交通波吸收」。

於是我做了一個環形軌道的車流模擬,想親眼看看:一個佛系駕駛如何默默改善交通?

基礎模型:IDM 智慧駕駛模型

首先需要一個「跟車模型」來決定每輛車的加速度。我選擇了 IDM(Intelligent Driver Model),這是德國物理學家 Treiber 在 2000 年提出的模型,至今仍被廣泛使用。

IDM 核心公式

a=amax[1(vv0)4(s(v,Δv)s)2]a = a_{max} \left[ 1 - \left(\frac{v}{v_0}\right)^4 - \left(\frac{s^*(v, \Delta v)}{s}\right)^2 \right]

其中:

參數設計

不同類型的駕駛有不同的參數:

參數正常車擾動者吸收者
安全時距1.5 秒1.0 秒2.5 秒
最大加速度1.0 m/s²1.5 m/s²0.6 m/s²
舒適減速度1.5 m/s²2.5 m/s²1.0 m/s²
最小車距0.08 rad0.05 rad0.12 rad

吸收者的特點是:保持較大的跟車距離,加減速都比較溫和。這讓他能「吸收」前方傳來的速度波動,不會放大傳給後方。

第一版的問題:太機械化

實作完基本的 IDM 模型後,模擬跑起來了,但看起來很假——所有車輛的行為都太一致、太平滑。

真實的交通中,駕駛人會:

  1. 偶爾分心減速:看手機、調冷氣、發呆
  2. 反應有延遲:前車動作後,需要時間才會反應

改進一:Nagel-Schreckenberg 隨機減速

這是來自 1992 年的經典元胞自動機模型。核心概念很簡單:每個時間步,車輛有一定機率隨機減速

// 隨機減速(Nagel-Schreckenberg 風格)
if (vehicle.velocity > 0.01 && Math.random() < vehicle.randomSlowdownProb * dt * 10) {
  const randomDecel = vehicle.comfortDecel * (0.5 + Math.random());
  vehicle.acceleration -= randomDecel;
}

不同駕駛類型的隨機減速機率:

這個小改動讓車流瞬間變得自然許多。你會看到偶爾有車「莫名減速」,然後這個減速波向後傳播——這就是幽靈塞車的起源。

改進二:反應時間延遲

真實駕駛不會瞬間反應前車的動作。要模擬這點,需要:

  1. 記錄前車歷史狀態
interface Vehicle {
  // ... 其他屬性
  reactionTime: number;  // 反應時間(秒)
  leaderHistory: { gap: number; velocity: number; time: number }[];
}
  1. 對「過去」的資訊反應
private getDelayedLeaderState(vehicle: Vehicle, leader: Vehicle) {
  const targetTime = this.simulationTime - vehicle.reactionTime;

  // 找到最接近目標時間的歷史記錄
  for (let i = vehicle.leaderHistory.length - 1; i >= 0; i--) {
    if (vehicle.leaderHistory[i].time <= targetTime) {
      return vehicle.leaderHistory[i];
    }
  }
  // 如果沒有足夠的歷史,使用當前狀態
  return { gap: this.getGap(vehicle, leader), velocity: leader.velocity };
}

反應時間的設定:

個體差異

每輛車的參數還會加入 ±20% 的隨機變異,讓同類型的車也有個性差異:

randomSlowdownProb: params.randomSlowdownProb * (0.8 + Math.random() * 0.4),
reactionTime: params.reactionTime * (0.8 + Math.random() * 0.4),

幽靈塞車的形成

加入這些改進後,你會在模擬中清楚看到:

  1. 某輛車隨機減速(可能是分心)
  2. 後車延遲反應,等到距離很近才煞車
  3. 後車需要更大幅度的減速來維持安全距離
  4. 減速波向後傳播,逐漸放大
  5. 最後面的車完全停止,即使最初只是輕微減速

這就是「幽靈塞車」(Phantom Traffic Jam)——明明沒有事故、沒有施工,就是莫名其妙塞住了。

吸收者的作用

調高吸收者比例後,觀察「速度波動(標準差)」指標會下降。

吸收者為什麼有效?

  1. 較大的跟車距離:有更多緩衝空間,不需要急煞
  2. 較緩的加減速:不會放大速度波動
  3. 較長的反應時間:聽起來是壞事,但配合大車距,反而讓行為更平滑

研究顯示,只需約 5% 的車輛採用吸收策略,就能顯著改善整體交通流量。

調校心得

參數敏感度

碰撞處理

由於有反應延遲,車輛可能會「撞上」前車。需要加入軟碰撞處理:

const softGap = 0.06;    // 開始減速的距離
const minSafeGap = 0.03; // 最小安全車距

if (gap < softGap && vehicle.velocity > leader.velocity) {
  // 接近中:漸進減速
  const urgency = 1 - (gap - minSafeGap) / (softGap - minSafeGap);
  vehicle.velocity = Math.max(leader.velocity, targetVelocity);
}

參考資料

這個模擬的理論基礎來自:

  1. IDM 模型traffic-simulation.de
  2. Nagel-Schreckenberg 模型Wikipedia
  3. 交通流體力學綜述arXiv:2104.02583

結語

這個專案讓我深刻體會到:複雜的巨觀行為可以從簡單的微觀規則湧現

每輛車只遵守簡單的跟車規則,但當幾十輛車一起模擬,就會自然產生塞車波、幽靈堵塞等現象。而只要有少數「佛系駕駛」,就能顯著改善整體流量。

下次開高速公路時,也許可以試試看當個吸收者?


工具連結交通流體力學模擬