traffic_sim/vehicle/
acceleration.rs1use std::cell::Cell;
2
3use serde::{Deserialize, Serialize};
4
5const MIN_GAP: f64 = 2.5; const MAX_DECEL: f64 = -6.0; #[derive(Clone, Serialize, Deserialize, Debug)]
13pub struct AccelerationModel {
14    max_acc: f64,
15    comf_dec: f64,
16    acc: Cell<f64>,
17}
18
19pub struct ModelParams {
21    pub max_acceleration: f64,
23    pub comf_deceleration: f64,
25}
26
27impl AccelerationModel {
28    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    pub fn reset(&self) {
39        self.acc.set(self.max_acc);
40    }
41
42    pub fn acc(&self) -> f64 {
44        f64::max(self.acc.get(), MAX_DECEL)
45    }
46
47    pub fn emergency_stop(&self) {
49        self.acc.set(MAX_DECEL);
50    }
51
52    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; let d = 0.5 * (vel + max_vel) * t;
61            t + (dist - d) / max_vel
62        }
63    }
64
65    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    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    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    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    pub fn stopping_distance(&self, my_vel: f64) -> f64 {
117        let min_dist = 2.5; let t = my_vel / self.comf_dec;
119        0.5 * my_vel * t + min_dist
120    }
121
122    fn idm(&self, net_dist: f64, my_vel: f64, their_vel: f64) -> f64 {
124        let headway = 1.5; let comf_dec = self.comf_dec; let max_acc = self.max_acc; 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}