Skip to content

Commit

Permalink
added enum to differentiate between possible battery efficiency inter…
Browse files Browse the repository at this point in the history
…p inputs
  • Loading branch information
calbaker committed Jan 22, 2025
1 parent dcc8cb2 commit 32602fd
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 16 deletions.
4 changes: 2 additions & 2 deletions fastsim-core/fastsim-proc-macros/src/fastsim_api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ fn add_serde_methods(py_impl_block: &mut TokenStream2) {
#[pyo3(signature = (msg_pack, skip_init=None))]
pub fn from_msg_pack_py(msg_pack: &Bound<PyBytes>, skip_init: Option<bool>) -> PyResult<Self> {
Self::from_msg_pack(
msg_pack.as_bytes(),
msg_pack.as_bytes(),
skip_init.unwrap_or_default()
).map_err(|e| PyIOError::new_err(format!("{:?}", e)))
}
Expand Down Expand Up @@ -343,7 +343,7 @@ fn process_named_field_struct(
format!("{self:?}")
}
});

// struct with named fields
for field in named.iter_mut() {
impl_getters_and_setters(field);
Expand Down
1 change: 1 addition & 0 deletions fastsim-core/resources/vehicles/2016_TOYOTA_Prius_Two.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pt_type:
energy_capacity_joules: 2700000.0
eff_interp:
Interp0D: 0.9848857801796105
eff_interp_inputs: Constant
min_soc: 0.25
max_soc: 0.95
save_interval: 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pt_type:
energy_capacity_joules: 196776000.0
eff_interp:
Interp0D: 0.9848857801796105
eff_interp_inputs: Constant
min_soc: 0.029
max_soc: 0.98
save_interval: 1
Expand Down
57 changes: 43 additions & 14 deletions fastsim-core/src/vehicle/powertrain/reversible_energy_storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,12 @@ pub struct ReversibleEnergyStorage {
/// Total energy capacity of battery of full discharge SOC of 0.0 and 1.0
pub energy_capacity: si::Energy,

/// interpolator for calculating [Self] efficiency as a function of the following variants:
/// - 0d -- constant -- handled on a round trip basis
/// - 1d -- linear w.r.t. power
/// - 2d -- linear w.r.t. power and SOC
/// - 3d -- linear w.r.t. power, SOC, and temperature
/// interpolator for calculating [Self] efficiency
pub eff_interp: Interpolator,

/// what state variables to use in calculating efficiency
pub eff_interp_inputs: RESEffInterpInputs,

/// Hard limit on minimum SOC, e.g. 0.05
pub min_soc: si::Ratio,
/// Hard limit on maximum SOC, e.g. 0.95
Expand Down Expand Up @@ -203,27 +202,37 @@ impl ReversibleEnergyStorage {
)
);
}
state.eff = match &self.eff_interp {
Interpolator::Interp0D(eff) => *eff * uc::R,
Interpolator::Interp1D(interp1d) => {
interp1d.interpolate(&[state.pwr_out_electrical.get::<si::watt>()])? * uc::R
state.eff = match (&self.eff_interp, &self.eff_interp_inputs) {
(Interpolator::Interp0D(eff), RESEffInterpInputs::Constant) => *eff * uc::R,
(Interpolator::Interp1D(interp1d) , RESEffInterpInputs::CRate)=> {
interp1d.interpolate(&[state.pwr_out_electrical.get::<si::watt>()
/ self.energy_capacity.get::<si::watt_hour>()])? * uc::R
}
Interpolator::Interp2D(interp2d) => {
(Interpolator::Interp2D(interp2d) , RESEffInterpInputs::CRateSOC)=> {
interp2d.interpolate(&[
state.pwr_out_electrical.get::<si::watt>(),
state.pwr_out_electrical.get::<si::watt>()
/ self.energy_capacity.get::<si::watt_hour>(),
state.soc.get::<si::ratio>(),
])? * uc::R
}
Interpolator::Interp3D(interp3d) => {
(Interpolator::Interp2D(interp2d) , RESEffInterpInputs::CRateTemperature)=> {
interp2d.interpolate(&[
state.pwr_out_electrical.get::<si::watt>()
/ self.energy_capacity.get::<si::watt_hour>(),
te_res.with_context(|| format_dbg!("Expected thermal model to be configured."))?.get::<si::degree_celsius>(),
])? * uc::R
}
(Interpolator::Interp3D(interp3d), RESEffInterpInputs::CRateSOCTemperature )=> {
interp3d.interpolate(&[
state.pwr_out_electrical.get::<si::watt>(),
state.pwr_out_electrical.get::<si::watt>()
/ self.energy_capacity.get::<si::watt_hour>(),
state.soc.get::<si::ratio>(),
te_res
.with_context(|| format_dbg!("Expected thermal model to be configured"))?
.get::<si::degree_celsius>(),
])? * uc::R
}
_ => bail!("Invalid interpolator. See docs for `ReversibleEnergyStorage::eff_interp`"),
_ => bail!("Invalid or not yet enabled interpolator config. See docs for `ReversibleEnergyStorage::eff_interp` an `ReversibleEnergyStorage::eff_interp_inputs`"),
};
ensure!(
state.eff >= 0.0 * uc::R && state.eff <= 1.0 * uc::R,
Expand Down Expand Up @@ -460,6 +469,7 @@ impl ReversibleEnergyStorage {
/// °C corresponds to `eta_interp_values[0][5]` in ALTRIOS
#[cfg(all(feature = "yaml", feature = "resources"))]
pub fn set_default_pwr_interp(&mut self) -> anyhow::Result<()> {
self.eff_interp_inputs = RESEffInterpInputs::CRate;
self.eff_interp = ninterp::Interpolator::from_resource("res/default_pwr.yaml", false)?;
Ok(())
}
Expand All @@ -477,6 +487,7 @@ impl ReversibleEnergyStorage {
/// ALTRIOS, the outermost layer is SOC and innermost is power)
#[cfg(all(feature = "yaml", feature = "resources"))]
pub fn set_default_pwr_and_soc_interp(&mut self) -> anyhow::Result<()> {
self.eff_interp_inputs = RESEffInterpInputs::CRateSOC;
self.eff_interp =
ninterp::Interpolator::from_resource("res/default_pwr_and_soc.yaml", false)?;
Ok(())
Expand All @@ -486,6 +497,7 @@ impl ReversibleEnergyStorage {
/// constant 50% SOC
#[cfg(all(feature = "yaml", feature = "resources"))]
pub fn set_default_pwr_and_temp_interp(&mut self) -> anyhow::Result<()> {
self.eff_interp_inputs = RESEffInterpInputs::CRateTemperature;
self.eff_interp =
ninterp::Interpolator::from_resource("res/default_pwr_and_temp.yaml", false)?;
Ok(())
Expand All @@ -506,6 +518,7 @@ impl ReversibleEnergyStorage {
/// ALTRIOS, the outermost layer is temperature and innermost is power)
#[cfg(all(feature = "yaml", feature = "resources"))]
pub fn set_default_pwr_soc_and_temp_interp(&mut self) -> anyhow::Result<()> {
self.eff_interp_inputs = RESEffInterpInputs::CRateSOCTemperature;
self.eff_interp =
ninterp::Interpolator::from_resource("res/default_pwr_soc_and_temp.yaml", false)?;
Ok(())
Expand Down Expand Up @@ -908,3 +921,19 @@ impl Default for RESLumpedThermalState {
}
}
}

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, IsVariant, From, TryInto)]
/// Determines what [ReversibleEnergyStorage] state variables to use in calculating efficiency
pub enum RESEffInterpInputs {
/// Efficiency is constant
Constant,
/// Efficiency = f(C-rate)
CRate,
/// Efficiency = f(C-rate, temperature)
CRateSOCTemperature,
/// Efficiency = f(C-rate, soc, temperature)
CRateTemperature,
/// Efficiency = f(C-rate, soc)
CRateSOC,
// TODO: finish adding possible variants
}
4 changes: 4 additions & 0 deletions fastsim-core/src/vehicle/vehicle_model/fastsim2_interface.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use powertrain::reversible_energy_storage::RESEffInterpInputs;

use super::*;

impl TryFrom<fastsim_2::vehicle::RustVehicle> for Vehicle {
Expand Down Expand Up @@ -168,6 +170,7 @@ impl TryFrom<&fastsim_2::vehicle::RustVehicle> for PowertrainType {
pwr_out_max: f2veh.ess_max_kw * uc::KW,
energy_capacity: f2veh.ess_max_kwh * uc::KWH,
eff_interp: Interpolator::Interp0D(f2veh.ess_round_trip_eff.sqrt()),
eff_interp_inputs: RESEffInterpInputs::Constant,
min_soc: f2veh.min_soc * uc::R,
max_soc: f2veh.max_soc * uc::R,
save_interval: Some(1),
Expand Down Expand Up @@ -218,6 +221,7 @@ impl TryFrom<&fastsim_2::vehicle::RustVehicle> for PowertrainType {
pwr_out_max: f2veh.ess_max_kw * uc::KW,
energy_capacity: f2veh.ess_max_kwh * uc::KWH,
eff_interp: Interpolator::Interp0D(f2veh.ess_round_trip_eff.sqrt()),
eff_interp_inputs: RESEffInterpInputs::Constant,
min_soc: f2veh.min_soc * uc::R,
max_soc: f2veh.max_soc * uc::R,
save_interval: Some(1),
Expand Down

0 comments on commit 32602fd

Please sign in to comment.