traffic_sim/vehicle/
acceleration.rs

1use std::cell::Cell;
2
3use serde::{Deserialize, Serialize};
4
5/// The minimum gap to maintain between vehicles in m.
6const MIN_GAP: f64 = 2.5; // m
7
8/// The maximum deceleration of all vehicles in m/s^2.
9const MAX_DECEL: f64 = -6.0; // m/s^2
10
11/// The acceleration model of a vehicle.
12#[derive(Clone, Serialize, Deserialize, Debug)]
13pub struct AccelerationModel {
14    max_acc: f64,
15    comf_dec: f64,
16    acc: Cell<f64>,
17}
18
19/// The parameters of the acceleration model.
20pub struct ModelParams {
21    /// The vehicle's maximum acceleration in m/s<sup>2</sup>.
22    pub max_acceleration: f64,
23    /// The comfortable decelleration in m/s<sup>2</sup>.
24    pub comf_deceleration: f64,
25}
26
27impl AccelerationModel {
28    /// Creates a new acceleration model.
29    pub fn new(params: &ModelParams) -> Self {
30        AccelerationModel {
31            max_acc: params.max_acceleration,
32            comf_dec: params.comf_deceleration,
33            acc: Cell::new(params.max_acceleration),
34        }
35    }
36
37    /// Resets the acceleration model. Use at the start of an update.
38    pub fn reset(&self) {
39        self.acc.set(self.max_acc);
40    }
41
42    /// Gets the current acceleration of the vehicle.
43    pub fn acc(&self) -> f64 {
44        f64::max(self.acc.get(), MAX_DECEL)
45    }
46
47    /// Applies the maximum deceleration to the vehicle.
48    pub fn emergency_stop(&self) {
49        self.acc.set(MAX_DECEL);
50    }
51
52    /// Calculates the time it would take the vehicle to reach the given `pos`
53    /// if it maximally accelerated.
54    pub fn min_reach_time(&self, vel: f64, dist: f64, max_vel: f64) -> f64 {
55        let discr = 2.0 * self.max_acc * dist + vel.powi(2);
56        if discr < max_vel.powi(2) {
57            (discr.sqrt() - vel) / self.max_acc
58        } else {
59            let t = (max_vel - vel) / self.max_acc; // 5
60            let d = 0.5 * (vel + max_vel) * t;
61            t + (dist - d) / max_vel
62        }
63    }
64
65    /// Calculates the acceleration needed to maintain the speed limit.
66    /// # Arguments
67    /// * `vel` - The velocity of the simulated vehicle (m/s).
68    /// * `speed_limit` - The current speed limit (m/s).
69    pub fn apply_current_speed_limit(&self, vel: f64, speed_limit: f64) {
70        let max_acc = self.max_acc;
71        let this_acc = max_acc * (1. - (vel / speed_limit).powi(4));
72        self.acc.set(f64::min(self.acc.get(), this_acc));
73    }
74
75    /// Calculates the acceleration needed to comfortably decelerate to
76    /// the speed limit of the next link.
77    /// # Arguments
78    /// * `vel` - The velocity of the simulated vehicle (m/s).
79    /// * `speed_limit` - The current speed limit (m/s).
80    /// * `distance` - The distance to the next link (m).
81    pub fn apply_speed_limit(&self, vel: f64, speed_limit: f64, distance: f64) {
82        if distance <= 0.0 {
83            return self.apply_current_speed_limit(vel, speed_limit);
84        }
85
86        let comf_acc = -self.comf_dec;
87        let this_acc = (speed_limit.powi(2) - vel.powi(2)) / (2. * distance);
88        if this_acc <= comf_acc {
89            let this_acc = f64::max(2.0 * comf_acc, this_acc);
90            self.acc.set(f64::min(self.acc.get(), this_acc));
91        }
92    }
93
94    /// Calculates the acceleration needed to stop before a stop line.
95    ///
96    /// # Arguments
97    /// * `net_dist` - The distance between this vehicle and the stop line.
98    /// * `my_vel` - The velocity of the simulated vehicle (m/s).
99    pub fn stop_at_line(&self, net_dist: f64, my_vel: f64) {
100        let acc = self.idm(net_dist, my_vel, 0.0);
101        self.acc.set(f64::min(self.acc.get(), acc));
102    }
103
104    /// Calculates the acceleration needed to follow the vehicle ahead.
105    ///
106    /// # Arguments
107    /// * `net_dist` - The distance between this vehicle and the vehicle ahead in metres.
108    /// * `my_vel` - The velocity of the simulated vehicle (m/s).
109    /// * `their_vel` - The vehicle ahead's velocity (m/s).
110    pub fn follow_vehicle(&self, net_dist: f64, my_vel: f64, their_vel: f64) {
111        let acc = self.idm(net_dist, my_vel, their_vel);
112        self.acc.set(f64::min(self.acc.get(), acc));
113    }
114
115    /// Calculates the comfortable break distance of the vehicle.
116    pub fn stopping_distance(&self, my_vel: f64) -> f64 {
117        let min_dist = 2.5; // m
118        let t = my_vel / self.comf_dec;
119        0.5 * my_vel * t + min_dist
120    }
121
122    /// Computes an acceleration using the intelligent driver model.
123    fn idm(&self, net_dist: f64, my_vel: f64, their_vel: f64) -> f64 {
124        let headway = 1.5; // s
125        let comf_dec = self.comf_dec; // m.s^-2
126        let max_acc = self.max_acc; // m.s^-2
127
128        if net_dist <= MIN_GAP {
129            -10. * max_acc
130        } else {
131            let appr = my_vel - their_vel;
132            let factor = 1. / (2. * (max_acc * comf_dec).sqrt());
133            let ss = MIN_GAP + (my_vel * headway) + (my_vel * appr * factor);
134            let term = ss / net_dist;
135            max_acc * (1. - (term * term))
136        }
137    }
138}
139
140#[cfg(test)]
141mod test {
142    use super::*;
143    use assert_approx_eq::assert_approx_eq;
144
145    #[test]
146    fn min_reach_time() {
147        let acc = AccelerationModel::new(&ModelParams {
148            max_acceleration: 2.0,
149            comf_deceleration: 2.0,
150        });
151
152        assert_approx_eq!(acc.min_reach_time(0.0, 25.0, 50.0), 5.0);
153        assert_approx_eq!(acc.min_reach_time(0.0, 25.0, 10.0), 5.0);
154        assert_approx_eq!(acc.min_reach_time(0.0, 25.0, 9.0), 5.027777777777);
155
156        assert_approx_eq!(acc.min_reach_time(5.0, 50.0, 50.0), 5.0);
157        assert_approx_eq!(acc.min_reach_time(5.0, 50.0, 15.0), 5.0);
158        assert_approx_eq!(acc.min_reach_time(5.0, 50.0, 14.0), 5.01785714285);
159    }
160}