from dataclasses import dataclass @dataclass class BatteryParameters: capacity_Ah: float = 330 efficiency: float = 0.9 # [dimensionless] voltage_V: float = 600 charge_kW: float = 50 discharge_kW: float = 60 # SOC is normalized so that minimal_depth_of_discharge = 0 and maximal_depth_of_discharge = 1. # please set capacity_Ah = nominal_capacity_Ah * (max_dod - min_dod) # # TODO efficiency multiplier is not currently used, where best to put it? class BatteryModel: def __init__(self, battery_parameters, time_interval_h): self.p = battery_parameters self.time_interval_h = time_interval_h # the only non-constant member variable! # ratio of self.current_capacity_kWh and self.maximal_capacity_kWh self.soc = 0.0 @property def maximal_capacity_kWh(self): return self.p.capacity_Ah * self.p.voltage_V / 1000 @property def current_capacity_kWh(self): return self.soc * self.maximal_capacity_kWh def satisfy_demand(self, demand_kW): assert 0 <= self.soc <= 1 assert demand_kW >= 0 # rate limited: possible_discharge_in_timestep_kWh = self.p.discharge_kW * self.time_interval_h # limited by current capacity: possible_discharge_in_timestep_kWh = min((possible_discharge_in_timestep_kWh, self.current_capacity_kWh)) # limited by need: discharge_in_timestep_kWh = min((possible_discharge_in_timestep_kWh, demand_kW * self.time_interval_h)) consumption_from_bess_kW = discharge_in_timestep_kWh / self.time_interval_h unsatisfied_demand_kW = demand_kW - consumption_from_bess_kW cap_of_battery_kWh = self.current_capacity_kWh - discharge_in_timestep_kWh soc = cap_of_battery_kWh / self.maximal_capacity_kWh assert 0 <= soc <= self.soc <= 1 self.soc = soc return unsatisfied_demand_kW def charge(self, charge_kW): assert 0 <= self.soc <= 1 assert charge_kW >= 0 # rate limited: possible_charge_in_timestep_kWh = self.p.charge_kW * self.time_interval_h # limited by current capacity: possible_charge_in_timestep_kWh = min((possible_charge_in_timestep_kWh, self.maximal_capacity_kWh - self.current_capacity_kWh)) # limited by supply: charge_in_timestep_kWh = min((possible_charge_in_timestep_kWh, charge_kW * self.time_interval_h)) actual_charge_kW = charge_in_timestep_kWh / self.time_interval_h unused_charge_kW = charge_kW - actual_charge_kW cap_of_battery_kWh = self.current_capacity_kWh + charge_in_timestep_kWh soc = cap_of_battery_kWh / self.maximal_capacity_kWh assert 0 <= self.soc <= soc <= 1 self.soc = soc return unused_charge_kW