Skip to content

Commit

Permalink
HEV engine now has temperature-sensitive on/off controls
Browse files Browse the repository at this point in the history
all thermal models are hypothetically correctly implemented!
  • Loading branch information
calbaker committed Dec 23, 2024
1 parent 8cd096e commit b1520ec
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 8 deletions.
53 changes: 45 additions & 8 deletions fastsim-core/src/vehicle/hev.rs
Original file line number Diff line number Diff line change
Expand Up @@ -509,15 +509,46 @@ impl HEVPowertrainControls {
em_state.pwr_mech_fwd_out_max.get::<si::kilowatt>(),
fc_state.pwr_prop_max.get::<si::kilowatt>()
);

// positive net power out of the powertrain
let (fc_pwr, em_pwr) = match self {
HEVPowertrainControls::RGWDB(ref mut rgwb) => {
HEVPowertrainControls::RGWDB(ref mut rgwdb) => {
match (
fc.temperature(),
fc.temp_prev(),
rgwdb.temp_fc_forced_on,
rgwdb.temp_fc_allowed_off,
) {
(None, None, None, None) => {}
(
Some(temperature),
Some(temp_prev),
Some(temp_fc_forced_on),
Some(temp_fc_allowed_off),
) => {
if
// temperature is currently below forced on threshold
temperature < temp_fc_forced_on ||
// temperature was below forced on threshold and still has not exceeded allowed off threshold
(temp_prev < temp_fc_forced_on && temperature < temp_fc_allowed_off)
{
hev_state.fc_on_causes.push(FCOnCause::FCTemperatureTooLow);
}
}
_ => {
bail!(
"{}\n`fc.temperature()`, `fc.temp_prev()`, `rgwdb.temp_fc_forced_on`, and
`rgwdb.temp_fc_allowed_off` must all be `None` or `Some`",
format_dbg!()
);
}
}
// cannot exceed ElectricMachine max output power. Excess demand will be handled by `fc`
let em_pwr = pwr_out_req.min(em_state.pwr_mech_fwd_out_max);
let frac_pwr_demand_fc_forced_on: si::Ratio = rgwb
let frac_pwr_demand_fc_forced_on: si::Ratio = rgwdb
.frac_pwr_demand_fc_forced_on
.with_context(|| format_dbg!())?;
let frac_of_most_eff_pwr_to_run_fc: si::Ratio = rgwb
let frac_of_most_eff_pwr_to_run_fc: si::Ratio = rgwdb
.frac_of_most_eff_pwr_to_run_fc
.with_context(|| format_dbg!())?;
// If the motor cannot produce more than the required power times a
Expand All @@ -532,27 +563,27 @@ impl HEVPowertrainControls {
}

if veh_state.speed_ach
> rgwb.speed_fc_forced_on.with_context(|| format_dbg!())?
> rgwdb.speed_fc_forced_on.with_context(|| format_dbg!())?
{
hev_state.fc_on_causes.push(FCOnCause::VehicleSpeedTooHigh);
}

rgwb.state.soc_fc_on_buffer = {
rgwdb.state.soc_fc_on_buffer = {
let energy_delta_to_buffer_speed = 0.5
* veh_state.mass
* (rgwb
* (rgwdb
.speed_soc_fc_on_buffer
.with_context(|| format_dbg!())?
.powi(typenum::P2::new())
- veh_state.speed_ach.powi(typenum::P2::new()));
energy_delta_to_buffer_speed.max(si::Energy::ZERO)
* rgwb
* rgwdb
.speed_soc_fc_on_buffer_coeff
.with_context(|| format_dbg!())?
} / res.energy_capacity_usable()
+ res.min_soc;

if res.state.soc < rgwb.state.soc_fc_on_buffer {
if res.state.soc < rgwdb.state.soc_fc_on_buffer {
hev_state.fc_on_causes.push(FCOnCause::ChargingForLowSOC)
}
if pwr_out_req - em_state.pwr_mech_fwd_out_max >= si::Power::ZERO {
Expand Down Expand Up @@ -639,6 +670,12 @@ pub struct RESGreedyWithDynamicBuffers {
/// Fraction of available discharging capacity to use toward running the
/// engine efficiently.
pub frac_res_dschrg_for_fc: si::Ratio,
/// temperature at which engine is forced on to warm up
#[serde(default, skip_serializing_if = "Option::is_none")]
pub temp_fc_forced_on: Option<si::Temperature>,
/// temperature at which engine is allowed to turn off due to being sufficiently warm
#[serde(default, skip_serializing_if = "Option::is_none")]
pub temp_fc_allowed_off: Option<si::Temperature>,
/// current state of control variables
#[serde(default, skip_serializing_if = "EqDefault::eq_default")]
pub state: RGWDBState,
Expand Down
13 changes: 13 additions & 0 deletions fastsim-core/src/vehicle/powertrain/fuel_converter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,15 @@ impl FuelConverter {
FuelConverterThermalOption::None => None,
}
}

/// If thermal model is appropriately configured, returns previous time step
/// lumped [Self] temperature
pub fn temp_prev(&self) -> Option<si::Temperature> {
match &self.thrml {
FuelConverterThermalOption::FuelConverterThermal(fct) => Some(fct.state.temp_prev),
FuelConverterThermalOption::None => None,
}
}
}

// impl FuelConverter {
Expand Down Expand Up @@ -614,6 +623,7 @@ impl FuelConverterThermal {
- self.state.heat_to_amb)
* dt)
/ self.heat_capacitance;
self.state.temp_prev = self.state.temperature;
self.state.temperature += delta_temp;

self.state.eff_coeff = match self.fc_eff_model {
Expand Down Expand Up @@ -675,6 +685,8 @@ pub struct FuelConverterThermalState {
pub te_adiabatic: si::Temperature,
/// Current engine thermal mass temperature (lumped engine block and coolant)
pub temperature: si::Temperature,
/// Engine thermal mass temperature (lumped engine block and coolant) at previous time step
pub temp_prev: si::Temperature,
/// Current heat transfer coefficient from [FuelConverter] to ambient
pub htc_to_amb: si::HeatTransferCoeff,
/// Current heat transfer to ambient
Expand All @@ -691,6 +703,7 @@ impl Default for FuelConverterThermalState {
i: Default::default(),
te_adiabatic: *TE_ADIABATIC_STD,
temperature: *TE_STD_AIR,
temp_prev: *TE_STD_AIR,
htc_to_amb: Default::default(),
heat_to_amb: Default::default(),
eff_coeff: uc::R,
Expand Down
2 changes: 2 additions & 0 deletions fastsim-core/src/vehicle/vehicle_model/fastsim2_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,8 @@ impl TryFrom<&fastsim_2::vehicle::RustVehicle> for PowertrainType {
// TODO: make sure these actually do something, if deemed worthwhile
frac_res_chrg_for_fc: f2veh.ess_chg_to_fc_max_eff_perc * uc::R,
frac_res_dschrg_for_fc: f2veh.ess_dischg_to_fc_max_eff_perc * uc::R,
temp_fc_forced_on: None,
temp_fc_allowed_off: None,
state: Default::default(),
history: Default::default(),
}));
Expand Down

0 comments on commit b1520ec

Please sign in to comment.