# Intelligent Driver Model (IDM)

## What Is IDM?

The **Intelligent Driver Model** is a microscopic car-following model developed by Martin Treiber, Ansgar Hennecke, and Dirk Helbing (2000). "Microscopic" means it models each vehicle individually rather than treating traffic as a fluid. It is one of the most widely used and studied car-following models because it is:

- **Simple** — one formula, five parameters per driver.
- **Realistic** — reproduces free flow, following, braking, stop-and-go waves, and capacity drop all from the same equation.
- **Collision-free** — with appropriate parameters, the model mathematically cannot produce a rear-end collision under any initial conditions (gap > 0, leader speed ≥ 0).

IDM defines the **acceleration** of a car as a function of its own speed, the gap to the car ahead, and the relative speed to that car. Everything else — speed, position, lane changes, signal compliance — flows from integrating that acceleration over time.

In this application, IDM controls longitudinal behavior (how fast and how close). MOBIL, documented separately in [mobil.md](mobil.md), handles lateral decisions (which lane).

---

## The Standard IDM Formula

```
a = a_max × ( 1  −  (v / v_max)⁴  −  (s* / s)² )
```

| Symbol | Meaning |
|---|---|
| `a` | Resulting acceleration [m/s²] (negative = braking) |
| `a_max` | Maximum comfortable acceleration [m/s²] |
| `v` | Current speed [m/s] |
| `v_max` | Desired free-road speed [m/s] |
| `s` | Bumper-to-bumper gap to the car ahead [m] |
| `s*` | Desired safety gap at current speed [m] (see below) |

### The Desired Safety Gap `s*`

```
s* = s₀  +  v·T  +  v·Δv / (2·√(a_max · b))
```

| Symbol | Meaning |
|---|---|
| `s₀` | Minimum standstill gap [m] |
| `T` | Desired time headway [s] |
| `Δv` | Approach rate: `v_self − v_leader` (positive when closing) |
| `b` | Comfortable deceleration [m/s²] |

`s*` has three components:

1. **`s₀`** — a physical minimum gap even when stopped (bumper clearance).
2. **`v·T`** — a speed-proportional gap: the faster the car, the larger the buffer it wants. At 30 m/s with `T = 1.5 s`, this alone is 45 m.
3. **`v·Δv / (2√(ab))`** — a braking term. When closing on a slower leader (`Δv > 0`), this adds extra buffer to ensure there is enough distance to decelerate smoothly. When the leader is faster (`Δv < 0`, pulling away), this term is negative — the car can follow more closely because the gap will grow naturally.

### Understanding the Three Regimes

**Free road (`s → ∞`):**
`(s*/s)² → 0`. The equation reduces to `a = a_max × (1 − (v/v_max)⁴)`. The car accelerates toward `v_max`, slowing the push as it approaches. At `v = v_max`, the term equals 1 and acceleration reaches zero.

**Car following (`s ≈ s*`):**
The two terms roughly cancel. Acceleration is small; the car maintains a stable following gap. Small disturbances are damped — if the gap shrinks, the braking term increases; if the gap grows, the free-road term re-accelerates.

**Braking (`s < s*`):**
`(s*/s)²` exceeds 1, producing a net deceleration. The harder the overshoot (gap much smaller than desired), the stronger the braking. The model is designed so that if the gap is never zero initially, it stays positive.

### The Exponent 4

The free-road term uses the 4th power of `v/v_max`. Higher exponents make the cutoff sharper — the car accelerates near-freely at low speeds and then quickly plateaus near `v_max`. The exponent 4 is the standard IDM value; lower exponents would produce a gentler, more linear deceleration curve as the car approaches `v_max`.

---

## This Application's Extension: Intersection Braking

The original IDM only models car-following on an open road. This application adds a **third term** to the formula to make cars respect traffic signals at stop lines:

```
a = a_max × ( 1  −  freeRoadCoeff  −  busyRoadCoeff  −  intersectionCoeff )
```

The first two coefficients are the standard IDM terms. The third is new:

