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: Interpolator,
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        state.eff.update(
31            match self.eff_interp {
32                Interpolator::Interp0D(eff) => eff * uc::R,
33                _ => unimplemented!(),
34            },
35            || format_dbg!(),
36        )?;
37        ensure!(
38            *state.eff.get_fresh(|| format_dbg!())? >= 0.0 * uc::R
39                && *state.eff.get_fresh(|| format_dbg!())? <= 1.0 * uc::R,
40            format!(
41                "{}\nTransmission efficiency ({}) must be between 0 and 1",
42                format_dbg!(
43                    *state.eff.get_fresh(|| format_dbg!())? >= 0.0 * uc::R
44                        && *state.eff.get_fresh(|| format_dbg!())? <= 1.0 * uc::R
45                ),
46                state.eff.get_fresh(|| format_dbg!())?.get::<si::ratio>()
47            )
48        );
49
50        state.pwr_out.update(pwr_out_req, || format_dbg!())?;
51        state.pwr_in.update(
52            if *state.pwr_out.get_fresh(|| format_dbg!())? > si::Power::ZERO {
53                *state.pwr_out.get_fresh(|| format_dbg!())?
54                    / *state.eff.get_fresh(|| format_dbg!())?
55            } else {
56                *state.pwr_out.get_fresh(|| format_dbg!())?
57                    * *state.eff.get_fresh(|| format_dbg!())?
58            },
59            || format_dbg!(),
60        )?;
61        state.pwr_loss.update(
62            (*state.pwr_in.get_fresh(|| format_dbg!())?
63                - *state.pwr_out.get_fresh(|| format_dbg!())?)
64            .abs(),
65            || format_dbg!(),
66        )?;
67
68        Ok(*state.pwr_in.get_fresh(|| format_dbg!())?)
69    }
70}
71impl HistoryMethods for Transmission {
72    fn save_interval(&self) -> anyhow::Result<Option<usize>> {
73        Ok(self.save_interval)
74    }
75    fn set_save_interval(&mut self, save_interval: Option<usize>) -> anyhow::Result<()> {
76        self.save_interval = save_interval;
77        Ok(())
78    }
79    fn clear(&mut self) {
80        self.history.clear()
81    }
82}
83impl SerdeAPI for Transmission {}
84impl Init for Transmission {}
85
86impl Mass for Transmission {
87    fn mass(&self) -> anyhow::Result<Option<si::Mass>> {
88        Ok(self.mass)
89    }
90
91    // TODO: the side effect doesn't really do anything, hmmm
92    fn set_mass(
93        &mut self,
94        new_mass: Option<si::Mass>,
95        _side_effect: MassSideEffect,
96    ) -> anyhow::Result<()> {
97        self.mass = new_mass;
98
99        Ok(())
100    }
101
102    // TODO this also doesn't really need to exist, except for the trait's sake
103    fn derived_mass(&self) -> anyhow::Result<Option<si::Mass>> {
104        Ok(self.mass)
105    }
106
107    fn expunge_mass_fields(&mut self) {
108        self.mass = None;
109    }
110}
111
112#[serde_api]
113#[derive(
114    Clone,
115    Default,
116    Debug,
117    Deserialize,
118    Serialize,
119    PartialEq,
120    HistoryVec,
121    StateMethods,
122    SetCumulative,
123)]
124#[non_exhaustive]
125#[serde(default)]
126#[serde(deny_unknown_fields)]
127pub struct TransmissionState {
128    /// time step index
129    pub i: TrackedState<usize>,
130
131    pub eff: TrackedState<si::Ratio>,
132
133    pub pwr_out: TrackedState<si::Power>,
134    pub pwr_in: TrackedState<si::Power>,
135    /// Power loss: [Self::pwr_in] - [Self::pwr_out]
136    pub pwr_loss: TrackedState<si::Power>,
137
138    pub energy_out: TrackedState<si::Energy>,
139    pub energy_loss: TrackedState<si::Energy>,
140}
141
142impl Init for TransmissionState {}
143impl SerdeAPI for TransmissionState {}