Self consumption predictor

* Inverter: Self consumption interpolator for better discharge_hour results
 * Small penalty when EV 100% and charge >0
 * Price Forceast (use mean of last 7 days instead of repeat)
 * Price Prediction as JSON simulation output, config fixed electricty fees configurable + MyPy & Ruff
This commit is contained in:
Andreas 2024-12-19 14:45:20 +01:00 committed by Dominique Lasserre
parent 1c75060d8a
commit 410a23e375
15 changed files with 1243 additions and 820 deletions

View File

@ -1072,6 +1072,19 @@
"description": "FastAPI server IP port number.",
"default": 8503
},
"server_fastapi_verbose": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"title": "Server Fastapi Verbose",
"description": "Enable debug output",
"default": false
},
"server_fastapi_startup_server_fasthtml": {
"anyOf": [
{
@ -3712,6 +3725,19 @@
"description": "FastAPI server IP port number.",
"default": 8503
},
"server_fastapi_verbose": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"title": "Server Fastapi Verbose",
"description": "Enable debug output",
"default": false
},
"server_fastapi_startup_server_fasthtml": {
"anyOf": [
{
@ -5775,6 +5801,21 @@
"type": "array",
"title": "Akku Soc Pro Stunde",
"description": "The state of charge of the battery (not the EV) in percentage per hour."
},
"Electricity_price": {
"items": {
"anyOf": [
{
"type": "number"
},
{
"type": "null"
}
]
},
"type": "array",
"title": "Electricity Price",
"description": "Used Electricity Price, including predictions"
}
},
"type": "object",
@ -5791,7 +5832,8 @@
"Netzbezug_Wh_pro_Stunde",
"Netzeinspeisung_Wh_pro_Stunde",
"Verluste_Pro_Stunde",
"akku_soc_pro_stunde"
"akku_soc_pro_stunde",
"Electricity_price"
],
"title": "SimulationResult",
"description": "This object contains the results of the simulation and provides insights into various parameters over the entire forecast period."

View File

@ -86,6 +86,9 @@ class SimulationResult(PydanticBaseModel):
akku_soc_pro_stunde: list[Optional[float]] = Field(
description="The state of charge of the battery (not the EV) in percentage per hour."
)
Electricity_price: list[Optional[float]] = Field(
description="Used Electricity Price, including predictions"
)
@field_validator(
"Last_Wh_pro_Stunde",
@ -97,6 +100,7 @@ class SimulationResult(PydanticBaseModel):
"EAuto_SoC_pro_Stunde",
"Verluste_Pro_Stunde",
"Home_appliance_wh_per_hour",
"Electricity_price",
mode="before",
)
def convert_numpy(cls, field: Any) -> Any:
@ -320,6 +324,7 @@ class EnergieManagementSystem(SingletonMixin, ConfigMixin, PredictionMixin, Pyda
eauto_soc_pro_stunde = np.full((total_hours), np.nan)
verluste_wh_pro_stunde = np.full((total_hours), np.nan)
home_appliance_wh_per_hour = np.full((total_hours), np.nan)
electricity_price_per_hour = np.full((total_hours), np.nan)
# Set initial state
if self.akku:
@ -377,6 +382,7 @@ class EnergieManagementSystem(SingletonMixin, ConfigMixin, PredictionMixin, Pyda
netzbezug_wh_pro_stunde[stunde_since_now] = netzbezug
verluste_wh_pro_stunde[stunde_since_now] += verluste
last_wh_pro_stunde[stunde_since_now] = verbrauch
electricity_price_per_hour[stunde_since_now] = self.strompreis_euro_pro_wh[stunde]
# Financial calculations
kosten_euro_pro_stunde[stunde_since_now] = (
@ -410,6 +416,7 @@ class EnergieManagementSystem(SingletonMixin, ConfigMixin, PredictionMixin, Pyda
"Verluste_Pro_Stunde": verluste_wh_pro_stunde,
"Gesamt_Verluste": np.nansum(verluste_wh_pro_stunde),
"Home_appliance_wh_per_hour": home_appliance_wh_per_hour,
"Electricity_price": electricity_price_per_hour,
}
return out

Binary file not shown.

View File

@ -10,6 +10,9 @@ from akkudoktoreos.devices.battery import Battery
from akkudoktoreos.devices.devicesabc import DevicesBase
from akkudoktoreos.devices.generic import HomeAppliance
from akkudoktoreos.devices.inverter import Inverter
from akkudoktoreos.prediction.self_consumption_probability import (
self_consumption_probability_interpolator,
)
from akkudoktoreos.utils.datetimeutil import to_duration
from akkudoktoreos.utils.logutil import get_logger
@ -162,7 +165,11 @@ class Devices(SingletonMixin, DevicesBase):
akku: ClassVar[Battery] = Battery(provider_id="GenericBattery")
eauto: ClassVar[Battery] = Battery(provider_id="GenericBEV")
home_appliance: ClassVar[HomeAppliance] = HomeAppliance(provider_id="GenericDishWasher")
inverter: ClassVar[Inverter] = Inverter(akku=akku, provider_id="GenericInverter")
inverter: ClassVar[Inverter] = Inverter(
self_consumption_predictor=self_consumption_probability_interpolator,
akku=akku,
provider_id="GenericInverter",
)
def update_data(self) -> None:
"""Update device simulation data."""

View File

@ -1,6 +1,7 @@
from typing import Optional, Tuple
from typing import Optional
from pydantic import BaseModel, Field
from scipy.interpolate import RegularGridInterpolator
from akkudoktoreos.devices.battery import Battery
from akkudoktoreos.devices.devicesabc import DeviceBase
@ -16,6 +17,7 @@ class InverterParameters(BaseModel):
class Inverter(DeviceBase):
def __init__(
self,
self_consumption_predictor: RegularGridInterpolator,
parameters: Optional[InverterParameters] = None,
akku: Optional[Battery] = None,
provider_id: Optional[str] = None,
@ -34,6 +36,7 @@ class Inverter(DeviceBase):
logger.error(error_msg)
raise NotImplementedError(error_msg)
self.akku = akku # Connection to a battery object
self.self_consumption_predictor = self_consumption_predictor
self.initialised = False
# Run setup if parameters are given, otherwise setup() has to be called later when the config is initialised.
@ -58,28 +61,60 @@ class Inverter(DeviceBase):
def process_energy(
self, generation: float, consumption: float, hour: int
) -> Tuple[float, float, float, float]:
) -> tuple[float, float, float, float]:
losses = 0.0
grid_export = 0.0
grid_import = 0.0
self_consumption = 0.0
if generation >= consumption:
# Case 1: Sufficient or excess generation
actual_consumption = min(consumption, self.max_power_wh)
remaining_energy = generation - actual_consumption
if consumption > self.max_power_wh:
# If consumption exceeds maximum inverter power
losses += generation - self.max_power_wh
remaining_power = self.max_power_wh - consumption
grid_import = -remaining_power # Negative indicates feeding into the grid
self_consumption = self.max_power_wh
else:
scr = self.self_consumption_predictor.calculate_self_consumption(
consumption, generation
)
# Charge battery with excess energy
charged_energy, charging_losses = self.akku.charge_energy(remaining_energy, hour)
losses += charging_losses
# Remaining power after consumption
remaining_power = (generation - consumption) * scr # EVQ
# Remaining load Self Consumption not perfect
remaining_load_evq = (generation - consumption) * (1.0 - scr)
# Calculate remaining surplus after battery charge
remaining_surplus = remaining_energy - (charged_energy + charging_losses)
grid_export = min(remaining_surplus, self.max_power_wh - actual_consumption)
if remaining_load_evq > 0:
# Akku muss den Restverbrauch decken
from_battery, discharge_losses = self.akku.discharge_energy(
remaining_load_evq, hour
)
remaining_load_evq -= from_battery # Restverbrauch nach Akkuentladung
losses += discharge_losses
# If any remaining surplus can't be fed to the grid, count as losses
losses += max(remaining_surplus - grid_export, 0)
self_consumption = actual_consumption
# Wenn der Akku den Restverbrauch nicht vollständig decken kann, wird der Rest ins Netz gezogen
if remaining_load_evq > 0:
grid_import += remaining_load_evq
remaining_load_evq = 0
else:
from_battery = 0.0
if remaining_power > 0:
# Load battery with excess energy
charged_energie, charge_losses = self.akku.charge_energy(remaining_power, hour)
remaining_surplus = remaining_power - (charged_energie + charge_losses)
# Feed-in to the grid based on remaining capacity
if remaining_surplus > self.max_power_wh - consumption:
grid_export = self.max_power_wh - consumption
losses += remaining_surplus - grid_export
else:
grid_export = remaining_surplus
losses += charge_losses
self_consumption = (
consumption + from_battery
) # Self-consumption is equal to the load
else:
# Case 2: Insufficient generation, cover shortfall

View File

@ -1,5 +1,7 @@
import random
from typing import Any, Optional, Tuple
import time
from pathlib import Path
from typing import Any, Optional
import numpy as np
from deap import algorithms, base, creator, tools
@ -20,6 +22,9 @@ from akkudoktoreos.devices.battery import (
)
from akkudoktoreos.devices.generic import HomeAppliance, HomeApplianceParameters
from akkudoktoreos.devices.inverter import Inverter, InverterParameters
from akkudoktoreos.prediction.self_consumption_probability import (
self_consumption_probability_interpolator,
)
from akkudoktoreos.utils.utils import NumpyEncoder
@ -116,8 +121,8 @@ class optimization_problem(ConfigMixin, DevicesMixin, EnergyManagementSystemMixi
random.seed(fixed_seed)
def decode_charge_discharge(
self, discharge_hours_bin: list[float]
) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
self, discharge_hours_bin: np.ndarray
) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
"""Decode the input array into ac_charge, dc_charge, and discharge arrays."""
discharge_hours_bin_np = np.array(discharge_hours_bin)
len_ac = len(self.config.optimization_ev_available_charge_rates_percent)
@ -137,7 +142,7 @@ class optimization_problem(ConfigMixin, DevicesMixin, EnergyManagementSystemMixi
# AC states
ac_mask = (discharge_hours_bin_np >= 2 * len_ac) & (discharge_hours_bin_np < 3 * len_ac)
ac_indices = discharge_hours_bin_np[ac_mask] - 2 * len_ac
ac_indices = (discharge_hours_bin_np[ac_mask] - 2 * len_ac).astype(int)
# DC states (if enabled)
if self.optimize_dc_charge:
@ -217,28 +222,71 @@ class optimization_problem(ConfigMixin, DevicesMixin, EnergyManagementSystemMixi
return creator.Individual(individual_components)
def merge_individual(
self,
discharge_hours_bin: np.ndarray,
eautocharge_hours_index: Optional[np.ndarray],
washingstart_int: Optional[int],
) -> list[int]:
"""Merge the individual components back into a single solution list.
Parameters:
discharge_hours_bin (np.ndarray): Binary discharge hours.
eautocharge_hours_index (Optional[np.ndarray]): EV charge hours as integers, or None.
washingstart_int (Optional[int]): Dishwasher start time as integer, or None.
Returns:
list[int]: The merged individual solution as a list of integers.
"""
# Start with the discharge hours
individual = discharge_hours_bin.tolist()
# Add EV charge hours if applicable
if self.optimize_ev and eautocharge_hours_index is not None:
individual.extend(eautocharge_hours_index.tolist())
elif self.optimize_ev:
# Falls optimize_ev aktiv ist, aber keine EV-Daten vorhanden sind, fügen wir Nullen hinzu
individual.extend([0] * self.config.prediction_hours)
# Add dishwasher start time if applicable
if self.opti_param.get("home_appliance", 0) > 0 and washingstart_int is not None:
individual.append(washingstart_int)
elif self.opti_param.get("home_appliance", 0) > 0:
# Falls ein Haushaltsgerät optimiert wird, aber kein Startzeitpunkt vorhanden ist
individual.append(0)
return individual
def split_individual(
self, individual: list[float]
) -> tuple[list[float], Optional[list[float]], Optional[int]]:
self, individual: list[int]
) -> tuple[np.ndarray, Optional[np.ndarray], Optional[int]]:
"""Split the individual solution into its components.
Components:
1. Discharge hours (binary),
2. Electric vehicle charge hours (float),
1. Discharge hours (binary as int NumPy array),
2. Electric vehicle charge hours (float as int NumPy array, if applicable),
3. Dishwasher start time (integer if applicable).
"""
discharge_hours_bin = individual[: self.config.prediction_hours]
# Discharge hours as a NumPy array of ints
discharge_hours_bin = np.array(individual[: self.config.prediction_hours], dtype=int)
# EV charge hours as a NumPy array of ints (if optimize_ev is True)
eautocharge_hours_index = (
individual[self.config.prediction_hours : self.config.prediction_hours * 2]
np.array(
individual[self.config.prediction_hours : self.config.prediction_hours * 2],
dtype=int,
)
if self.optimize_ev
else None
)
# Washing machine start time as an integer (if applicable)
washingstart_int = (
int(individual[-1])
if self.opti_param and self.opti_param.get("home_appliance", 0) > 0
else None
)
return discharge_hours_bin, eautocharge_hours_index, washingstart_int
def setup_deap_environment(self, opti_param: dict[str, Any], start_hour: int) -> None:
@ -308,7 +356,7 @@ class optimization_problem(ConfigMixin, DevicesMixin, EnergyManagementSystemMixi
self.toolbox.register("mutate", self.mutate)
self.toolbox.register("select", tools.selTournament, tournsize=3)
def evaluate_inner(self, individual: list[float]) -> dict[str, Any]:
def evaluate_inner(self, individual: list[int]) -> dict[str, Any]:
"""Simulates the energy management system (EMS) using the provided individual solution.
This is an internal function.
@ -340,16 +388,17 @@ class optimization_problem(ConfigMixin, DevicesMixin, EnergyManagementSystemMixi
)
self.ems.set_ev_charge_hours(eautocharge_hours_float)
else:
self.ems.set_ev_charge_hours(np.full(self.config.prediction_hours, 0.0))
self.ems.set_ev_charge_hours(np.full(self.config.prediction_hours, 0))
return self.ems.simuliere(self.ems.start_datetime.hour)
def evaluate(
self,
individual: list[float],
individual: list[int],
parameters: OptimizationParameters,
start_hour: int,
worst_case: bool,
) -> Tuple[float]:
) -> tuple[float]:
"""Evaluate the fitness of an individual solution based on the simulation results."""
try:
o = self.evaluate_inner(individual)
@ -358,19 +407,39 @@ class optimization_problem(ConfigMixin, DevicesMixin, EnergyManagementSystemMixi
gesamtbilanz = o["Gesamtbilanz_Euro"] * (-1.0 if worst_case else 1.0)
discharge_hours_bin, eautocharge_hours_index, _ = self.split_individual(individual)
# Small Penalty for not discharging
gesamtbilanz += sum(
0.01 for i in range(self.config.prediction_hours) if discharge_hours_bin[i] == 0.0
discharge_hours_bin, eautocharge_hours_index, washingstart_int = self.split_individual(
individual
)
# Penalty for not meeting the minimum SOC (State of Charge) requirement
# if parameters.eauto_min_soc_prozent - ems.eauto.current_soc_percentage() <= 0.0 and self.optimize_ev:
# gesamtbilanz += sum(
# self.config.optimization_penalty for ladeleistung in eautocharge_hours_float if ladeleistung != 0.0
# )
# EV 100% & charge not allowed
if self.optimize_ev:
eauto_soc_per_hour = np.array(o.get("EAuto_SoC_pro_Stunde", [])) # Beispielkey
if eauto_soc_per_hour is None or eautocharge_hours_index is None:
raise ValueError("eauto_soc_per_hour or eautocharge_hours_index is None")
min_length = min(eauto_soc_per_hour.size, eautocharge_hours_index.size)
eauto_soc_per_hour_tail = eauto_soc_per_hour[-min_length:]
eautocharge_hours_index_tail = eautocharge_hours_index[-min_length:]
# Mask
invalid_charge_mask = (eauto_soc_per_hour_tail == 100) & (
eautocharge_hours_index_tail > 0
)
if np.any(invalid_charge_mask):
invalid_indices = np.where(invalid_charge_mask)[0]
if len(invalid_indices) > 1:
eautocharge_hours_index_tail[invalid_indices[1:]] = 0
eautocharge_hours_index[-min_length:] = eautocharge_hours_index_tail.tolist()
adjusted_individual = self.merge_individual(
discharge_hours_bin, eautocharge_hours_index, washingstart_int
)
individual[:] = adjusted_individual # Aktualisiere das ursprüngliche individual
# Berechnung weiterer Metriken
individual.extra_data = ( # type: ignore[attr-defined]
o["Gesamtbilanz_Euro"],
o["Gesamt_Verluste"],
@ -380,13 +449,11 @@ class optimization_problem(ConfigMixin, DevicesMixin, EnergyManagementSystemMixi
)
# Adjust total balance with battery value and penalties for unmet SOC
restwert_akku = (
self.ems.akku.current_energy_content() * parameters.ems.preis_euro_pro_wh_akku
)
# print(ems.akku.current_energy_content()," * ", parameters.ems.preis_euro_pro_wh_akku , " ", restwert_akku, " ", gesamtbilanz)
gesamtbilanz += -restwert_akku
# print(gesamtbilanz)
if self.optimize_ev:
gesamtbilanz += max(
0,
@ -401,8 +468,8 @@ class optimization_problem(ConfigMixin, DevicesMixin, EnergyManagementSystemMixi
return (gesamtbilanz,)
def optimize(
self, start_solution: Optional[list[float]] = None, ngen: int = 400
) -> Tuple[Any, dict[str, list[Any]]]:
self, start_solution: Optional[list[float]] = None, ngen: int = 200
) -> tuple[Any, dict[str, list[Any]]]:
"""Run the optimization process using a genetic algorithm."""
population = self.toolbox.population(n=300)
hof = tools.HallOfFame(1)
@ -414,7 +481,7 @@ class optimization_problem(ConfigMixin, DevicesMixin, EnergyManagementSystemMixi
# Insert the start solution into the population if provided
if start_solution is not None:
for _ in range(3):
for _ in range(10):
population.insert(0, creator.Individual(start_solution))
# Run the evolutionary algorithm
@ -446,7 +513,7 @@ class optimization_problem(ConfigMixin, DevicesMixin, EnergyManagementSystemMixi
parameters: OptimizationParameters,
start_hour: Optional[int] = None,
worst_case: bool = False,
ngen: int = 600,
ngen: int = 400,
) -> OptimizeResponse:
"""Perform EMS (Energy Management System) optimization and visualize results."""
if start_hour is None:
@ -456,6 +523,11 @@ class optimization_problem(ConfigMixin, DevicesMixin, EnergyManagementSystemMixi
self.config.prediction_hours, parameters.ems.einspeiseverguetung_euro_pro_wh
)
# 1h Load to Sub 1h Load Distribution -> SelfConsumptionRate
sc = self_consumption_probability_interpolator(
Path(__file__).parent.resolve() / ".." / "data" / "regular_grid_interpolator.pkl"
)
# Initialize PV and EV batteries
akku = Battery(
parameters.pv_akku,
@ -487,9 +559,14 @@ class optimization_problem(ConfigMixin, DevicesMixin, EnergyManagementSystemMixi
)
# Initialize the inverter and energy management system
inverter = Inverter(
sc,
parameters.inverter,
akku,
)
self.ems.set_parameters(
parameters.ems,
inverter=Inverter(parameters.inverter, akku),
inverter=inverter,
eauto=eauto,
home_appliance=dishwasher,
)
@ -501,8 +578,14 @@ class optimization_problem(ConfigMixin, DevicesMixin, EnergyManagementSystemMixi
"evaluate",
lambda ind: self.evaluate(ind, parameters, start_hour, worst_case),
)
if self.verbose:
start_time = time.time()
start_solution, extra_data = self.optimize(parameters.start_solution, ngen=ngen)
if self.verbose:
elapsed_time = time.time() - start_time
print(f"Time evaluate inner: {elapsed_time:.4f} sec.")
# Perform final evaluation on the best solution
o = self.evaluate_inner(start_solution)
discharge_hours_bin, eautocharge_hours_index, washingstart_int = self.split_individual(

View File

@ -0,0 +1,72 @@
#!/usr/bin/env python
import pickle
from functools import lru_cache
from pathlib import Path
import numpy as np
from scipy.interpolate import RegularGridInterpolator
class self_consumption_probability_interpolator:
def __init__(self, filepath: str | Path):
self.filepath = filepath
# self.interpolator = None
# Load the RegularGridInterpolator
with open(self.filepath, "rb") as file:
self.interpolator: RegularGridInterpolator = pickle.load(file)
@lru_cache(maxsize=128)
def generate_points(
self, load_1h_power: float, pv_power: float
) -> tuple[np.ndarray, np.ndarray]:
"""Generate the grid points for interpolation."""
partial_loads = np.arange(0, pv_power + 50, 50)
points = np.array([np.full_like(partial_loads, load_1h_power), partial_loads]).T
return points, partial_loads
def calculate_self_consumption(self, load_1h_power: float, pv_power: float) -> float:
points, partial_loads = self.generate_points(load_1h_power, pv_power)
probabilities = self.interpolator(points)
return probabilities.sum()
# def calculate_self_consumption(self, load_1h_power: float, pv_power: float) -> float:
# """Calculate the PV self-consumption rate using RegularGridInterpolator.
# Args:
# - last_1h_power: 1h power levels (W).
# - pv_power: Current PV power output (W).
# Returns:
# - Self-consumption rate as a float.
# """
# # Generate the range of partial loads (0 to last_1h_power)
# partial_loads = np.arange(0, pv_power + 50, 50)
# # Get probabilities for all partial loads
# points = np.array([np.full_like(partial_loads, load_1h_power), partial_loads]).T
# if self.interpolator == None:
# return -1.0
# probabilities = self.interpolator(points)
# self_consumption_rate = probabilities.sum()
# # probabilities = probabilities / (np.sum(probabilities)) # / (pv_power / 3450))
# # # for i, w in enumerate(partial_loads):
# # # print(w, ": ", probabilities[i])
# # print(probabilities.sum())
# # # Ensure probabilities are within [0, 1]
# # probabilities = np.clip(probabilities, 0, 1)
# # # Mask: Only include probabilities where the load is <= PV power
# # mask = partial_loads <= pv_power
# # # Calculate the cumulative probability for covered loads
# # self_consumption_rate = np.sum(probabilities[mask]) / np.sum(probabilities)
# # print(self_consumption_rate)
# # sys.exit()
# return self_consumption_rate
# Test the function
# print(calculate_self_consumption(1000, 1200))

View File

@ -80,7 +80,7 @@ app = FastAPI(
)
# That's the problem
opt_class = optimization_problem()
opt_class = optimization_problem(verbose=bool(config_eos.server_fastapi_verbose))
server_dir = Path(__file__).parent.resolve()

View File

@ -23,6 +23,7 @@ class ServerCommonSettings(SettingsBaseModel):
server_fastapi_port: Optional[int] = Field(
default=8503, description="FastAPI server IP port number."
)
server_fastapi_verbose: Optional[bool] = Field(default=False, description="Enable debug output")
server_fastapi_startup_server_fasthtml: Optional[bool] = Field(
default=True, description="FastAPI server to startup application FastHTML server."
)

View File

@ -1,3 +1,5 @@
from pathlib import Path
import numpy as np
import pytest
@ -15,6 +17,9 @@ from akkudoktoreos.devices.battery import (
)
from akkudoktoreos.devices.generic import HomeAppliance, HomeApplianceParameters
from akkudoktoreos.devices.inverter import Inverter, InverterParameters
from akkudoktoreos.prediction.self_consumption_probability import (
self_consumption_probability_interpolator,
)
start_hour = 1
@ -35,8 +40,19 @@ def create_ems_instance() -> EnergieManagementSystem:
),
hours=config_eos.prediction_hours,
)
# 1h Load to Sub 1h Load Distribution -> SelfConsumptionRate
sc = self_consumption_probability_interpolator(
Path(__file__).parent.resolve()
/ ".."
/ "src"
/ "akkudoktoreos"
/ "data"
/ "regular_grid_interpolator.pkl"
)
akku.reset()
inverter = Inverter(InverterParameters(max_power_wh=10000), akku)
inverter = Inverter(sc, InverterParameters(max_power_wh=10000), akku)
# Household device (currently not used, set to None)
home_appliance = HomeAppliance(
@ -306,21 +322,21 @@ def test_simulation(create_ems_instance):
# Verify the total balance
assert (
abs(result["Gesamtbilanz_Euro"] - 1.7880374129090917) < 1e-5
), "Total balance should be 1.7880374129090917."
abs(result["Gesamtbilanz_Euro"] - 1.958185274567674) < 1e-5
), "Total balance should be 1.958185274567674."
# Check total revenue and total costs
assert (
abs(result["Gesamteinnahmen_Euro"] - 1.3169784090909087) < 1e-5
), "Total revenue should be 1.3169784090909087."
abs(result["Gesamteinnahmen_Euro"] - 1.168863124510214) < 1e-5
), "Total revenue should be 1.168863124510214."
assert (
abs(result["Gesamtkosten_Euro"] - 3.1050158220000004) < 1e-5
), "Total costs should be 3.1050158220000004 ."
abs(result["Gesamtkosten_Euro"] - 3.127048399077888) < 1e-5
), "Total costs should be 3.127048399077888 ."
# Check the losses
assert (
abs(result["Gesamt_Verluste"] - 2615.222727272727) < 1e-5
), "Total losses should be 2615.222727272727 ."
abs(result["Gesamt_Verluste"] - 2871.5330639359036) < 1e-5
), "Total losses should be 2871.5330639359036 ."
# Check the values in 'akku_soc_pro_stunde'
assert (

View File

@ -1,3 +1,5 @@
from pathlib import Path
import numpy as np
import pytest
@ -14,6 +16,9 @@ from akkudoktoreos.devices.battery import (
)
from akkudoktoreos.devices.generic import HomeAppliance, HomeApplianceParameters
from akkudoktoreos.devices.inverter import Inverter, InverterParameters
from akkudoktoreos.prediction.self_consumption_probability import (
self_consumption_probability_interpolator,
)
start_hour = 0
@ -34,8 +39,19 @@ def create_ems_instance() -> EnergieManagementSystem:
),
hours=config_eos.prediction_hours,
)
# 1h Load to Sub 1h Load Distribution -> SelfConsumptionRate
sc = self_consumption_probability_interpolator(
Path(__file__).parent.resolve()
/ ".."
/ "src"
/ "akkudoktoreos"
/ "data"
/ "regular_grid_interpolator.pkl"
)
akku.reset()
inverter = Inverter(InverterParameters(max_power_wh=10000), akku)
inverter = Inverter(sc, InverterParameters(max_power_wh=10000), akku)
# Household device (currently not used, set to None)
home_appliance = HomeAppliance(

View File

@ -1,8 +1,12 @@
from pathlib import Path
from unittest.mock import Mock
import pytest
from akkudoktoreos.devices.inverter import Inverter, InverterParameters
from akkudoktoreos.prediction.self_consumption_probability import (
self_consumption_probability_interpolator,
)
@pytest.fixture
@ -15,25 +19,38 @@ def mock_battery():
@pytest.fixture
def inverter(mock_battery):
return Inverter(InverterParameters(max_power_wh=500.0), akku=mock_battery)
sc = self_consumption_probability_interpolator(
Path(__file__).parent.resolve()
/ ".."
/ "src"
/ "akkudoktoreos"
/ "data"
/ "regular_grid_interpolator.pkl"
)
return Inverter(sc, InverterParameters(max_power_wh=500.0), akku=mock_battery)
def test_process_energy_excess_generation(inverter, mock_battery):
# Battery charges 100 Wh with 10 Wh loss
mock_battery.charge_energy.return_value = (100.0, 10.0)
generation = 600.0
consumption = 200.0
hour = 12
mock_battery.charge_energy.return_value = (100.0, 10.0)
grid_export, grid_import, losses, self_consumption = inverter.process_energy(
generation, consumption, hour
)
assert grid_export == pytest.approx(290.0, rel=1e-2) # 290 Wh feed-in after battery charges
assert grid_import == 0.0 # No grid draw
assert grid_export == pytest.approx(
286.1737223461208, rel=1e-2
) # 290 Wh feed-in after battery charges
assert grid_import == pytest.approx(3.826277653879151, rel=1e-2) # Little grid draw
assert losses == 10.0 # Battery charging losses
assert self_consumption == 200.0 # All consumption is met
mock_battery.charge_energy.assert_called_once_with(400.0, hour)
mock_battery.charge_energy.assert_called_once_with(
pytest.approx(396.1737223461208, rel=1e-2), hour
)
def test_process_energy_generation_equals_consumption(inverter, mock_battery):
@ -50,7 +67,8 @@ def test_process_energy_generation_equals_consumption(inverter, mock_battery):
assert losses == 0.0 # No losses
assert self_consumption == 300.0 # All consumption is met with generation
mock_battery.charge_energy.assert_called_once_with(0.0, hour)
mock_battery.charge_energy.assert_not_called()
mock_battery.discharge_energy.assert_not_called()
def test_process_energy_battery_discharges(inverter, mock_battery):
@ -103,12 +121,14 @@ def test_process_energy_battery_full_at_start(inverter, mock_battery):
)
assert grid_export == pytest.approx(
300.0, rel=1e-2
296.39026480502736, rel=1e-2
) # All excess energy should be fed into the grid
assert grid_import == 0.0 # No grid draw
assert grid_import == pytest.approx(3.609735194972663, rel=1e-2) # Almost no grid draw
assert losses == 0.0 # No losses
assert self_consumption == 200.0 # Only consumption is met
mock_battery.charge_energy.assert_called_once_with(300.0, hour)
mock_battery.charge_energy.assert_called_once_with(
pytest.approx(296.39026480502736, rel=1e-2), hour
)
def test_process_energy_insufficient_generation_no_battery(inverter, mock_battery):
@ -185,10 +205,14 @@ def test_process_energy_zero_consumption(inverter, mock_battery):
)
assert grid_export == pytest.approx(390.0, rel=1e-2) # Excess energy after battery charges
assert grid_import == 0.0 # No grid draw as no consumption
assert grid_import == pytest.approx(
0.022862368543430378, rel=1e-2
) # Almost no grid draw as no consumption
assert losses == 10.0 # Charging losses
assert self_consumption == 0.0 # Zero consumption
mock_battery.charge_energy.assert_called_once_with(500.0, hour)
mock_battery.charge_energy.assert_called_once_with(
pytest.approx(499.97713763145657, rel=1e-2), hour
)
def test_process_energy_zero_generation_zero_consumption(inverter, mock_battery):