```
safeIntersectionDistance = 1 + v·T + v² / (2·b)
intersectionCoeff        = ( safeIntersectionDistance / distanceToStopLine )²
```

| Symbol | Meaning |
|---|---|
| `v·T` | Speed-proportional buffer (same as in `s*`) |
| `v²/(2·b)` | Kinematic stopping distance at current speed under deceleration `b` |
| `1` | Minimum 1 m baseline buffer at the stop line |
| `distanceToStopLine` | Distance from car's front bumper to the stop line |

The structure mirrors the car-following term: when `distanceToStopLine ≫ safeIntersectionDistance`, the coefficient approaches zero and the intersection has no effect. As the car approaches a red light, `distanceToStopLine` shrinks, the coefficient grows, and the car decelerates smoothly to a stop at the line.

### The `Infinity` Sentinel

`Trajectory.distanceToStopLine` returns `Infinity` in two situations where braking should be suppressed:

1. **Green light** — `canEnterIntersection()` returns `true`. The car has permission; no braking needed.
2. **Mid-crossing** — the car has already committed to crossing (its `next._lane` is on a different road than `current._lane`). Re-applying braking once the car has entered the intersection would cause it to stop inside the box.

When `distanceToStopLine = Infinity`, `intersectionCoeff = (x/∞)² = 0`. The term vanishes, and the car accelerates normally.

When the signal is red and the car is approaching, `distanceToStopLine` is the actual bumper-to-stopline distance:
```
distance = currentLane.length  −  car.length/2  −  current.position
```
Clamped to `Math.max(distance, 0)` so it never goes negative (prevents reverse braking behavior if the car has slightly overshot).

### A Previously Fixed Bug

Adjacent same-road lane changes (MOBIL moves, turn-lane repositioning) once incorrectly suppressed the stop-line braking term by reusing the `isChangingLanes` flag. The fix: `distanceToStopLine` only returns `Infinity` when the car is crossing to a _different road_, not merely changing lanes on the same road.

---

## Implementation: `Car.getAcceleration()`

Location: [js/model/Car.js](js/model/Car.js)

```javascript
getAcceleration() {
    const { car: aheadCar, distance } = this.trajectory.nextCarDistance;
    const s = Math.max(distance, 0);
    const v = this.speed;
    const a = this.maxAcceleration;
    const b = this.maxDeceleration;

    const deltaSpeed        = v - (aheadCar ? aheadCar.speed : 0);
    const freeRoadCoeff     = (v / this.maxSpeed) ** 4;

    const timeGap           = v * this.timeHeadway;
    const breakGap          = v * deltaSpeed / (2 * Math.sqrt(a * b));
    const safeDistance      = this.s0 + timeGap + breakGap;
    const busyRoadCoeff     = (safeDistance / Math.max(s, 0.1)) ** 2;

    const safeIntersectionDistance = 1 + timeGap + v * v / (2 * b);
    const intersectionCoeff        = (safeIntersectionDistance / this.trajectory.distanceToStopLine) ** 2;

    return a * (1 - freeRoadCoeff - busyRoadCoeff - intersectionCoeff);
}
```

**Notes on the implementation:**

- **`Math.max(distance, 0)`** — `nextCarDistance` should never be negative (rear of leader is always ahead of front of follower), but this guard prevents accidental negative inputs from producing incorrect results during edge-case startup conditions.

- **`Math.max(s, 0.1)`** — prevents division by zero when two cars are extremely close. At `s = 0.1 m`, `busyRoadCoeff` is already enormous, producing strong emergency braking.

- **`deltaSpeed = v − 0`** when there is no leader — the car behaves as if it is following a ghost car at infinite distance going its own speed. `Δv = 0` collapses `breakGap` to zero, and `(safeDistance / ∞)² = 0` collapses `busyRoadCoeff` to zero. Only `freeRoadCoeff` remains.

- The result is unclamped — it can be strongly negative during emergency braking. The `speed` setter then clamps speed to `[0, maxSpeed]` so the car cannot go negative or exceed its design speed.

