fastsim_core/vehicle/powertrain/
transmission.rs1use 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 #[serde(default)]
10 pub(crate) mass: Option<si::Mass>,
11
12 pub eff_interp: InterpolatorEnumOwned<f64>,
15
16 pub save_interval: Option<usize>,
18 #[serde(default)]
20 pub state: TransmissionState,
21 #[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 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 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 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 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 {}