View File

@ -1,52 +1,52 @@
{
"ac_charge": [
0.75,
0.75,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.75,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.875,
0.0,
0.875,
0.0,
0.625,
0.75,
0.0,
0.375,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
1.0,
0.0,
1.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.375,
0.0,
0.0,
0.625,
0.0,
0.0,
0.375,
0.75,
1.0,
0.0,
0.0
],
"dc_charge": [
@ -102,35 +102,6 @@
"discharge_allowed": [
0,
0,
1,
1,
0,
1,
1,
1,
0,
1,
1,
1,
0,
1,
1,
1,
0,
0,
0,
0,
0,
0,
0,
0,
0,
1,
1,
0,
1,
1,
0,
0,
1,
0,
@ -138,8 +109,6 @@
0,
0,
0,
1,
0,
0,
0,
1,
@ -147,7 +116,38 @@
0,
1,
1,
1
0,
0,
0,
0,
1,
1,
1,
0,
0,
1,
0,
1,
1,
0,
0,
0,
1,
0,
1,
0,
1,
0,
1,
1,
0,
1,
0,
0,
0,
0,
1,
0
],
"eautocharge_hours_float": null,
"result": {
@ -179,7 +179,7 @@
992.46,
1155.99,
827.01,
1257.98,
3132.98,
1232.67,
871.26,
860.88,
@ -237,10 +237,10 @@
0.0,
0.0,
0.0,
0.212927386983471,
0.19275619999999996,
0.1339926,
0.0569765,
0.22334747537370364,
0.19016535126346096,
0.12880892587597292,
0.04260510586128589,
0.0,
0.0,
0.0,
@ -260,21 +260,21 @@
0.0,
0.0,
0.0,
0.1512260012396691,
0.257789,
0.1516669,
0.09915009999999999,
0.0348376,
0.059176154400016855,
0.25751345302450973,
0.14923279815365575,
0.07926913850394514,
0.024174420063375994,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Gesamt_Verluste": 2071.900103305785,
"Gesamtbilanz_Euro": 0.9349588927768602,
"Gesamteinnahmen_Euro": 1.2913222882231399,
"Gesamtkosten_Euro": 2.226281181,
"Gesamt_Verluste": 2500.030611233429,
"Gesamtbilanz_Euro": 1.4988843060949502,
"Gesamteinnahmen_Euro": 1.1542928225199272,
"Gesamtkosten_Euro": 2.6531771286148773,
"Home_appliance_wh_per_hour": [
null,
null,
@ -316,84 +316,84 @@
null
],
"Kosten_Euro_pro_Stunde": [
0.0,
0.027996119999999992,
0.0,
0.04475252599999999,
0.0018232052307313393,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.008135265032732555,
0.016809914659344942,
0.061530097476751734,
0.05480703000000003,
0.225316611,
0.291163892,
0.26650619799999997,
0.0,
0.0,
0.0,
0.19588158,
0.174739608,
0.0,
0.0,
0.199865757,
0.22802125600000003,
0.0,
0.0,
0.162995926,
0.16677339,
0.26411047,
0.0,
0.08545095,
0.0,
0.028255713342252034,
0.0,
0.3629952558325975,
0.0,
0.0,
0.0076430797975209205,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.04565364324294593,
0.08231598,
0.174597189,
0.293043269,
0.0,
0.0,
0.0
0.16484566
],
"Netzbezug_Wh_pro_Stunde": [
0.0,
122.78999999999996,
0.0,
213.81999999999994,
9.703061366318996,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
37.01212480770043,
74.05248748610107,
205.30563055305882,
171.54000000000008,
731.31,
980.68,
912.38,
0.0,
0.0,
0.0,
704.61,
516.37,
0.0,
0.0,
608.79,
694.34,
0.0,
0.0,
488.89,
506.91,
799.85,
0.0,
351.65,
0.0,
127.73830624887898,
0.0,
1931.853410498124,
0.0,
0.0,
34.77288351920346,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
152.3311419517715,
257.64,
566.69,
987.01,
0.0,
0.0,
0.0
592.97
],
"Netzeinspeisung_Wh_pro_Stunde": [
0.0,
@ -401,10 +401,10 @@
0.0,
0.0,
0.0,
3041.819814049586,
2753.66,
1914.18,
813.95,
3190.678219624338,
2716.6478751922996,
1840.127512513899,
608.6443694469413,
0.0,
0.0,
0.0,
@ -424,11 +424,11 @@
0.0,
0.0,
0.0,
2160.371446280987,
3682.7,
2166.67,
1416.43,
497.68000000000006,
845.3736342859552,
3678.7636146358536,
2131.8971164807967,
1132.4162643420734,
345.3488580482285,
0.0,
0.0,
0.0,
@ -436,51 +436,74 @@
0.0
],
"Verluste_Pro_Stunde": [
16.744090909090914,
0.0,
2.817272727272737,
0.0,
3.5592000000000112,
582.6179999999995,
156.0516223140496,
0.0,
0.0,
0.0,
2.3948326360417305,
582.6180000000041,
138.18861364508305,
0.0,
0.0,
0.0,
0.0,
99.72409090909093,
133.72909090909081,
124.41545454545451,
0.0,
0.0,
118.37045454545455,
94.68272727272722,
0.0,
83.01681818181817,
75.86045454545456,
66.66681818181814,
0.0,
0.0,
0.0,
109.96227272727276,
0.0,
15.439199999999985,
53.855999999999995,
159.6443999999999,
21.032399999999996,
279.0538264462814,
16.01263877609336,
38.52740325013451,
161.62968357967037,
239.20999074022512,
436.85356388568886,
0.5004782113116364,
0.0,
36.109951963721926,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
134.59227272727276,
100.08954545454549,
80.85954545454547
0.0
],
"akku_soc_pro_stunde": [
79.4714617768595,
79.38253271349862,
79.38253271349862,
79.48139938016529,
95.66523271349861,
80.0,
79.91107093663912,
79.91107093663912,
79.97759406541806,
96.1614273987495,
100.0,
100.0,
100.0,
100.0,
100.0,
96.85214359504131,
92.63089703856748,
88.7036415289256,
88.7036415289256,
88.7036415289256,
84.96720041322313,
84.96720041322313,
82.34672004132229,
79.95213498622587,
79.95213498622587,
79.95213498622587,
79.95213498622587,
76.48110365013771,
76.48110365013771,
76.64231728537023,
77.71252293120729,
81.22045681594867,
87.86517878095492,
100.0,
100.0,
100.0,
@ -489,31 +512,48 @@
100.0,
100.0,
100.0,
100.0,
100.0,
96.26355888429752,
93.27483643250687,
93.27483643250687,
90.88025137741046,
88.7758694903581,
88.7758694903581,
88.7758694903581,
85.30483815426996,
85.30483815426996,
85.73370482093662,
87.22970482093662,
91.66427148760329,
92.24850482093663,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
95.75150654269973,
92.59211432506888,
90.0397296831956
96.84060778236915,
96.84060778236915
],
"Electricity_price": [
0.000228,
0.0002212,
0.0002093,
0.0001879,
0.0001838,
0.0002004,
0.0002198,
0.000227,
0.0002997,
0.0003195,
0.0003081,
0.0002969,
0.0002921,
0.000278,
0.0003384,
0.0003318,
0.0003284,
0.0003283,
0.0003289,
0.0003334,
0.000329,
0.0003302,
0.0003042,
0.000243,
0.000228,
0.0002212,
0.0002093,
0.0001879,
0.0001838,
0.0002004,
0.0002198,
0.000227,
0.0002997,
0.0003195,
0.0003081,
0.0002969,
0.0002921,
0.000278
]
},
"eauto_obj": {
@ -626,54 +666,54 @@
"initial_soc_percentage": 54
},
"start_solution": [
18.0,
18.0,
9.0,
13.0,
4.0,
7.0,
9.0,
8.0,
0.0,
12.0,
10.0,
10.0,
14.0,
8.0,
7.0,
11.0,
6.0,
4.0,
18.0,
3.0,
4.0,
3.0,
5.0,
14.0,
14.0,
10.0,
13.0,
3.0,
7.0,
11.0,
6.0,
14.0,
9.0,
14.0,
8.0,
3.0,
2.0,
5.0,
9.0,
19.0,
1.0,
6.0,
5.0,
19.0,
10.0,
4.0,
2.0,
19.0,
7.0,
17.0,
18.0,
3.0,
15.0,
4.0,
10.0,
2.0,
3.0,
11.0,
10.0
10.0,
5.0,
20.0,
2.0,
20.0,
11.0,
13.0,
11.0,
0.0,
1.0,
8.0,
4.0,
11.0,
8.0,
3.0,
0.0,
1.0,
12.0,
14.0,
13.0,
0.0,
13.0,
15.0,
12.0,
11.0,
17.0,
12.0,
3.0,
15.0,
18.0,
20.0,
7.0,
5.0
],
"washingstart": null
}

View File

@ -1,47 +1,47 @@
{
"ac_charge": [
0.5,
0.0,
0.0,
0.0,
0.0,
0.75,
0.0,
0.5,
0.0,
1.0,
0.0,
0.0,
0.75,
0.75,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.75,
0.0,
0.0,
0.0,
0.0,
0.0,
0.625,
0.0,
0.0,
0.0,
0.0,
0.625,
0.0,
0.375,
0.0,
0.0,
0.75,
0.0,
0.75,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.75,
0.0,
0.0,
0.0,
@ -101,17 +101,15 @@
],
"discharge_allowed": [
0,
0,
1,
1,
0,
0,
1,
1,
1,
0,
1,
0,
1,
0,
0,
0,
1,
0,
0,
@ -124,15 +122,14 @@
1,
1,
1,
1,
1,
0,
1,
1,
0,
0,
0,
1,
1,
1,
0,
0,
0,
@ -141,76 +138,79 @@
0,
0,
1,
1,
0,
0,
1,
0,
0,
0,
1,
0,
0,
0
],
"eautocharge_hours_float": [
0.0,
0.5,
0.0,
0.5,
0.375,
1.0,
0.875,
0.375,
0.5,
1.0,
0.875,
0.875,
0.875,
0.75,
0.5,
0.625,
0.875,
0.75,
0.5,
0.0,
0.625,
0.5,
0.0,
1.0,
0.625,
0.0,
1.0,
0.625,
0.875,
0.375,
1.0,
0.375,
0.625,
0.75,
0.75,
0.0,
0.5,
0.875,
0.875,
0.75,
0.875,
0.5,
0.375,
0.75,
0.875,
0.625,
0.375,
0.5,
0.375,
0.0,
0.875,
0.5,
0.75,
0.625,
0.875,
0.0,
0.375,
0.875,
1.0,
0.5
0.5,
0.625,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"result": {
"Last_Wh_pro_Stunde": [
12105.07,
10240.91,
10497.56,
12748.03,
8907.67,
13981.82,
4986.07,
1063.91,
14247.56,
12626.029999999999,
11529.67,
7731.82,
10393.22,
1730.78,
1129.12,
1178.71,
1103.78,
6373.12,
7733.71,
1050.98,
988.56,
912.38,
@ -221,7 +221,7 @@
608.79,
556.31,
488.89,
506.91,
4256.91,
804.89,
1141.98,
1056.97,
@ -231,8 +231,8 @@
1257.98,
1232.67,
871.26,
860.88,
4027.009545454555,
3985.88,
1158.03,
1222.72,
1221.04,
949.99,
@ -241,44 +241,44 @@
592.97
],
"EAuto_SoC_pro_Stunde": [
20.294999999999998,
11.555,
11.555,
26.85,
35.589999999999996,
50.885000000000005,
63.995000000000005,
72.735,
48.699999999999996,
59.62499999999999,
74.92,
74.92,
83.66,
98.955,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0
94.585,
94.585,
94.585,
94.585,
94.585,
94.585,
94.585,
94.585,
94.585,
94.585,
94.585,
94.585,
94.585,
94.585,
94.585,
94.585,
94.585,
94.585,
94.585,
94.585,
94.585,
94.585,
94.585,
94.585,
94.585,
94.585,
94.585,
94.585,
94.585
],
"Einnahmen_Euro_pro_Stunde": [
0.0,
@ -313,24 +313,24 @@
0.0,
0.0,
0.0,
0.0348376,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0
],
"Gesamt_Verluste": 8823.859090909093,
"Gesamtbilanz_Euro": 12.348447740818184,
"Gesamteinnahmen_Euro": 0.0348376,
"Gesamtkosten_Euro": 12.383285340818183,
"Gesamt_Verluste": 9258.73062020124,
"Gesamtbilanz_Euro": 12.332782378812306,
"Gesamteinnahmen_Euro": 0.0,
"Gesamtkosten_Euro": 12.332782378812306,
"Home_appliance_wh_per_hour": [
0.0,
0.0,
0.0,
2500.0,
2500.0,
0.0,
2500.0,
2500.0,
0.0,
0.0,
0.0,
@ -365,16 +365,16 @@
0.0
],
"Kosten_Euro_pro_Stunde": [
2.54785212,
0.928522392,
0.9189986259999999,
2.1770732859999997,
0.53097063,
1.6959351,
0.0,
0.004569992000000018,
2.750373626,
2.1541494859999997,
1.0128942300000001,
0.0,
1.4118501319999999,
0.0,
0.0,
0.0,
0.55162953,
0.0,
0.0,
0.0,
@ -385,36 +385,36 @@
0.199865757,
0.182970359,
0.162995926,
0.0,
0.0,
0.0,
1.4005233899999998,
0.26411047,
0.24530383800000005,
0.08545095,
0.007989913613567745,
0.028255713342252034,
0.025392879919306634,
0.0,
0.0,
0.0003442778967139274,
0.6945180797975209,
0.0,
0.0,
0.0,
0.0,
0.0,
0.651258356818184,
0.0,
0.04565364324294593,
0.08231598,
0.174597189,
0.293043269,
0.0,
0.214398479,
0.16484566
],
"Netzbezug_Wh_pro_Stunde": [
11174.789999999999,
4197.66,
4390.82,
11586.34,
2888.8500000000004,
8462.75,
0.0,
20.660000000000082,
13140.82,
11464.339999999998,
5510.85,
0.0,
6423.339999999999,
0.0,
0.0,
0.0,
1726.54,
0.0,
0.0,
0.0,
@ -425,23 +425,23 @@
608.79,
556.31,
488.89,
0.0,
0.0,
0.0,
4256.91,
799.85,
806.3900000000001,
351.65,
35.04348076126204,
127.73830624887898,
121.32288542430308,
0.0,
0.0,
1.7179535764168035,
3159.7728835192033,
0.0,
0.0,
0.0,
0.0,
0.0,
2868.979545454555,
0.0,
152.3311419517715,
257.64,
566.69,
987.01,
0.0,
733.99,
592.97
],
"Netzeinspeisung_Wh_pro_Stunde": [
@ -477,7 +477,7 @@
0.0,
0.0,
0.0,
497.68000000000006,
0.0,
0.0,
0.0,
0.0,
@ -485,16 +485,16 @@
0.0
],
"Verluste_Pro_Stunde": [
708.0,
1164.818181818182,
1164.818181818182,
864.0,
276.0,
795.0,
760.062272727273,
0.0,
933.0,
726.0,
414.0,
646.7386363636365,
483.0,
187.4616000000001,
97.67399999999998,
23.391818181818195,
230.91336797704525,
880.0977272727268,
1026.818181818182,
99.72409090909093,
133.72909090909081,
124.41545454545451,
@ -505,64 +505,104 @@
0.0,
0.0,
0.0,
69.12409090909085,
109.0704545454546,
109.96227272727276,
450.0,
0.0,
15.439199999999985,
53.855999999999995,
159.6443999999999,
21.032399999999996,
538.2984000000001,
441.924,
260.0003999999999,
514.2491454545468,
0.0,
0.0,
11.233982308648535,
38.52740325013451,
145.08565374908358,
21.962728535423857,
538.2984000000038,
441.7178455708299,
630.8276539776955,
171.99990368477063,
41.441862965787436,
0.0,
0.0,
0.0,
0.0,
100.08954545454549,
0.0
],
"akku_soc_pro_stunde": [
86.25,
64.72796143250687,
43.20592286501377,
55.70592286501377,
55.70592286501377,
68.20592286501376,
68.20592286501376,
72.49652286501377,
75.20968953168044,
74.47131143250688,
71.32345502754819,
67.10220847107436,
63.17495296143248,
60.14202424242422,
60.14202424242422,
56.40558312672175,
53.41686067493111,
53.41686067493111,
53.41686067493111,
53.41686067493111,
51.23491336088152,
47.792032851239654,
44.3210015151515,
44.3210015151515,
44.749868181818165,
46.24586818181816,
50.68043484848482,
51.264668181818166,
66.21740151515148,
78.49306818181815,
85.71530151515148,
100.0,
100.0,
100.0,
100.0,
100.0,
96.84060778236915,
96.84060778236915
62.54222623966943,
62.54222623966943,
75.04222623966943,
87.54222623966943,
87.54222623966943,
78.01764807162535,
78.01764807162535,
83.83265434833275,
64.76391295714818,
43.24187438965506,
40.094017984696386,
35.87277142822256,
31.945515918580686,
28.912587199572425,
28.912587199572425,
25.176146083869945,
22.187423632079316,
22.187423632079316,
22.187423632079316,
22.187423632079316,
34.68742363207931,
34.68742363207931,
34.68742363207931,
34.68742363207931,
34.99947869620843,
36.0696843420455,
40.099841390631155,
40.249843096950585,
55.20257643028218,
67.47251658502745,
84.99550697329678,
88.77022785443704,
89.9213907145978,
89.9213907145978,
89.9213907145978,
89.9213907145978,
89.9213907145978,
89.9213907145978
],
"Electricity_price": [
0.000228,
0.0002212,
0.0002093,
0.0001879,
0.0001838,
0.0002004,
0.0002198,
0.000227,
0.0002997,
0.0003195,
0.0003081,
0.0002969,
0.0002921,
0.000278,
0.0003384,
0.0003318,
0.0003284,
0.0003283,
0.0003289,
0.0003334,
0.000329,
0.0003302,
0.0003042,
0.000243,
0.000228,
0.0002212,
0.0002093,
0.0001879,
0.0001838,
0.0002004,
0.0002198,
0.000227,
0.0002997,
0.0003195,
0.0003081,
0.0002969,
0.0002921,
0.000278
]
},
"eauto_obj": {
@ -671,107 +711,107 @@
"capacity_wh": 60000,
"charging_efficiency": 0.95,
"max_charge_power_w": 11040,
"soc_wh": 60000.0,
"soc_wh": 56751.0,
"initial_soc_percentage": 5
},
"start_solution": [
0.0,
4.0,
16.0,
13.0,
17.0,
14.0,
12.0,
9.0,
9.0,
17.0,
13.0,
15.0,
12.0,
9.0,
18.0,
14.0,
18.0,
14.0,
9.0,
2.0,
8.0,
10.0,
12.0,
10.0,
10.0,
14.0,
8.0,
7.0,
2.0,
6.0,
4.0,
7.0,
10.0,
8.0,
2.0,
5.0,
0.0,
2.0,
4.0,
5.0,
14.0,
10.0,
18.0,
11.0,
14.0,
2.0,
18.0,
3.0,
16.0,
4.0,
20.0,
12.0,
2.0,
18.0,
18.0,
1.0,
0.0,
5.0,
13.0,
1.0,
0.0,
2.0,
0.0,
2.0,
1.0,
6.0,
5.0,
1.0,
2.0,
6.0,
5.0,
5.0,
5.0,
4.0,
7.0,
9.0,
8.0,
10.0,
12.0,
10.0,
10.0,
14.0,
8.0,
7.0,
2.0,
6.0,
4.0,
18.0,
3.0,
4.0,
3.0,
5.0,
14.0,
14.0,
10.0,
13.0,
3.0,
17.0,
11.0,
6.0,
14.0,
14.0,
14.0,
2.0,
3.0,
5.0,
4.0,
2.0,
0.0,
3.0,
2.0,
0.0,
6.0,
3.0,
0.0,
6.0,
3.0,
5.0,
2.0,
1.0,
6.0,
1.0,
3.0,
4.0,
4.0,
0.0,
2.0,
5.0,
5.0,
4.0,
5.0,
3.0,
1.0,
2.0,
1.0,
0.0,
5.0,
2.0,
4.0,
3.0,
5.0,
0.0,
1.0,
5.0,
6.0,
2.0,
14.0
3.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
13.0
],
"washingstart": 14
"washingstart": 13
}

View File

@ -1,16 +1,16 @@
{
"ac_charge": [
0.0,
0.0,
0.875,
0.0,
1.0,
0.0,
0.0,
0.0,
0.375,
0.0,
0.875,
0.0,
0.375,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
@ -102,21 +102,33 @@
"discharge_allowed": [
1,
0,
0,
1,
0,
0,
0,
1,
1,
0,
1,
0,
0,
1,
0,
0,
1,
0,
0,
1,
0,
0,
1,
1,
1,
1,
1,
1,
1,
1,
1,
1,
0,
1,
1,
1,
@ -134,46 +146,34 @@
1,
1,
1,
0,
1,
0,
1,
1,
0,
1,
0,
1,
1,
1,
1,
1,
1
],
"eautocharge_hours_float": [
0.75,
0.75,
0.5,
0.0,
1.0,
0.625,
0.0,
0.875,
0.75,
1.0,
0.0,
0.75,
1.0,
1.0,
1.0,
0.875,
0.375,
0.0,
1.0,
0.75,
0.5,
0.5,
1.0,
0.625,
0.875,
0.0,
0.375,
0.5,
0.75,
0.375,
0.0,
0.5,
0.625,
1.0,
0.625,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
@ -201,15 +201,15 @@
],
"result": {
"Last_Wh_pro_Stunde": [
1053.07,
6297.07,
8929.91,
11808.56,
11620.03,
14151.67,
7609.82,
9082.22,
6347.78,
1756.12,
5253.5599999999995,
3632.0299999999997,
8907.67,
7731.82,
11704.22,
7658.78,
1129.12,
1178.71,
1050.98,
988.56,
@ -241,44 +241,44 @@
592.97
],
"EAuto_SoC_pro_Stunde": [
5.0,
18.11,
35.589999999999996,
13.74,
26.85,
33.405,
33.405,
42.144999999999996,
53.06999999999999,
70.55,
77.105,
90.215,
98.955,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0,
100.0
81.475,
81.475,
81.475,
81.475,
81.475,
81.475,
81.475,
81.475,
81.475,
81.475,
81.475,
81.475,
81.475,
81.475,
81.475,
81.475,
81.475,
81.475,
81.475,
81.475,
81.475,
81.475,
81.475,
81.475,
81.475,
81.475,
81.475,
81.475,
81.475,
81.475,
81.475
],
"Einnahmen_Euro_pro_Stunde": [
0.0,
@ -320,17 +320,17 @@
0.0,
0.0
],
"Gesamt_Verluste": 7248.648818181819,
"Gesamtbilanz_Euro": 8.568052366,
"Gesamt_Verluste": 6757.733989740087,
"Gesamtbilanz_Euro": 6.952642478544519,
"Gesamteinnahmen_Euro": 0.0,
"Gesamtkosten_Euro": 8.568052366,
"Gesamtkosten_Euro": 6.952642478544519,
"Home_appliance_wh_per_hour": [
0.0,
0.0,
0.0,
2500.0,
2500.0,
0.0,
2500.0,
2500.0,
0.0,
0.0,
0.0,
@ -365,18 +365,14 @@
0.0
],
"Kosten_Euro_pro_Stunde": [
0.0,
1.22362812,
1.7445291920000001,
2.2398909259999997,
1.9651220859999998,
1.4948178300000001,
0.0,
1.1236923319999998,
0.0,
0.0,
0.0,
0.0,
0.0,
0.4641768859999999,
0.53097063,
0.0,
1.7000079319999999,
1.0534661399999998,
0.0,
0.0,
0.0,
@ -387,10 +383,14 @@
0.0,
0.0,
0.0,
0.182970359,
0.0,
0.0,
0.0,
0.0,
0.0326838476973626,
0.007989913613567745,
0.012219458233588555,
0.0,
0.0,
0.0,
@ -405,18 +405,14 @@
0.0
],
"Netzbezug_Wh_pro_Stunde": [
0.0,
5366.79,
7886.66,
10701.82,
10458.34,
8132.85,
0.0,
5112.339999999999,
0.0,
0.0,
0.0,
0.0,
0.0,
2470.3399999999997,
2888.8500000000004,
0.0,
7734.339999999999,
4640.82,
0.0,
0.0,
0.0,
@ -427,10 +423,14 @@
0.0,
0.0,
0.0,
556.31,
0.0,
0.0,
0.0,
0.0,
134.50143085334403,
35.04348076126204,
55.24167375040034,
0.0,
0.0,
0.0,
@ -485,15 +485,15 @@
0.0
],
"Verluste_Pro_Stunde": [
16.744090909090914,
276.0,
414.0,
772.4754545454543,
0.0,
276.0,
646.7386363636365,
552.0,
552.0,
552.0,
492.1022727272725,
414.0,
730.0663636363638,
55.434,
345.0,
101.0335466817773,
23.391818181818195,
99.72409090909093,
133.72909090909081,
@ -503,21 +503,21 @@
118.37045454545455,
94.68272727272722,
83.01681818181817,
75.86045454545456,
0.0,
66.66681818181814,
69.12409090909085,
109.0704545454546,
109.96227272727276,
47.952272727272714,
15.439199999999985,
53.855999999999995,
159.6443999999999,
21.032399999999996,
538.2984000000001,
441.924,
260.0003999999999,
169.97160000000008,
59.721600000000024,
29.61116851999853,
11.233982308648535,
48.41330768174524,
161.62968357967037,
21.962728535423857,
538.2984000000038,
441.95211196761403,
260.56941082122324,
171.99990368477063,
62.214291413756285,
35.132727272727266,
77.27590909090907,
134.59227272727276,
@ -525,44 +525,84 @@
80.85954545454547
],
"akku_soc_pro_stunde": [
79.4714617768595,
79.4714617768595,
79.4714617768595,
79.4714617768595,
79.4714617768595,
70.47202134986226,
70.47202134986226,
56.13911845730028,
56.76228512396694,
56.02390702479339,
52.876050619834714,
48.654804063360885,
44.72754855371902,
41.69461983471075,
39.47195282369147,
35.73551170798899,
32.746789256198355,
30.126308884297526,
27.731723829201112,
25.627341942148767,
23.445394628099184,
20.002514118457306,
16.531482782369153,
15.017837809917364,
15.446704476584031,
16.94270447658403,
21.377271143250695,
21.961504476584032,
36.91423780991737,
49.189904476584026,
56.41213780991736,
61.133571143250684,
62.79250447658402,
61.68351687327823,
59.2442520661157,
54.99575860881543,
51.836366391184576,
49.28398174931129
80.0,
80.0,
62.150396005509634,
62.150396005509634,
62.150396005509634,
52.62581783746556,
52.62581783746556,
52.62581783746556,
53.77091326251142,
53.03253516333787,
49.884678758379195,
45.663432201905366,
41.73617669226349,
38.70324797325523,
36.48058096223595,
32.74413984653347,
29.75541739474284,
27.134937022842013,
27.134937022842013,
25.030555135789673,
22.848607821740085,
19.405727312098207,
15.934695976010055,
15.0,
15.312055064129126,
16.07020564583707,
19.578139530578447,
19.728141236897873,
34.68087457022947,
46.94341995234899,
53.90006700591099,
57.67478788705125,
58.17025540478875,
57.06126780148296,
54.622002994320425,
50.373509537020155,
47.214117319389295,
44.661732677516014
],
"Electricity_price": [
0.000228,
0.0002212,
0.0002093,
0.0001879,
0.0001838,
0.0002004,
0.0002198,
0.000227,
0.0002997,
0.0003195,
0.0003081,
0.0002969,
0.0002921,
0.000278,
0.0003384,
0.0003318,
0.0003284,
0.0003283,
0.0003289,
0.0003334,
0.000329,
0.0003302,
0.0003042,
0.000243,
0.000228,
0.0002212,
0.0002093,
0.0001879,
0.0001838,
0.0002004,
0.0002198,
0.000227,
0.0002997,
0.0003195,
0.0003081,
0.0002969,
0.0002921,
0.000278
]
},
"eauto_obj": {
@ -671,82 +711,76 @@
"capacity_wh": 60000,
"charging_efficiency": 0.95,
"max_charge_power_w": 11040,
"soc_wh": 60000.0,
"soc_wh": 48885.0,
"initial_soc_percentage": 5
},
"start_solution": [
12.0,
7.0,
4.0,
11.0,
15.0,
13.0,
19.0,
9.0,
20.0,
14.0,
6.0,
9.0,
8.0,
19.0,
7.0,
2.0,
2.0,
1.0,
3.0,
8.0,
14.0,
15.0,
5.0,
11.0,
10.0,
1.0,
2.0,
8.0,
1.0,
2.0,
13.0,
14.0,
1.0,
9.0,
7.0,
9.0,
10.0,
12.0,
11.0,
13.0,
11.0,
12.0,
8.0,
13.0,
13.0,
7.0,
7.0,
6.0,
13.0,
7.0,
7.0,
10.0,
10.0,
11.0,
12.0,
9.0,
9.0,
11.0,
13.0,
7.0,
11.0,
9.0,
10.0,
10.0,
11.0,
10.0,
8.0,
7.0,
13.0,
11.0,
8.0,
3.0,
5.0,
5.0,
1.0,
7.0,
2.0,
11.0,
11.0,
14.0,
11.0,
5.0,
10.0,
9.0,
13.0,
10.0,
9.0,
8.0,
4.0,
4.0,
2.0,
0.0,
6.0,
3.0,
0.0,
5.0,
4.0,
6.0,
0.0,
4.0,
6.0,
6.0,
6.0,
1.0,
2.0,
4.0,
1.0,
0.0,
2.0,
2.0,
6.0,
3.0,
5.0,
3.0,
6.0,
3.0,
0.0,
0.0,
0.0,
@ -771,7 +805,13 @@
0.0,
0.0,
0.0,
14.0
0.0,
0.0,
0.0,
0.0,
0.0,
0.0,
13.0
],
"washingstart": 14
"washingstart": 13
}