mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2025-04-19 00:45:22 +00:00
First self consumption predictor only PV > load
This commit is contained in:
parent
c56d29f63d
commit
4e8e9bd0c0
@ -1,6 +1,9 @@
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from akkudoktoreos.devices.battery import PVAkku
|
||||
from akkudoktoreos.prediction.self_consumption_probability import (
|
||||
self_consumption_probability_interpolator,
|
||||
)
|
||||
|
||||
|
||||
class WechselrichterParameters(BaseModel):
|
||||
@ -8,11 +11,17 @@ class WechselrichterParameters(BaseModel):
|
||||
|
||||
|
||||
class Wechselrichter:
|
||||
def __init__(self, parameters: WechselrichterParameters, akku: PVAkku):
|
||||
def __init__(
|
||||
self,
|
||||
parameters: WechselrichterParameters,
|
||||
akku: PVAkku,
|
||||
self_consumption_predictor: self_consumption_probability_interpolator,
|
||||
):
|
||||
self.max_leistung_wh = (
|
||||
parameters.max_leistung_wh # Maximum power that the inverter can handle
|
||||
)
|
||||
self.akku = akku # Connection to a battery object
|
||||
self.self_consumption_predictor = self_consumption_predictor
|
||||
|
||||
def energie_verarbeiten(
|
||||
self, erzeugung: float, verbrauch: float, hour: int
|
||||
@ -21,7 +30,7 @@ class Wechselrichter:
|
||||
netzeinspeisung = 0.0 # Grid feed-in
|
||||
netzbezug = 0.0 # Grid draw
|
||||
eigenverbrauch = 0.0 # Self-consumption
|
||||
|
||||
aus_akku = 0.0
|
||||
if erzeugung >= verbrauch:
|
||||
if verbrauch > self.max_leistung_wh:
|
||||
# If consumption exceeds maximum inverter power
|
||||
@ -30,10 +39,14 @@ class Wechselrichter:
|
||||
netzbezug = -restleistung_nach_verbrauch # Negative indicates feeding into the grid
|
||||
eigenverbrauch = self.max_leistung_wh
|
||||
else:
|
||||
scr = self.self_consumption_predictor.calculate_self_consumption(
|
||||
verbrauch, erzeugung
|
||||
)
|
||||
|
||||
# Remaining power after consumption
|
||||
restleistung_nach_verbrauch = (erzeugung - verbrauch) * 0.95 # EVQ
|
||||
restleistung_nach_verbrauch = (erzeugung - verbrauch) * scr # EVQ
|
||||
# Remaining load Self Consumption not perfect
|
||||
restlast_evq = (erzeugung - verbrauch) * (1.0 - 0.95)
|
||||
restlast_evq = (erzeugung - verbrauch) * (1.0 - scr)
|
||||
|
||||
if restlast_evq > 0:
|
||||
# Akku muss den Restverbrauch decken
|
||||
|
@ -5,6 +5,7 @@ import numpy as np
|
||||
from deap import algorithms, base, creator, tools
|
||||
from pydantic import BaseModel, Field, field_validator, model_validator
|
||||
from typing_extensions import Self
|
||||
from pathlib import Path
|
||||
|
||||
from akkudoktoreos.config import AppConfig
|
||||
from akkudoktoreos.devices.battery import (
|
||||
@ -13,6 +14,9 @@ from akkudoktoreos.devices.battery import (
|
||||
PVAkku,
|
||||
PVAkkuParameters,
|
||||
)
|
||||
from akkudoktoreos.prediction.self_consumption_probability import (
|
||||
self_consumption_probability_interpolator,
|
||||
)
|
||||
from akkudoktoreos.devices.generic import HomeAppliance, HomeApplianceParameters
|
||||
from akkudoktoreos.devices.inverter import Wechselrichter, WechselrichterParameters
|
||||
from akkudoktoreos.prediction.ems import (
|
||||
@ -142,7 +146,7 @@ class optimization_problem:
|
||||
|
||||
# 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:
|
||||
@ -350,10 +354,10 @@ class optimization_problem:
|
||||
worst_case: bool,
|
||||
) -> Tuple[float]:
|
||||
"""Evaluate the fitness of an individual solution based on the simulation results."""
|
||||
try:
|
||||
o = self.evaluate_inner(individual, ems, start_hour)
|
||||
except Exception as e:
|
||||
return (100000.0,) # Return a high penalty in case of an exception
|
||||
# try:
|
||||
o = self.evaluate_inner(individual, ems, start_hour)
|
||||
# except Exception as e:
|
||||
# return (100000.0,) # Return a high penalty in case of an exception
|
||||
|
||||
gesamtbilanz = o["Gesamtbilanz_Euro"] * (-1.0 if worst_case else 1.0)
|
||||
|
||||
@ -443,13 +447,18 @@ class optimization_problem:
|
||||
parameters: OptimizationParameters,
|
||||
start_hour: int,
|
||||
worst_case: bool = False,
|
||||
ngen: int = 600,
|
||||
ngen: int = 200,
|
||||
) -> OptimizeResponse:
|
||||
"""Perform EMS (Energy Management System) optimization and visualize results."""
|
||||
einspeiseverguetung_euro_pro_wh = np.full(
|
||||
self.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 = PVAkku(
|
||||
parameters.pv_akku,
|
||||
@ -481,7 +490,11 @@ class optimization_problem:
|
||||
)
|
||||
|
||||
# Initialize the inverter and energy management system
|
||||
wr = Wechselrichter(parameters.wechselrichter, akku)
|
||||
wr = Wechselrichter(
|
||||
parameters.wechselrichter,
|
||||
akku,
|
||||
self_consumption_predictor=sc,
|
||||
)
|
||||
ems = EnergieManagementSystem(
|
||||
self._config.eos,
|
||||
parameters.ems,
|
||||
|
@ -10,9 +10,11 @@ class self_consumption_probability_interpolator:
|
||||
def __init__(self, filepath: str | Path):
|
||||
self.filepath = filepath
|
||||
self.interpolator = None
|
||||
print("OPEN")
|
||||
# Load the RegularGridInterpolator
|
||||
with open("regular_grid_interpolator.pkl", "rb") as file:
|
||||
interpolator = pickle.load(self.filepath)
|
||||
with open(self.filepath, "rb") as file:
|
||||
print("OPENED")
|
||||
self.interpolator = pickle.load(file)
|
||||
|
||||
def calculate_self_consumption(self, load_1h_power: float, pv_power: float) -> float:
|
||||
"""Calculate the PV self-consumption rate using RegularGridInterpolator.
|
||||
@ -29,11 +31,13 @@ class self_consumption_probability_interpolator:
|
||||
|
||||
# Get probabilities for all partial loads
|
||||
points = np.array([np.full_like(partial_loads, load_1h_power), partial_loads]).T
|
||||
probabilities = interpolator(points)
|
||||
if self.interpolator == None:
|
||||
return -1.0
|
||||
probabilities = self.interpolator(points)
|
||||
probabilities = probabilities / probabilities.sum()
|
||||
for i, w in enumerate(partial_loads):
|
||||
print(w, ": ", probabilities[i])
|
||||
print(probabilities.sum())
|
||||
# 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)
|
||||
|
||||
|
@ -48,7 +48,7 @@ app = FastAPI(
|
||||
working_dir = get_working_dir()
|
||||
# copy config to working directory. Make this a CLI option later
|
||||
config = load_config(working_dir, True)
|
||||
opt_class = optimization_problem(config)
|
||||
opt_class = optimization_problem(config, verbose=False)
|
||||
server_dir = Path(__file__).parent.resolve()
|
||||
|
||||
|
||||
@ -196,7 +196,7 @@ def fastapi_optimize(
|
||||
] = None,
|
||||
) -> OptimizeResponse:
|
||||
if start_hour is None:
|
||||
start_hour = datetime.now().hour
|
||||
start_hour = 10 # datetime.now().hour
|
||||
|
||||
# Perform optimization simulation
|
||||
result = opt_class.optimierung_ems(parameters=parameters, start_hour=start_hour)
|
||||
|
Loading…
x
Reference in New Issue
Block a user