---

## Pure IDM Variant: `Car.getAccelerationGiven()`

Location: [js/model/Car.js](js/model/Car.js)

```javascript
getAccelerationGiven(speed, gap, leaderSpeed) {
    ...
    return a * (1 - freeRoadCoeff - busyRoadCoeff);
    // No intersectionCoeff — caller provides explicit scenario inputs
}
```

This variant accepts all three inputs explicitly and omits the intersection braking term. It exists specifically for **MOBIL** ([mobil.md](mobil.md)), which needs to evaluate hypothetical "what would my acceleration be in that lane?" scenarios. Using the real `getAcceleration()` would be wrong for two reasons:

1. It reads live simulation state (the actual ahead car, the actual stop-line distance) rather than the hypothetical scenario.
2. The intersection term would distort the comparison — a car 10 m from a red light would compute very different accelerations in the two lanes even if neither lane has a leader, purely due to stop-line braking.

---

## Car Physical Parameters

All parameters are set per car in the `Car` constructor. They are currently uniform across the population (except where noted).

| Parameter | Value | Meaning |
|---|---|---|
| `width` | `1.7 m` | Vehicle width (fixed) |
| `length` | `3 + 2 × random()` | Vehicle length, sampled from 3–5 m (uniform) |
| `maxSpeed` | `30 m/s` (90%) or `60 m/s` (10%) | Desired free-road speed — see Bimodal Speeds below |
| `s0` | `2 m` | Minimum standstill gap |
| `timeHeadway` | `1.5 s` | Desired time headway |
| `maxAcceleration` | `1 m/s²` | Maximum comfortable acceleration |
| `maxDeceleration` | `3 m/s²` | Comfortable (not emergency) braking limit |

`maxDeceleration` is called "comfortable" because IDM uses it in computing `s*`, not as a hard cap on braking. When the car is very close to a leader or stop line, the computed `a` can go far more negative than `−3 m/s²`. The speed setter clamps at zero, so the car stops rather than reversing, but a physically realistic model would cap at something like `−9 m/s²` for tyres-locked emergency braking.

### Bimodal Speed Distribution

90% of cars get `maxSpeed = 30 m/s` (~108 km/h). 10% get `maxSpeed = 60 m/s` (~216 km/h). These fast cars are rendered black to make them visually distinguishable.

This creates two distinct driver populations:

- **Standard cars** form platoons, queue at red lights, and cruise comfortably.
- **Fast cars** accelerate aggressively (they spend more time far below their `v_max`), weave through slower traffic more readily (their higher IDM-desired gap at any given speed makes them more sensitive to obstructions), and arrive at red lights at higher speeds requiring longer deceleration zones.

There are no intermediate speed tiers. Three or more tiers would produce richer heterogeneous traffic, but the bimodal setup already captures the most visible effect (slow bulk + rare aggressive outliers).

---

## Numerical Integration

Each tick, `Car.move(delta)` computes:

```javascript
const acceleration = this.getAcceleration();
this.speed += acceleration * delta;                                    // Euler speed update
const step = this.speed * delta + 0.5 * acceleration * delta * delta; // kinematic position step
```

The position step uses the **kinematic formula** `s = v·Δt + ½·a·Δt²` rather than a pure Euler step `s = v·Δt`. This is more accurate for constant-acceleration intervals and avoids the slight position underestimation that pure Euler produces.

`World.onTick()` caps `delta` at 1 second to prevent physics explosions if a very large time step is passed (e.g., after a tab switch or long pause). `Visualizer.draw()` independently caps the wall-clock delta at 100 ms before scaling by `timeFactor`. At the maximum `timeFactor = 10`, the maximum simulation step per frame is therefore `10 × 0.1 = 1.0 s`, exactly at the World cap.

At the default `timeFactor = 5`, the typical frame step is `5 × 0.033 ≈ 0.165 simulation seconds` at 30 fps. IDM is smooth and stable at this resolution.

---

## Emergent Traffic Behaviors

