Skip to content

Intelligent driver

The intelligent driver system of cars on a ring road.

  • Class: IntelligentDriverSystem
  • Import: from skcomplex.systems.engineering.traffic import IntelligentDriverSystem
  • Field: engineering/traffic
  • Topics: traffic, jams, ode, car following
  • References: Treiber, Hennecke, and Helbing 2000; Chowdhury, Santen, and Schadschneider 2000

Use this system

from skcomplex.core.engine.runtime import simulate
from skcomplex.systems.engineering.traffic import IntelligentDriverSystem

trajectory = simulate(IntelligentDriverSystem())

Parameters

Parameter Default
n_cars 20
length 500.0
v0 30.0
T 1.5
a 1.0
b 1.5
s0 2.0
delta 4.0
car_length 5.0
perturbation 1.0

Tags

Tag Values
Time continuous
Space none
Laws rate
Randomness deterministic
Domains real
Structure fixed

Class

class IntelligentDriverSystem(BaseSystem):
    """The intelligent driver system 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. The system has the group `cars`
    of positions `cars.x` and speeds `cars.v`, car `i + 1` ahead of car `i`.

    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.

        label:
            The label of the system, which names it when it is nested in another one.

    Examples:
        >>> from skcomplex.systems.engineering.traffic import IntelligentDriverSystem
        >>> IntelligentDriverSystem(n_cars=4).prepare().system_.interactions[0].road_length
        500.0
    """

    field = 'engineering/traffic'
    topics = ('traffic', 'jams', 'ode', 'car following')
    references = ('Treiber, Hennecke, and Helbing 2000', 'Chowdhury, Santen, and Schadschneider 2000')
    until = 100.0
    dt = 1.0

    def __init__(
        self,
        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,
        label: str = 'system',
    ) -> None:
        super().__init__(label)
        self.n_cars = n_cars
        self.length = length
        self.v0 = v0
        self.T = T
        self.a = a
        self.b = b
        self.s0 = s0
        self.delta = delta
        self.car_length = car_length
        self.perturbation = perturbation

    def _build_system(self) -> System:
        """Return the parts of the system built from its model parameters."""
        cars = GroupElement(
            'cars',
            element=CarElement,
            size=self.n_cars,
            values={'x': _ring_positions(self.n_cars, self.length, self.perturbation), 'v': 0.0},
        )
        following = IntelligentDriverInteraction(
            'follow',
            target='cars',
            v0=self.v0,
            T=self.T,
            a=self.a,
            b=self.b,
            s0=self.s0,
            delta=self.delta,
            length=self.car_length,
            road_length=self.length,
        )
        return System(self.label, elements=[cars], interactions=[following])

Components

Elements:

  • CarElement, from Element

Interactions:

  • IntelligentDriverInteraction, from RateInteraction
class CarElement(Element):
    """Car on a road whose position `x` advances at its speed `v`."""

    law_classes = (RateLaw,)

    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 system.

    The acceleration depends on 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 system."""
        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)