From 7adf3d336ab7f82f82d70fe94b2bfc0fb63ac03d Mon Sep 17 00:00:00 2001 From: Andreas Date: Thu, 17 Oct 2024 10:32:24 +0200 Subject: [PATCH] AC /DC / Discharge optimzation - First try (not finished yet) --- src/akkudoktoreos/class_ems.py | 9 +++++--- src/akkudoktoreos/class_optimize.py | 29 +++++++++++++------------ src/akkudoktoreos/visualize.py | 9 ++++++-- src/akkudoktoreosserver/flask_server.py | 7 +++--- 4 files changed, 32 insertions(+), 22 deletions(-) diff --git a/src/akkudoktoreos/class_ems.py b/src/akkudoktoreos/class_ems.py index 33dd05a..94c33a2 100644 --- a/src/akkudoktoreos/class_ems.py +++ b/src/akkudoktoreos/class_ems.py @@ -25,6 +25,7 @@ class EnergieManagementSystem: self.wechselrichter = wechselrichter self.ac_charge_hours = np.full(prediction_hours,0) self.dc_charge_hours = np.full(prediction_hours,1) + self.ev_charge_hours = np.full(prediction_hours,0) def set_akku_discharge_hours(self, ds: List[int]) -> None: self.akku.set_discharge_per_hour(ds) @@ -35,8 +36,8 @@ class EnergieManagementSystem: def set_akku_dc_charge_hours(self, ds: np.ndarray) -> None: self.dc_charge_hours = ds - def set_eauto_charge_hours(self, ds: List[int]) -> None: - self.eauto.set_charge_per_hour(ds) + def set_ev_charge_hours(self, ds: List[int]) -> None: + self.ev_charge_hours = ds def set_haushaltsgeraet_start(self, ds: List[int], global_start_hour: int = 0) -> None: self.haushaltsgeraet.set_startzeitpunkt(ds, global_start_hour=global_start_hour) @@ -95,7 +96,9 @@ class EnergieManagementSystem: # E-Auto handling if self.eauto: - geladene_menge_eauto, verluste_eauto = self.eauto.energie_laden(None, stunde) + geladene_menge_eauto, verluste_eauto = self.eauto.energie_laden(None, stunde, relative_power=self.ev_charge_hours[stunde]) + # if self.ev_charge_hours[stunde] > 0.0: + # print(self.ev_charge_hours[stunde], " ", geladene_menge_eauto," ", self.eauto.ladezustand_in_prozent()) verbrauch += geladene_menge_eauto verluste_wh_pro_stunde[stunde_since_now] += verluste_eauto eauto_soc_pro_stunde[stunde_since_now] = self.eauto.ladezustand_in_prozent() diff --git a/src/akkudoktoreos/class_optimize.py b/src/akkudoktoreos/class_optimize.py index fbf2906..80b610d 100644 --- a/src/akkudoktoreos/class_optimize.py +++ b/src/akkudoktoreos/class_optimize.py @@ -241,8 +241,9 @@ class optimization_problem: eautocharge_hours_float = [ possible_ev_charge_currents[i] for i in eautocharge_hours_index ] - ems.set_eauto_charge_hours(eautocharge_hours_float) - + ems.set_ev_charge_hours(eautocharge_hours_float) + #else: + # ems.set_ev_charge_hours(np.full(self.prediction_hours, 0 )) return ems.simuliere(start_hour) def evaluate( @@ -271,10 +272,10 @@ class optimization_problem: ) # Penalty for not meeting the minimum SOC (State of Charge) requirement - if parameter["eauto_min_soc"] - ems.eauto.ladezustand_in_prozent() <= 0.0: - gesamtbilanz += sum( - self.strafe for ladeleistung in eautocharge_hours_float if ladeleistung != 0.0 - ) + # if parameter["eauto_min_soc"] - ems.eauto.ladezustand_in_prozent() <= 0.0 and self.optimize_ev: + # gesamtbilanz += sum( + # self.strafe for ladeleistung in eautocharge_hours_float if ladeleistung != 0.0 + # ) individual.extra_data = ( o["Gesamtbilanz_Euro"], @@ -284,13 +285,13 @@ class optimization_problem: # Adjust total balance with battery value and penalties for unmet SOC restwert_akku = ems.akku.aktueller_energieinhalt() * parameter["preis_euro_pro_wh_akku"] - gesamtbilanz += ( - max( - 0, - (parameter["eauto_min_soc"] - ems.eauto.ladezustand_in_prozent()) * self.strafe, - ) - - restwert_akku - ) + gesamtbilanz += -restwert_akku + if self.optimize_ev: + gesamtbilanz += max( + 0, + (parameter["eauto_min_soc"] - ems.eauto.ladezustand_in_prozent()) * self.strafe, + ) + return (gesamtbilanz,) @@ -342,7 +343,7 @@ class optimization_problem: worst_case: bool = False, startdate: Optional[Any] = None, # startdate is not used! *, - ngen: int = 400, + ngen: int = 600, ) -> Dict[str, Any]: """ Perform EMS (Energy Management System) optimization and visualize results. diff --git a/src/akkudoktoreos/visualize.py b/src/akkudoktoreos/visualize.py index ea64c52..eab5feb 100644 --- a/src/akkudoktoreos/visualize.py +++ b/src/akkudoktoreos/visualize.py @@ -164,9 +164,11 @@ def visualisiere_ergebnisse( plt.legend(loc="upper left", bbox_to_anchor=(1, 1)) # Place legend outside the plot plt.grid(True, which="both", axis="x") # Grid for every hour + + # Plot for AC, DC charging, and Discharge status using bar charts ax1 = plt.subplot(3, 2, 5) - + hours = np.arange(0, prediction_hours) # Plot AC charging as bars (relative values between 0 and 1) plt.bar(hours, ac, width=0.4, label="AC Charging (relative)", color="blue", alpha=0.6) @@ -185,7 +187,10 @@ def visualisiere_ergebnisse( ax1.grid(True) - + if ist_dst_wechsel(datetime.datetime.now()): + hours = np.arange(start_hour, prediction_hours - 1) + else: + hours = np.arange(start_hour, prediction_hours) pdf.savefig() # Save the current figure state to the PDF diff --git a/src/akkudoktoreosserver/flask_server.py b/src/akkudoktoreosserver/flask_server.py index 4544a15..570ad82 100755 --- a/src/akkudoktoreosserver/flask_server.py +++ b/src/akkudoktoreosserver/flask_server.py @@ -17,6 +17,7 @@ from akkudoktoreos.class_load_container import Gesamtlast from akkudoktoreos.class_load_corrector import LoadPredictionAdjuster from akkudoktoreos.class_optimize import optimization_problem from akkudoktoreos.class_pv_forecast import PVForecast +from akkudoktoreos.class_numpy_encoder import * from akkudoktoreos.class_strompreis import HourlyElectricityPriceForecast from akkudoktoreos.config import ( get_start_enddate, @@ -28,7 +29,7 @@ from akkudoktoreos.config import ( app = Flask(__name__) opt_class = optimization_problem( - prediction_hours=prediction_hours, strafe=10, optimization_hours=optimization_hours + prediction_hours=prediction_hours, strafe=10, optimization_hours=optimization_hours, verbose=True ) @@ -248,9 +249,9 @@ def flask_optimize(): # Perform optimization simulation result = opt_class.optimierung_ems(parameter=parameter, start_hour=datetime.now().hour) - print(result) + #print(result) # convert to JSON (None accepted by dumps) - return jsonify(result) + return NumpyEncoder.dumps(result) @app.route("/visualization_results.pdf")