Intelligent driver model
The intelligent driver model of cars on a ring road.
- Name:
intelligent_driver_model - Field:
engineering/traffic - Formalism: ordinary differential equations
- References: Treiber, Hennecke, and Helbing 2000; Chowdhury, Santen, and Schadschneider 2000
Factory
@register_model(
field='engineering/traffic',
tags=('traffic', 'jams', 'ode', 'car following'),
references=('Treiber, Hennecke, and Helbing 2000', 'Chowdhury, Santen, and Schadschneider 2000'),
defaults={'until': 100.0, 'dt': 1.0},
)
def intelligent_driver_model(
n_cars: int = 20,
length: float = 500.0,
*,
v0: float = 30.0,
T: float = 1.5,
a: float = 1.0,
b: float = 1.5,
s0: float = 2.0,
delta: float = 4.0,
car_length: float = 5.0,
perturbation: float = 1.0,
) -> System:
"""Return the intelligent driver model of cars on a ring road.
Car `i` accelerates as `v' = a (1 - (v / v0)^δ - (s* / s)^2)` with the gap `s` to the car ahead and the desired
gap `s* = s0 + v T + v Δv / (2 sqrt(a b))`, where `Δv` is the speed difference to the car ahead. Cars start at rest.
The cars are one group, and the car ahead of car `i` is member `i + 1` along the ring.
Args:
n_cars:
The number of cars.
length:
The length of the ring road.
v0:
The desired speed.
T:
The safe time headway.
a:
The largest acceleration.
b:
The comfortable deceleration.
s0:
The jam distance.
delta:
The acceleration exponent.
car_length:
The length of a car, subtracted from the headway to give the gap.
perturbation:
The forward shift of the first car from uniform spacing.
Returns:
system:
The model, with the group `cars` of positions `cars.x` and speeds `cars.v`, car `i + 1` ahead of car `i`.
Examples:
>>> from skcomplex.models.engineering.traffic import intelligent_driver_model
>>> intelligent_driver_model(n_cars=4).interactions[0].road_length
500.0
"""
cars = GroupElement(
'cars',
element=CarElement,
size=n_cars,
values={'x': _ring_positions(n_cars, length, perturbation), 'v': 0.0},
)
following = IntelligentDriverInteraction(
'follow',
target='cars',
v0=v0,
T=T,
a=a,
b=b,
s0=s0,
delta=delta,
length=car_length,
road_length=length,
)
return System(elements=[cars], interactions=[following])
Components
class CarElement(Element):
"""Car on a road whose position `x` advances at its speed `v`."""
def __init__(
self,
label: str,
visual: VisualSpec | None = None,
*,
x: Annotated[object, StateSpec(role='position')] = 0.0,
v: Annotated[object, StateSpec(role='velocity')] = 0.0,
) -> None:
super().__init__(label, visual=visual)
self.x = x
self.v = v
def _get_laws(self, s: SimpleNamespace) -> list[BaseLaw]:
"""Return the advance of the position at the speed."""
return [RateLaw(s.x, s.v)]
class IntelligentDriverInteraction(RateInteraction):
"""Acceleration of every car of a ring road by the intelligent driver model of its speed and the car ahead.
The speed follows `v' = a (1 - (v / v0)^δ - (s*(v, Δv) / (h - l))^2)`, with the desired gap
`s* = s0 + v T + v Δv / (2 sqrt(a b))`, the approach rate `Δv` to the next car, and the headway `h` less the car
length `l`.
Args:
label:
The label of the interaction.
target:
The path of the group of cars, in the order they drive.
v0:
The desired speed.
T:
The safe time headway.
a:
The largest acceleration.
b:
The comfortable deceleration.
s0:
The jam distance.
delta:
The acceleration exponent.
length:
The length of a car.
road_length:
The length of the ring road.
"""
def __init__(
self,
label: str,
*,
target: Annotated[str, RoleSpec()],
v0: Annotated[object, ParameterSpec(domain=RealSet.open(0, oo))] = 30.0,
T: Annotated[object, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 1.5,
a: Annotated[object, ParameterSpec(domain=RealSet.open(0, oo))] = 1.0,
b: Annotated[object, ParameterSpec(domain=RealSet.open(0, oo))] = 1.5,
s0: Annotated[object, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 2.0,
delta: Annotated[object, ParameterSpec(domain=RealSet.open(0, oo))] = 4.0,
length: Annotated[object, ParameterSpec(domain=RealSet.closed_open(0, oo))] = 5.0,
road_length: Annotated[object, ParameterSpec(domain=RealSet.open(0, oo))] = 500.0,
) -> None:
super().__init__(label, target=target, state='v')
self.v0 = v0
self.T = T
self.a = a
self.b = b
self.s0 = s0
self.delta = delta
self.length = length
self.road_length = road_length
def _get_rate(self, namespace: SimpleNamespace) -> object:
"""Return the acceleration of the intelligent driver model."""
s, cars = namespace, namespace.target
gap = s.s0 + cars.v * s.T + cars.v * (cars.v - shift_member(cars.v, 1)) / (2 * sqrt(s.a * s.b))
return s.a * (
1
- (cars.v / s.v0) ** s.delta
- (gap / (OptimalVelocityInteraction._headway(cars.x, s.road_length) - s.length)) ** 2
)
Equations
cars.x[i]: diff(x_cars(t), t) == v_cars(t)
cars.v[i]: diff(v_cars(t), t) == -1/4*a_follow*(4*(v_cars(t)/v0_follow)^delta_follow + (2*T_follow*v_cars(t) - (v_cars__shift0 - v_cars(t))*v_cars(t)/sqrt(a_follow*b_follow) + 2*s0_follow)^2/(length_follow - mod(x_cars__shift1 - x_cars(t), road_length_follow))^2 - 4)