Because every car independently solves the same IDM equation, realistic collective behaviors emerge without being explicitly programmed.

### Free-Flow Platoons

Cars travelling at similar speeds on an open road naturally form loosely-spaced platoons. The gap between them settles at `v·T = v × 1.5 s`. At 30 m/s, platoon gaps are ~45 m.

### Traffic Jams at Red Lights

As cars queue at a red light, each one brakes to maintain `s*` behind the car ahead. The queue grows backward one car at a time. When the light turns green, cars depart sequentially — the second car cannot move until the first has created a gap of `s* ≈ s₀ + v·T`, producing the familiar "accordion" departure that anyone who has waited at traffic lights recognises.

### Stop-and-Go Waves

If a section of road is congested enough that the outflow is less than the inflow, a backward-propagating density wave forms. Cars in the wave repeatedly decelerate to near-zero, then re-accelerate. IDM reproduces this naturally. The wave travels upstream at roughly −15 km/h (typical for real motorway jams), though the exact propagation speed depends on the simulation parameters.

### Capacity Drop

When traffic density exceeds a critical level, average speed drops sharply and throughput falls below the theoretical maximum. IDM shows this transition clearly: at moderate densities, cars maintain good following gaps and flow efficiently; at high densities, the braking term dominates, speeds drop, and the system tips into the congested regime.

---

## Quirks and Edge Cases

### No Hard Collision Detection

IDM's guarantee of collision-free behavior only holds with realistic parameters and moderate time steps. At very high `timeFactor` values (approaching the cap of 10×), the Euler speed update can cause a car to briefly penetrate another car's rear before braking corrects it. There is no explicit collision geometry — cars can visually overlap without triggering any special handling. This is a known limitation documented in [CLAUDE.md](CLAUDE.md).

### Negative `breakGap`

When the leader is faster than the follower (`Δv < 0`), `breakGap = v·Δv / (2√(ab)) < 0`. This correctly reduces `s*` — the car can safely follow more closely since the gap is widening. However, if `Δv` is large enough (very fast leader), `safeDistance = s₀ + timeGap + breakGap` could theoretically go negative. `Math.max(s, 0.1)` in the denominator prevents a divide-by-zero, but the physics interpretation becomes slightly wrong (the car thinks it can be closer than `s₀` because the leader is pulling away quickly). In practice this is harmless because the leader's departure causes the gap to grow naturally.

### The `0.1 m` Floor

`busyRoadCoeff = (safeDistance / Math.max(s, 0.1))²`. The `0.1 m` floor means that even at zero gap, `busyRoadCoeff` is finite (though very large). This prevents a NaN from propagating through the simulation and ensures the car always gets a valid (very negative) acceleration when extremely close to a leader.

### Speed Clamping at Zero

The `speed` setter clamps to `[0, maxSpeed]`. IDM can produce accelerations of `−100 m/s²` or more when a car is right on top of another car or a stop line. With delta integration, `speed += a * delta` could go strongly negative. The clamp ensures the car stops rather than reversing. A real simulator might instead propagate the impulse, but zero-clamping is simpler and sufficient here since the road network has no reversing behavior.

### `aheadCar.speed` Not `aheadCar._speed`

The `deltaSpeed` computation uses `aheadCar.speed` (the getter), which reads `_speed` after clamping. This is intentional — it ensures the follower reacts to the leader's actual displayed speed, not any intermediate pre-clamped value.

---

## Interaction with the Trajectory System

IDM in this application does not directly read positions — it asks the `Trajectory` object for:

- **`nextCarDistance`** — returns `{ car, distance }`: the nearest registered car ahead (from the `LanePosition` registry), along with the bumper-to-bumper gap. This comes from the minimum of the `current` and `next` LanePosition slots, so a car in the final phase of a crossing considers followers in its destination lane already.

- **`distanceToStopLine`** — the Infinity-or-real sentinel described above.

This separation keeps the physics pure: `getAcceleration()` knows nothing about lanes, roads, or intersections directly. All spatial context is mediated by `Trajectory`.

---

## Limitations

