mirror of
				https://github.com/Akkudoktor-EOS/EOS.git
				synced 2025-10-31 14:56:21 +00:00 
			
		
		
		
	translation of battery.py v3 (#262)
This commit is contained in:
		| @@ -10,345 +10,279 @@ from akkudoktoreos.utils.utils import NumpyEncoder | ||||
| logger = get_logger(__name__) | ||||
|  | ||||
|  | ||||
| def max_ladeleistung_w_field(default: Optional[float] = None) -> Optional[float]: | ||||
| def max_charging_power_field(description: Optional[str] = None) -> float: | ||||
|     if description is None: | ||||
|         description = "Maximum charging power in watts." | ||||
|     return Field( | ||||
|         default=default, | ||||
|         default=5000, | ||||
|         gt=0, | ||||
|         description="An integer representing the charging power of the battery in watts.", | ||||
|         description=description, | ||||
|     ) | ||||
|  | ||||
|  | ||||
| def start_soc_prozent_field(description: str) -> int: | ||||
| def initial_soc_percentage_field(description: str) -> int: | ||||
|     return Field(default=0, ge=0, le=100, description=description) | ||||
|  | ||||
|  | ||||
| class BaseAkkuParameters(BaseModel): | ||||
|     kapazitaet_wh: int = Field( | ||||
| class BaseBatteryParameters(BaseModel): | ||||
|     """Base class for battery parameters with fields for capacity, efficiency, and state of charge.""" | ||||
|  | ||||
|     capacity_wh: int = Field( | ||||
|         gt=0, description="An integer representing the capacity of the battery in watt-hours." | ||||
|     ) | ||||
|     lade_effizienz: float = Field( | ||||
|     charging_efficiency: float = Field( | ||||
|         default=0.88, | ||||
|         gt=0, | ||||
|         le=1, | ||||
|         description="A float representing the charging efficiency of the battery.", | ||||
|     ) | ||||
|     entlade_effizienz: float = Field(default=0.88, gt=0, le=1) | ||||
|     max_ladeleistung_w: Optional[float] = max_ladeleistung_w_field() | ||||
|     start_soc_prozent: int = start_soc_prozent_field( | ||||
|     discharging_efficiency: float = Field( | ||||
|         default=0.88, | ||||
|         gt=0, | ||||
|         le=1, | ||||
|         description="A float representing the discharge efficiency of the battery.", | ||||
|     ) | ||||
|     max_charge_power_w: Optional[float] = max_charging_power_field() | ||||
|     initial_soc_percentage: int = initial_soc_percentage_field( | ||||
|         "An integer representing the state of charge of the battery at the **start** of the current hour (not the current state)." | ||||
|     ) | ||||
|     min_soc_prozent: int = Field( | ||||
|     min_soc_percentage: int = Field( | ||||
|         default=0, | ||||
|         ge=0, | ||||
|         le=100, | ||||
|         description="An integer representing the minimum state of charge (SOC) of the battery in percentage.", | ||||
|     ) | ||||
|     max_soc_prozent: int = Field(default=100, ge=0, le=100) | ||||
|     max_soc_percentage: int = Field( | ||||
|         default=100, | ||||
|         ge=0, | ||||
|         le=100, | ||||
|         description="An integer representing the maximum state of charge (SOC) of the battery in percentage.", | ||||
|     ) | ||||
|  | ||||
|  | ||||
| class PVAkkuParameters(BaseAkkuParameters): | ||||
|     max_ladeleistung_w: Optional[float] = max_ladeleistung_w_field(5000) | ||||
| class SolarPanelBatteryParameters(BaseBatteryParameters): | ||||
|     max_charge_power_w: Optional[float] = max_charging_power_field() | ||||
|  | ||||
|  | ||||
| class EAutoParameters(BaseAkkuParameters): | ||||
|     entlade_effizienz: float = 1.0 | ||||
|     start_soc_prozent: int = start_soc_prozent_field( | ||||
| class ElectricVehicleParameters(BaseBatteryParameters): | ||||
|     """Parameters specific to an electric vehicle (EV).""" | ||||
|  | ||||
|     discharging_efficiency: float = 1.0 | ||||
|     initial_soc_percentage: int = initial_soc_percentage_field( | ||||
|         "An integer representing the current state of charge (SOC) of the battery in percentage." | ||||
|     ) | ||||
|  | ||||
|  | ||||
| class EAutoResult(BaseModel): | ||||
|     """This object contains information related to the electric vehicle and its charging and discharging behavior.""" | ||||
| class ElectricVehicleResult(BaseModel): | ||||
|     """Result class containing information related to the electric vehicle's charging and discharging behavior.""" | ||||
|  | ||||
|     charge_array: list[float] = Field( | ||||
|         description="Indicates for each hour whether the EV is charging (`0` for no charging, `1` for charging)." | ||||
|         description="Hourly charging status (0 for no charging, 1 for charging)." | ||||
|     ) | ||||
|     discharge_array: list[int] = Field( | ||||
|         description="Indicates for each hour whether the EV is discharging (`0` for no discharging, `1` for discharging)." | ||||
|         description="Hourly discharging status (0 for no discharging, 1 for discharging)." | ||||
|     ) | ||||
|     entlade_effizienz: float = Field(description="The discharge efficiency as a float.") | ||||
|     hours: int = Field(description="Amount of hours the simulation is done for.") | ||||
|     kapazitaet_wh: int = Field(description="The capacity of the EV’s battery in watt-hours.") | ||||
|     lade_effizienz: float = Field(description="The charging efficiency as a float.") | ||||
|     max_ladeleistung_w: int = Field(description="The maximum charging power of the EV in watts.") | ||||
|     discharging_efficiency: float = Field(description="The discharge efficiency as a float..") | ||||
|     hours: int = Field(description="Number of hours in the simulation.") | ||||
|     capacity_wh: int = Field(description="Capacity of the EV’s battery in watt-hours.") | ||||
|     charging_efficiency: float = Field(description="Charging efficiency as a float..") | ||||
|     max_charge_power_w: int = Field(description="Maximum charging power in watts.") | ||||
|     soc_wh: float = Field( | ||||
|         description="The state of charge of the battery in watt-hours at the start of the simulation." | ||||
|         description="State of charge of the battery in watt-hours at the start of the simulation." | ||||
|     ) | ||||
|     start_soc_prozent: int = Field( | ||||
|         description="The state of charge of the battery in percentage at the start of the simulation." | ||||
|     initial_soc_percentage: int = Field( | ||||
|         description="State of charge at the start of the simulation in percentage." | ||||
|     ) | ||||
|  | ||||
|     @field_validator( | ||||
|         "discharge_array", | ||||
|         "charge_array", | ||||
|         mode="before", | ||||
|     ) | ||||
|     @field_validator("discharge_array", "charge_array", mode="before") | ||||
|     def convert_numpy(cls, field: Any) -> Any: | ||||
|         return NumpyEncoder.convert_numpy(field)[0] | ||||
|  | ||||
|  | ||||
| class PVAkku(DeviceBase): | ||||
| class Battery(DeviceBase): | ||||
|     """Represents a battery device with methods to simulate energy charging and discharging.""" | ||||
|  | ||||
|     def __init__( | ||||
|         self, | ||||
|         parameters: Optional[BaseAkkuParameters] = None, | ||||
|         parameters: Optional[BaseBatteryParameters] = None, | ||||
|         hours: Optional[int] = 24, | ||||
|         provider_id: Optional[str] = None, | ||||
|     ): | ||||
|         # Configuration initialisation | ||||
|         # Initialize configuration and parameters | ||||
|         self.provider_id = provider_id | ||||
|         self.prefix = "<invalid>" | ||||
|         if self.provider_id == "GenericBattery": | ||||
|             self.prefix = "battery" | ||||
|         elif self.provider_id == "GenericBEV": | ||||
|             self.prefix = "bev" | ||||
|         # Parameter initialisiation | ||||
|  | ||||
|         self.parameters = parameters | ||||
|         if hours is None: | ||||
|             self.hours = self.total_hours | ||||
|             self.hours = self.total_hours  # TODO where does that come from? | ||||
|         else: | ||||
|             self.hours = hours | ||||
|  | ||||
|         self.initialised = False | ||||
|  | ||||
|         # Run setup if parameters are given, otherwise setup() has to be called later when the config is initialised. | ||||
|         if self.parameters is not None: | ||||
|             self.setup() | ||||
|  | ||||
|     def setup(self) -> None: | ||||
|         """Sets up the battery parameters based on configuration or provided parameters.""" | ||||
|         if self.initialised: | ||||
|             return | ||||
|         if self.provider_id is not None: | ||||
|             # Setup by configuration | ||||
|             # Battery capacity in Wh | ||||
|             self.kapazitaet_wh = getattr(self.config, f"{self.prefix}_capacity") | ||||
|             # Initial state of charge in Wh | ||||
|             self.start_soc_prozent = getattr(self.config, f"{self.prefix}_soc_start") | ||||
|             self.hours = self.total_hours | ||||
|             # Charge and discharge efficiency | ||||
|             self.lade_effizienz = getattr(self.config, f"{self.prefix}_charge_efficiency") | ||||
|             self.entlade_effizienz = getattr(self.config, f"{self.prefix}_discharge_efficiency") | ||||
|             self.max_ladeleistung_w = getattr(self.config, f"{self.prefix}_charge_power_max") | ||||
|             # Only assign for storage battery | ||||
|  | ||||
|         if self.provider_id: | ||||
|             # Setup from configuration | ||||
|             self.capacity_wh = getattr(self.config, f"{self.prefix}_capacity") | ||||
|             self.initial_soc_percentage = getattr(self.config, f"{self.prefix}_initial_soc") | ||||
|             self.hours = self.total_hours  # TODO where does that come from? | ||||
|             self.charging_efficiency = getattr(self.config, f"{self.prefix}_charging_efficiency") | ||||
|             self.discharging_efficiency = getattr( | ||||
|                 self.config, f"{self.prefix}_discharging_efficiency" | ||||
|             ) | ||||
|             self.max_charge_power_w = getattr(self.config, f"{self.prefix}_max_charging_power") | ||||
|  | ||||
|             if self.provider_id == "GenericBattery": | ||||
|                 self.min_soc_prozent = getattr(self.config, f"{self.prefix}_soc_mint") | ||||
|                 self.min_soc_percentage = getattr( | ||||
|                     self.config, | ||||
|                     f"{self.prefix}_soc_min", | ||||
|                 ) | ||||
|             else: | ||||
|                 self.min_soc_prozent = 0 | ||||
|             self.max_soc_prozent = getattr(self.config, f"{self.prefix}_soc_mint") | ||||
|         elif self.parameters is not None: | ||||
|             # Setup by parameters | ||||
|             # Battery capacity in Wh | ||||
|             self.kapazitaet_wh = self.parameters.kapazitaet_wh | ||||
|             # Initial state of charge in Wh | ||||
|             self.start_soc_prozent = self.parameters.start_soc_prozent | ||||
|             # Charge and discharge efficiency | ||||
|             self.lade_effizienz = self.parameters.lade_effizienz | ||||
|             self.entlade_effizienz = self.parameters.entlade_effizienz | ||||
|             self.max_ladeleistung_w = self.parameters.max_ladeleistung_w | ||||
|                 self.min_soc_percentage = 0 | ||||
|  | ||||
|             self.max_soc_percentage = getattr( | ||||
|                 self.config, | ||||
|                 f"{self.prefix}_soc_max", | ||||
|             ) | ||||
|         elif self.parameters: | ||||
|             # Setup from parameters | ||||
|             self.capacity_wh = self.parameters.capacity_wh | ||||
|             self.initial_soc_percentage = self.parameters.initial_soc_percentage | ||||
|             self.charging_efficiency = self.parameters.charging_efficiency | ||||
|             self.discharging_efficiency = self.parameters.discharging_efficiency | ||||
|             self.max_charge_power_w = self.parameters.max_charge_power_w | ||||
|             # Only assign for storage battery | ||||
|             self.min_soc_prozent = ( | ||||
|                 self.parameters.min_soc_prozent | ||||
|                 if isinstance(self.parameters, PVAkkuParameters) | ||||
|             self.min_soc_percentage = ( | ||||
|                 self.parameters.min_soc_percentage | ||||
|                 if isinstance(self.parameters, SolarPanelBatteryParameters) | ||||
|                 else 0 | ||||
|             ) | ||||
|             self.max_soc_prozent = self.parameters.max_soc_prozent | ||||
|             self.max_soc_percentage = self.parameters.max_soc_percentage | ||||
|         else: | ||||
|             error_msg = "Parameters and provider ID missing. Can't instantiate." | ||||
|             error_msg = "Parameters and provider ID are missing. Cannot instantiate." | ||||
|             logger.error(error_msg) | ||||
|             raise ValueError(error_msg) | ||||
|  | ||||
|         # init | ||||
|         if self.max_ladeleistung_w is None: | ||||
|             self.max_ladeleistung_w = self.kapazitaet_wh | ||||
|         # Initialize state of charge | ||||
|         if self.max_charge_power_w is None: | ||||
|             self.max_charge_power_w = self.capacity_wh  # TODO this should not be equal capacity_wh | ||||
|         self.discharge_array = np.full(self.hours, 1) | ||||
|         self.charge_array = np.full(self.hours, 1) | ||||
|         # Calculate start, min and max SoC in Wh | ||||
|         self.soc_wh = (self.start_soc_prozent / 100) * self.kapazitaet_wh | ||||
|         self.min_soc_wh = (self.min_soc_prozent / 100) * self.kapazitaet_wh | ||||
|         self.max_soc_wh = (self.max_soc_prozent / 100) * self.kapazitaet_wh | ||||
|         self.soc_wh = (self.initial_soc_percentage / 100) * self.capacity_wh | ||||
|         self.min_soc_wh = (self.min_soc_percentage / 100) * self.capacity_wh | ||||
|         self.max_soc_wh = (self.max_soc_percentage / 100) * self.capacity_wh | ||||
|  | ||||
|         self.initialised = True | ||||
|  | ||||
|     def to_dict(self) -> dict[str, Any]: | ||||
|         """Converts the object to a dictionary representation.""" | ||||
|         return { | ||||
|             "kapazitaet_wh": self.kapazitaet_wh, | ||||
|             "start_soc_prozent": self.start_soc_prozent, | ||||
|             "capacity_wh": self.capacity_wh, | ||||
|             "initial_soc_percentage": self.initial_soc_percentage, | ||||
|             "soc_wh": self.soc_wh, | ||||
|             "hours": self.hours, | ||||
|             "discharge_array": self.discharge_array, | ||||
|             "charge_array": self.charge_array, | ||||
|             "lade_effizienz": self.lade_effizienz, | ||||
|             "entlade_effizienz": self.entlade_effizienz, | ||||
|             "max_ladeleistung_w": self.max_ladeleistung_w, | ||||
|             "charging_efficiency": self.charging_efficiency, | ||||
|             "discharging_efficiency": self.discharging_efficiency, | ||||
|             "max_charge_power_w": self.max_charge_power_w, | ||||
|         } | ||||
|  | ||||
|     def reset(self) -> None: | ||||
|         self.soc_wh = (self.start_soc_prozent / 100) * self.kapazitaet_wh | ||||
|         # Ensure soc_wh is within min and max limits | ||||
|         """Resets the battery state to its initial values.""" | ||||
|         self.soc_wh = (self.initial_soc_percentage / 100) * self.capacity_wh | ||||
|         self.soc_wh = min(max(self.soc_wh, self.min_soc_wh), self.max_soc_wh) | ||||
|  | ||||
|         self.discharge_array = np.full(self.hours, 1) | ||||
|         self.charge_array = np.full(self.hours, 1) | ||||
|  | ||||
|     def set_discharge_per_hour(self, discharge_array: np.ndarray) -> None: | ||||
|         assert len(discharge_array) == self.hours | ||||
|         """Sets the discharge values for each hour.""" | ||||
|         if len(discharge_array) != self.hours: | ||||
|             raise ValueError(f"Discharge array must have exactly {self.hours} elements.") | ||||
|         self.discharge_array = np.array(discharge_array) | ||||
|  | ||||
|     def set_charge_per_hour(self, charge_array: np.ndarray) -> None: | ||||
|         assert len(charge_array) == self.hours | ||||
|         """Sets the charge values for each hour.""" | ||||
|         if len(charge_array) != self.hours: | ||||
|             raise ValueError(f"Charge array must have exactly {self.hours} elements.") | ||||
|         self.charge_array = np.array(charge_array) | ||||
|  | ||||
|     def set_charge_allowed_for_hour(self, charge: float, hour: int) -> None: | ||||
|         assert hour < self.hours | ||||
|         """Sets the charge for a specific hour.""" | ||||
|         if hour >= self.hours: | ||||
|             raise ValueError(f"Hour {hour} is out of range. Must be less than {self.hours}.") | ||||
|         self.charge_array[hour] = charge | ||||
|  | ||||
|     def ladezustand_in_prozent(self) -> float: | ||||
|         return (self.soc_wh / self.kapazitaet_wh) * 100 | ||||
|     def current_soc_percentage(self) -> float: | ||||
|         """Calculates the current state of charge in percentage.""" | ||||
|         return (self.soc_wh / self.capacity_wh) * 100 | ||||
|  | ||||
|     def energie_abgeben(self, wh: float, hour: int) -> tuple[float, float]: | ||||
|     def discharge_energy(self, wh: float, hour: int) -> tuple[float, float]: | ||||
|         """Discharges energy from the battery.""" | ||||
|         if self.discharge_array[hour] == 0: | ||||
|             return 0.0, 0.0  # No energy discharge and no losses | ||||
|             return 0.0, 0.0 | ||||
|  | ||||
|         # Calculate the maximum energy that can be discharged considering min_soc and efficiency | ||||
|         max_possible_discharge_wh = (self.soc_wh - self.min_soc_wh) * self.entlade_effizienz | ||||
|         max_possible_discharge_wh = max(max_possible_discharge_wh, 0.0)  # Ensure non-negative | ||||
|         max_possible_discharge_wh = (self.soc_wh - self.min_soc_wh) * self.discharging_efficiency | ||||
|         max_possible_discharge_wh = max(max_possible_discharge_wh, 0.0) | ||||
|  | ||||
|         # Consider the maximum discharge power of the battery | ||||
|         max_abgebbar_wh = min(max_possible_discharge_wh, self.max_ladeleistung_w) | ||||
|         max_possible_discharge_wh = min( | ||||
|             max_possible_discharge_wh, self.max_charge_power_w | ||||
|         )  # TODO make a new cfg variable max_discharge_power_w | ||||
|  | ||||
|         # The actually discharged energy cannot exceed requested energy or maximum discharge | ||||
|         tatsaechlich_abgegeben_wh = min(wh, max_abgebbar_wh) | ||||
|         actual_discharge_wh = min(wh, max_possible_discharge_wh) | ||||
|         actual_withdrawal_wh = ( | ||||
|             actual_discharge_wh / self.discharging_efficiency | ||||
|             if self.discharging_efficiency > 0 | ||||
|             else 0.0 | ||||
|         ) | ||||
|  | ||||
|         # Calculate the actual amount withdrawn from the battery (before efficiency loss) | ||||
|         if self.entlade_effizienz > 0: | ||||
|             tatsaechliche_entnahme_wh = tatsaechlich_abgegeben_wh / self.entlade_effizienz | ||||
|         else: | ||||
|             tatsaechliche_entnahme_wh = 0.0 | ||||
|  | ||||
|         # Update the state of charge considering the actual withdrawal | ||||
|         self.soc_wh -= tatsaechliche_entnahme_wh | ||||
|         # Ensure soc_wh does not go below min_soc_wh | ||||
|         self.soc_wh -= actual_withdrawal_wh | ||||
|         self.soc_wh = max(self.soc_wh, self.min_soc_wh) | ||||
|  | ||||
|         # Calculate losses due to efficiency | ||||
|         verluste_wh = tatsaechliche_entnahme_wh - tatsaechlich_abgegeben_wh | ||||
|         losses_wh = actual_withdrawal_wh - actual_discharge_wh | ||||
|         return actual_discharge_wh, losses_wh | ||||
|  | ||||
|         # Return the actually discharged energy and the losses | ||||
|         return tatsaechlich_abgegeben_wh, verluste_wh | ||||
|  | ||||
|     def energie_laden( | ||||
|     def charge_energy( | ||||
|         self, wh: Optional[float], hour: int, relative_power: float = 0.0 | ||||
|     ) -> tuple[float, float]: | ||||
|         """Charges energy into the battery.""" | ||||
|         if hour is not None and self.charge_array[hour] == 0: | ||||
|             return 0.0, 0.0  # Charging not allowed in this hour | ||||
|  | ||||
|         if relative_power > 0.0: | ||||
|             wh = self.max_ladeleistung_w * relative_power | ||||
|         # If no value for wh is given, use the maximum charging power | ||||
|         wh = wh if wh is not None else self.max_ladeleistung_w | ||||
|             wh = self.max_charge_power_w * relative_power | ||||
|  | ||||
|         # Calculate the maximum energy that can be charged considering max_soc and efficiency | ||||
|         if self.lade_effizienz > 0: | ||||
|             max_possible_charge_wh = (self.max_soc_wh - self.soc_wh) / self.lade_effizienz | ||||
|         else: | ||||
|             max_possible_charge_wh = 0.0 | ||||
|         max_possible_charge_wh = max(max_possible_charge_wh, 0.0)  # Ensure non-negative | ||||
|         wh = wh if wh is not None else self.max_charge_power_w | ||||
|  | ||||
|         # The actually charged energy cannot exceed requested energy, charging power, or maximum possible charge | ||||
|         effektive_lademenge = min(wh, max_possible_charge_wh) | ||||
|         max_possible_charge_wh = ( | ||||
|             (self.max_soc_wh - self.soc_wh) / self.charging_efficiency | ||||
|             if self.charging_efficiency > 0 | ||||
|             else 0.0 | ||||
|         ) | ||||
|         max_possible_charge_wh = max(max_possible_charge_wh, 0.0) | ||||
|  | ||||
|         # Energy actually stored in the battery | ||||
|         geladene_menge = effektive_lademenge * self.lade_effizienz | ||||
|         effective_charge_wh = min(wh, max_possible_charge_wh) | ||||
|         charged_wh = effective_charge_wh * self.charging_efficiency | ||||
|  | ||||
|         # Update soc_wh | ||||
|         self.soc_wh += geladene_menge | ||||
|         # Ensure soc_wh does not exceed max_soc_wh | ||||
|         self.soc_wh += charged_wh | ||||
|         self.soc_wh = min(self.soc_wh, self.max_soc_wh) | ||||
|  | ||||
|         # Calculate losses | ||||
|         verluste_wh = effektive_lademenge - geladene_menge | ||||
|         return geladene_menge, verluste_wh | ||||
|         losses_wh = effective_charge_wh - charged_wh | ||||
|         return charged_wh, losses_wh | ||||
|  | ||||
|     def aktueller_energieinhalt(self) -> float: | ||||
|         """This method returns the current remaining energy considering efficiency. | ||||
|  | ||||
|         It accounts for both charging and discharging efficiency. | ||||
|         """ | ||||
|         # Calculate remaining energy considering discharge efficiency | ||||
|         nutzbare_energie = (self.soc_wh - self.min_soc_wh) * self.entlade_effizienz | ||||
|         return max(nutzbare_energie, 0.0) | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     # Test battery discharge below min_soc | ||||
|     print("Test: Discharge below min_soc") | ||||
|     akku = PVAkku( | ||||
|         PVAkkuParameters( | ||||
|             kapazitaet_wh=10000, | ||||
|             start_soc_prozent=50, | ||||
|             min_soc_prozent=20, | ||||
|             max_soc_prozent=80, | ||||
|         ), | ||||
|         hours=1, | ||||
|     ) | ||||
|     akku.reset() | ||||
|     print(f"Initial SoC: {akku.ladezustand_in_prozent()}%") | ||||
|  | ||||
|     # Try to discharge 5000 Wh | ||||
|     abgegeben_wh, verlust_wh = akku.energie_abgeben(5000, 0) | ||||
|     print(f"Energy discharged: {abgegeben_wh} Wh, Losses: {verlust_wh} Wh") | ||||
|     print(f"SoC after discharge: {akku.ladezustand_in_prozent()}%") | ||||
|     print(f"Expected min SoC: {akku.min_soc_prozent}%") | ||||
|  | ||||
|     # Test battery charge above max_soc | ||||
|     print("\nTest: Charge above max_soc") | ||||
|     akku = PVAkku( | ||||
|         PVAkkuParameters( | ||||
|             kapazitaet_wh=10000, | ||||
|             start_soc_prozent=50, | ||||
|             min_soc_prozent=20, | ||||
|             max_soc_prozent=80, | ||||
|         ), | ||||
|         hours=1, | ||||
|     ) | ||||
|     akku.reset() | ||||
|     print(f"Initial SoC: {akku.ladezustand_in_prozent()}%") | ||||
|  | ||||
|     # Try to charge 5000 Wh | ||||
|     geladen_wh, verlust_wh = akku.energie_laden(5000, 0) | ||||
|     print(f"Energy charged: {geladen_wh} Wh, Losses: {verlust_wh} Wh") | ||||
|     print(f"SoC after charge: {akku.ladezustand_in_prozent()}%") | ||||
|     print(f"Expected max SoC: {akku.max_soc_prozent}%") | ||||
|  | ||||
|     # Test charging when battery is at max_soc | ||||
|     print("\nTest: Charging when at max_soc") | ||||
|     akku = PVAkku( | ||||
|         PVAkkuParameters( | ||||
|             kapazitaet_wh=10000, | ||||
|             start_soc_prozent=80, | ||||
|             min_soc_prozent=20, | ||||
|             max_soc_prozent=80, | ||||
|         ), | ||||
|         hours=1, | ||||
|     ) | ||||
|     akku.reset() | ||||
|     print(f"Initial SoC: {akku.ladezustand_in_prozent()}%") | ||||
|  | ||||
|     geladen_wh, verlust_wh = akku.energie_laden(5000, 0) | ||||
|     print(f"Energy charged: {geladen_wh} Wh, Losses: {verlust_wh} Wh") | ||||
|     print(f"SoC after charge: {akku.ladezustand_in_prozent()}%") | ||||
|  | ||||
|     # Test discharging when battery is at min_soc | ||||
|     print("\nTest: Discharging when at min_soc") | ||||
|     akku = PVAkku( | ||||
|         PVAkkuParameters( | ||||
|             kapazitaet_wh=10000, | ||||
|             start_soc_prozent=20, | ||||
|             min_soc_prozent=20, | ||||
|             max_soc_prozent=80, | ||||
|         ), | ||||
|         hours=1, | ||||
|     ) | ||||
|     akku.reset() | ||||
|     print(f"Initial SoC: {akku.ladezustand_in_prozent()}%") | ||||
|  | ||||
|     abgegeben_wh, verlust_wh = akku.energie_abgeben(5000, 0) | ||||
|     print(f"Energy discharged: {abgegeben_wh} Wh, Losses: {verlust_wh} Wh") | ||||
|     print(f"SoC after discharge: {akku.ladezustand_in_prozent()}%") | ||||
|     def current_energy_content(self) -> float: | ||||
|         """Returns the current usable energy in the battery.""" | ||||
|         usable_energy = (self.soc_wh - self.min_soc_wh) * self.discharging_efficiency | ||||
|         return max(usable_energy, 0.0) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user