diff --git a/fastsim-core/src/vehicle/bev.rs b/fastsim-core/src/vehicle/bev.rs index 8323c1a1..7912db8a 100644 --- a/fastsim-core/src/vehicle/bev.rs +++ b/fastsim-core/src/vehicle/bev.rs @@ -176,11 +176,12 @@ impl Powertrain for BatteryElectricVehicle { Ok(()) } + /// Regen braking power, positive means braking is happening fn pwr_regen(&self) -> si::Power { // When `pwr_mech_prop_out` is negative, regen is happening. First, clip it at 0, and then negate it. // see https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e8f7af5a6e436dd1163fa3c70931d18d // for example - -self.em.state.pwr_mech_prop_out.min(si::Power::ZERO) + -(self.em.state.pwr_mech_prop_out.max(si::Power::ZERO)) } } diff --git a/fastsim-core/src/vehicle/hev.rs b/fastsim-core/src/vehicle/hev.rs index 4b37ff3f..9f31305e 100644 --- a/fastsim-core/src/vehicle/hev.rs +++ b/fastsim-core/src/vehicle/hev.rs @@ -207,11 +207,12 @@ impl Powertrain for Box { Ok(()) } + /// Regen braking power, positive means braking is happening fn pwr_regen(&self) -> si::Power { // When `pwr_mech_prop_out` is negative, regen is happening. First, clip it at 0, and then negate it. // see https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e8f7af5a6e436dd1163fa3c70931d18d // for example - -self.em.state.pwr_mech_prop_out.min(0. * uc::W) + -(self.em.state.pwr_mech_prop_out.max(si::Power::ZERO)) } } @@ -616,11 +617,8 @@ impl HEVPowertrainControls { .min(em_state.pwr_mech_fwd_out_max) .max(-em_state.pwr_mech_regen_max); // tractive power handled by fc - let (fc_pwr_corrected, em_pwr_corrected): (si::Power, si::Power) = if hev_state - .fc_on_causes - .is_empty() - { - // engine is off + if hev_state.fc_on_causes.is_empty() { + // engine is off, and `em_pwr` has already been limited within bounds (si::Power::ZERO, em_pwr) } else { // engine has been forced on @@ -631,7 +629,9 @@ impl HEVPowertrainControls { // negative tractive power // max power system can receive from engine during negative traction (em_state.pwr_mech_regen_max + pwr_prop_req) + // or peak efficiency power if it's lower than above .min(fc.pwr_for_peak_eff * frac_of_pwr_for_peak_eff) + // but not negative .max(si::Power::ZERO) } else { // positive tractive power @@ -645,7 +645,8 @@ impl HEVPowertrainControls { // fc handles all power not covered by em (pwr_prop_req - em_pwr) // and if that's less than the - // efficiency-focused value, then operate at that value + // efficiency-focused value, then operate at + // that value .max(fc.pwr_for_peak_eff * frac_of_pwr_for_peak_eff) // but don't exceed what what the battery can // absorb + tractive demand @@ -656,15 +657,10 @@ impl HEVPowertrainControls { .min(fc_state.pwr_prop_max); // recalculate `em_pwr` based on `fc_pwr` - let em_pwr_corrected = pwr_prop_req - fc_pwr; + let em_pwr_corrected = + (pwr_prop_req - fc_pwr).max(-em_state.pwr_mech_regen_max); (fc_pwr, em_pwr_corrected) - }; - - ensure!( - fc_pwr_corrected >= si::Power::ZERO, - format_dbg!(fc_pwr_corrected >= si::Power::ZERO) - ); - (fc_pwr_corrected, em_pwr_corrected) + } } Self::Placeholder => todo!(), }; diff --git a/fastsim-core/src/vehicle/powertrain/electric_machine.rs b/fastsim-core/src/vehicle/powertrain/electric_machine.rs index b81e7da6..123d50da 100755 --- a/fastsim-core/src/vehicle/powertrain/electric_machine.rs +++ b/fastsim-core/src/vehicle/powertrain/electric_machine.rs @@ -223,15 +223,17 @@ impl ElectricMachine { (pwr_out_req - self.state.pwr_mech_fwd_out_max).get::().format_eng(Some(6)) ), ); - ensure!( - almost_le_uom(&pwr_out_req.abs(), &self.state.pwr_mech_regen_max, None), - format!( - "{}\nedrv charge power ({:.6} kW) exceeds current max charge power ({:.6} kW)", - format_dbg!(pwr_out_req.abs() <= self.state.pwr_mech_regen_max), - pwr_out_req.get::(), - self.state.pwr_mech_regen_max.get::() - ), - ); + if pwr_out_req < si::Power::ZERO { + ensure!( + almost_le_uom(&pwr_out_req.abs(), &self.state.pwr_mech_regen_max, None), + format!( + "{}\nedrv charge power ({:.6} kW) exceeds current max charge power ({:.6} kW)", + format_dbg!(), + -pwr_out_req.get::(), + self.state.pwr_mech_regen_max.get::() + ), + ); + } self.state.pwr_out_req = pwr_out_req; diff --git a/python/fastsim/demos/demo_hev_thrml.py b/python/fastsim/demos/demo_hev_thrml.py index 7f034670..e6e1ad6d 100644 --- a/python/fastsim/demos/demo_hev_thrml.py +++ b/python/fastsim/demos/demo_hev_thrml.py @@ -312,6 +312,11 @@ def plot_road_loads() -> Tuple[Figure, Axes]: df["veh.history.pwr_rr_watts"] / 1e3, label="rr", ) + ax[0].plot( + df["cyc.time_seconds"][::veh.save_interval], + df["veh.history.pwr_tractive_watts"] / 1e3, + label="total", + ) ax[0].set_ylabel("Power [kW]") ax[0].legend() @@ -338,7 +343,7 @@ def plot_road_loads() -> Tuple[Figure, Axes]: fig_res_pwr, ax_res_pwr = plot_res_pwr() fig_res_energy, ax_res_energy = plot_res_energy() fig_temps, ax_temps = plot_temperatures() - # fig, ax = plot_road_loads() + fig, ax = plot_road_loads() plt.show() # %% # example for how to use set_default_pwr_interp() method for veh.res