### One-Dimensional Following Only

IDM models following along a single axis (position along a lane). It has no concept of lateral offset — two cars in different lanes at the same position are completely invisible to each other's IDM term. Lane safety is handled by MOBIL's safety gate, not IDM.

### No Look-Ahead Beyond One Car

The standard IDM only looks at the immediately preceding car. Multi-anticipation extensions (looking at the car two or three ahead) are not implemented. This means a platoon at a red light decelerates in a backward cascade rather than as a coordinated group. Each car brakes only when the gap to the car directly ahead shrinks.

### Uniform Parameters Within Each Speed Tier

All standard cars share identical `s₀`, `T`, `a_max`, and `b`. Real drivers vary substantially on all of these. Adding per-car randomness to at least `T` (timeHeadway) would create richer traffic with naturally variable following gaps and more realistic lane-change opportunities for MOBIL.

### No Reaction Time

Real drivers have a perception-reaction delay of 0.5–1.5 s. IDM in this application responds instantaneously to the current gap. Adding a reaction-time delay (computing `a` based on gap from `τ` seconds ago) would produce slightly more realistic braking waves, particularly the tendency for jams to amplify rather than damp small perturbations.

### No Emergency Braking Cap

The model imposes no hard upper limit on deceleration magnitude. At very small gaps, computed braking can far exceed what a real vehicle is physically capable of (typically −9 to −12 m/s² for an emergency stop). This is generally harmless in the simulation but means the car never "crashes" in the way a real car would.

---

## Possible Future Enhancements

### Per-Car Parameter Variation

Randomise `timeHeadway` (`T`) per car, e.g. uniformly from 1.0 s to 2.5 s. Aggressive drivers (`T = 1.0 s`) tailgate and create denser platoons; cautious drivers (`T = 2.5 s`) leave large gaps that invite lane-changing. This single change would substantially enrich traffic diversity without changing the IDM formula.

```javascript
this.timeHeadway = 1.0 + 1.5 * Math.random();   // 1.0–2.5 s range
```

### Reaction Time Delay

Store a ring buffer of recent `(gap, leaderSpeed)` observations and evaluate IDM on the state from `τ = 0.8 s` ago rather than the current state. This makes jams amplify more realistically and produces the characteristic "shockwave" backward propagation.

### Multi-Anticipation

Extend `getAcceleration()` to consider the two cars ahead, weighted by `1/n`:

```
a = a_IDM(leader_1)  +  (1/2) × correction_term(leader_2)
```

This dampens stop-and-go waves — drivers who can see further ahead brake earlier and more gently.

### Speed-Dependent Vehicle Length

Long vehicles (trucks, buses) occupy more road space and require longer following distances. A third size class with `length = 10–15 m` and lower `maxSpeed = 20 m/s` would model heavy vehicles. Combined with IDM, these naturally create "rolling roadblocks" that cause real bunching behavior behind them.

### Graduated Deceleration Cap

Cap the computed acceleration at a physically plausible minimum, e.g. `−12 m/s²`, before integrating. This would make very-close encounters visible as partial overlaps or "bumps" rather than instantaneous recovery, and would allow the simulation to model the aftermath of a collision rather than silently resolving it.

### IDM Calibration Interface

Expose `s₀`, `T`, `a_max`, and `b` as sliders in the control panel (similar to the existing `timeFactor` slider). This would let users explore different traffic regimes interactively — e.g., set `T = 0.5 s` to simulate tailgating culture, or `T = 3 s` to simulate cautious freeway driving — and observe how IDM parameters affect jam formation, capacity, and lane-change frequency.

---

## Reference

Treiber, M., Hennecke, A., & Helbing, D. (2000). _Congested traffic states in empirical observations and microscopic simulations_. Physical Review E, 62(2), 1805–1824.

Further reading and interactive demonstrations are available at Martin Treiber's traffic simulation site: [http://www.traffic-simulation.de](http://www.traffic-simulation.de)

The IDM paper is one of the most cited works in traffic science and is freely available through most academic search engines.
