fastsim_core/vehicle/powertrain/
transmission.rs

1use super::*;
2
3#[serde_api]
4#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, StateMethods, SetCumulative)]
5#[non_exhaustive]
6#[serde(deny_unknown_fields)]
7pub struct Transmission {
8    /// Transmission mass
9    #[serde(default)]
10    pub(crate) mass: Option<si::Mass>,
11
12    /// interpolator for calculating [Self] efficiency as a function of the following variants:  
13    /// - 0d -- constant
14    pub eff_interp: InterpolatorEnumOwned<f64>,
15
16    /// time step interval between saves. 1 is a good option. If None, no saving occurs.
17    pub save_interval: Option<usize>,
18    /// struct for tracking current state
19    #[serde(default)]
20    pub state: TransmissionState,
21    /// Custom vector of [Self::state]
22    #[serde(default, skip_serializing_if = "TransmissionStateHistoryVec::is_empty")]
23    pub history: TransmissionStateHistoryVec,
24}
25
26impl Transmission {
27    pub fn get_pwr_in_req(&mut self, pwr_out_req: si::Power) -> anyhow::Result<si::Power> {
28        let state = &mut self.state;
29
30        let eff_pt: &[f64] = match self.eff_interp {
31            InterpolatorEnum::Interp0D(_) => &[],
32            _ => unimplemented!("Only Interp0D is currently implemented"),
33        };
34        state.eff.update(
35            self.eff_interp.interpolate(eff_pt)? * uc::R,
36            || format_dbg!(),
37        )?;
38        ensure!(
39            *state.eff.get_fresh(|| format_dbg!())? >= 0.0 * uc::R
40                && *state.eff.get_fresh(|| format_dbg!())? <= 1.0 * uc::R,
41            format!(
42                "{}\nTransmission efficiency ({}) must be between 0 and 1",
43                format_dbg!(
44                    *state.eff.get_fresh(|| format_dbg!())? >= 0.0 * uc::R
45                        && *state.eff.get_fresh(|| format_dbg!())? <= 1.0 * uc::R
46                ),
47                state.eff.get_fresh(|| format_dbg!())?.get::<si::ratio>()
48            )
49        );
50
51        state.pwr_out.update(pwr_out_req, || format_dbg!())?;
52        state.pwr_in.update(
53            if *state.pwr_out.get_fresh(|| format_dbg!())? > si::Power::ZERO {
54                *state.pwr_out.get_fresh(|| format_dbg!())?
55                    / *state.eff.get_fresh(|| format_dbg!())?
56            } else {
57                *state.pwr_out.get_fresh(|| format_dbg!())?
58                    * *state.eff.get_fresh(|| format_dbg!())?
59            },
60            || format_dbg!(),
61        )?;
62        state.pwr_loss.update(
63            (*state.pwr_in.get_fresh(|| format_dbg!())?
64                - *state.pwr_out.get_fresh(|| format_dbg!())?)
65            .abs(),
66            || format_dbg!(),
67        )?;
68
69        Ok(*state.pwr_in.get_fresh(|| format_dbg!())?)
70    }
71}
72impl HistoryMethods for Transmission {
73    fn save_interval(&self) -> anyhow::Result<Option<usize>> {
74        Ok(self.save_interval)
75    }
76    fn set_save_interval(&mut self, save_interval: Option<usize>) -> anyhow::Result<()> {
77        self.save_interval = save_interval;
78        Ok(())
79    }
80    fn clear(&mut self) {
81        self.history.clear()
82    }
83}
84impl SerdeAPI for Transmission {}
85impl Init for Transmission {}
86
87impl Mass for Transmission {
88    fn mass(&self) -> anyhow::Result<Option<si::Mass>> {
89        Ok(self.mass)
90    }
91
92    // TODO: the side effect doesn't really do anything, hmmm
93    fn set_mass(
94        &mut self,
95        new_mass: Option<si::Mass>,
96        _side_effect: MassSideEffect,
97    ) -> anyhow::Result<()> {
98        self.mass = new_mass;
99
100        Ok(())
101    }
102
103    // TODO this also doesn't really need to exist, except for the trait's sake
104    fn derived_mass(&self) -> anyhow::Result<Option<si::Mass>> {
105        Ok(self.mass)
106    }
107
108    fn expunge_mass_fields(&mut self) {
109        self.mass = None;
110    }
111}
112
113#[serde_api]
114#[derive(
115    Clone,
116    Default,
117    Debug,
118    Deserialize,
119    Serialize,
120    PartialEq,
121    HistoryVec,
122    StateMethods,
123    SetCumulative,
124)]
125#[non_exhaustive]
126#[serde(default)]
127#[serde(deny_unknown_fields)]
128pub struct TransmissionState {
129    /// time step index
130    pub i: TrackedState<usize>,
131
132    pub eff: TrackedState<si::Ratio>,
133
134    pub pwr_out: TrackedState<si::Power>,
135    pub pwr_in: TrackedState<si::Power>,
136    /// Power loss: [Self::pwr_in] - [Self::pwr_out]
137    pub pwr_loss: TrackedState<si::Power>,
138
139    pub energy_out: TrackedState<si::Energy>,
140    pub energy_loss: TrackedState<si::Energy>,
141}
142
143impl Init for TransmissionState {}
144impl SerdeAPI for TransmissionState {}