diff --git a/modules/class_eauto.py b/modules/class_eauto.py index a1e04af..97030fa 100644 --- a/modules/class_eauto.py +++ b/modules/class_eauto.py @@ -30,8 +30,9 @@ class EAuto: return for moeglich in self.laden_moeglich: - if moeglich == 1 and self.soc < 100: - geladene_energie = min(self.ladegeschwindigkeit, (100 - self.soc) / 100 * self.akku_kapazitaet) + if moeglich > 0.0 and self.soc < 100: + # Berechnung der geladenen Energie basierend auf dem Anteil der Lademöglichkeit + geladene_energie = min(self.ladegeschwindigkeit * moeglich, (100 - self.soc) / 100 * self.akku_kapazitaet) self.soc += geladene_energie / self.akku_kapazitaet * 100 self.soc = min(100, self.soc) self.stuendliche_last.append(geladene_energie) @@ -42,6 +43,24 @@ class EAuto: # Umwandlung der stündlichen Last in ein NumPy-Array self.stuendliche_last = np.array(self.stuendliche_last) + # def berechne_ladevorgang(self): + # if self.laden_moeglich is None: + # print("Lademöglichkeit wurde nicht gesetzt.") + # return + + # for moeglich in self.laden_moeglich: + # if moeglich > 1 and self.soc < 100: + # geladene_energie = min(self.ladegeschwindigkeit, (100 - self.soc) / 100 * self.akku_kapazitaet) + # self.soc += geladene_energie / self.akku_kapazitaet * 100 + # self.soc = min(100, self.soc) + # self.stuendliche_last.append(geladene_energie) + # else: + # self.stuendliche_last.append(0) # Keine Ladung in dieser Stunde + # self.stuendlicher_soc.append(self.soc) + + # # Umwandlung der stündlichen Last in ein NumPy-Array + # self.stuendliche_last = np.array(self.stuendliche_last) + def get_stuendliche_last(self): """Gibt das NumPy-Array mit der stündlichen Last zurück.""" return self.stuendliche_last diff --git a/modules/class_load_container.py b/modules/class_load_container.py index c6add76..d251c9c 100644 --- a/modules/class_load_container.py +++ b/modules/class_load_container.py @@ -4,9 +4,10 @@ import numpy as np from pprint import pprint class Gesamtlast: - def __init__(self): + def __init__(self, prediction_hours=24): self.lasten = {} # Enthält Namen und Lasten-Arrays für verschiedene Quellen - + self.prediction_hours=prediction_hours + def hinzufuegen(self, name, last_array): """ Fügt ein Array von Lasten für eine bestimmte Quelle hinzu. @@ -14,8 +15,11 @@ class Gesamtlast: :param name: Name der Lastquelle (z.B. "Haushalt", "Wärmepumpe") :param last_array: Array von Lasten, wobei jeder Eintrag einer Stunde entspricht """ + if(len(last_array) != self.prediction_hours): + raise ValueError(f"Gesamtlast Inkonsistente Längen bei den Arrays: ", name," ", len(last_array) ) self.lasten[name] = last_array + def gesamtlast_berechnen(self): """ Berechnet die gesamte Last für jede Stunde und gibt ein Array der Gesamtlasten zurück. diff --git a/modules/visualize.py b/modules/visualize.py index a1d4a27..6ae5f12 100644 --- a/modules/visualize.py +++ b/modules/visualize.py @@ -63,11 +63,11 @@ def visualisiere_ergebnisse(gesamtlast,leistung_haushalt,leistung_wp, pv_forecas ax1 = plt.subplot(3, 2, 5) for hour, value in enumerate(discharge_hours): - if value == 1: - ax1.axvspan(hour, hour+1, color='red', alpha=0.3, label='Entlademöglichkeit' if hour == 0 else "") + #if value == 1: + ax1.axvspan(hour, hour+1, color='red',ymax=value, alpha=0.3, label='Entlademöglichkeit' if hour == 0 else "") for hour, value in enumerate(laden_moeglich): - if value == 1: - ax1.axvspan(hour, hour+1, color='green', alpha=0.3, label='Lademöglichkeit' if hour == 0 else "") + #if value == 1: + ax1.axvspan(hour, hour+1, color='green',ymax=value, alpha=0.3, label='Lademöglichkeit' if hour == 0 else "") ax1.legend(loc='upper left') diff --git a/test.py b/test.py index e8e0f1c..72420c8 100644 --- a/test.py +++ b/test.py @@ -37,7 +37,7 @@ discharge_array = np.full(prediction_hours,1) #np.array([1, 0, 1, 0, 1, 1, 1, 1, laden_moeglich = np.full(prediction_hours,1) # np.array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0]) #np.full(prediction_hours,1) eauto = EAuto(soc=10, capacity = 60000, power_charge = 7000, load_allowed = laden_moeglich) -min_soc_eauto = 20 +min_soc_eauto = 100 hohe_strafe = 10.0 @@ -102,13 +102,18 @@ o = ems.simuliere(0)#ems.simuliere_ab_jetzt() # Optimierung -# Fitness-Funktion (muss Ihre EnergieManagementSystem-Logik integrieren) -def evaluate(individual): +def evaluate_inner(individual): + #print(individual) + discharge_hours_bin = individual[0::2] + eautocharge_hours_float = individual[1::2] + + #print(discharge_hours_bin) + #print(len(eautocharge_hours_float)) ems.reset() eauto.reset() - ems.set_akku_discharge_hours(individual[:prediction_hours]) + ems.set_akku_discharge_hours(discharge_hours_bin) - eauto.set_laden_moeglich(individual[prediction_hours:]) + eauto.set_laden_moeglich(eautocharge_hours_float) eauto.berechne_ladevorgang() leistung_eauto = eauto.get_stuendliche_last() gesamtlast.hinzufuegen("eauto", leistung_eauto) @@ -116,6 +121,11 @@ def evaluate(individual): ems.set_gesamtlast(gesamtlast.gesamtlast_berechnen()) o = ems.simuliere(0) + return o, eauto + +# Fitness-Funktion (muss Ihre EnergieManagementSystem-Logik integrieren) +def evaluate(individual): + o,eauto = evaluate_inner(individual) gesamtbilanz = o["Gesamtbilanz_Euro"] # Überprüfung, ob der Mindest-SoC erreicht wird @@ -124,20 +134,25 @@ def evaluate(individual): #if final_soc < min_soc_eauto: # Fügt eine Strafe hinzu, wenn der Mindest-SoC nicht erreicht wird strafe = max(0,(min_soc_eauto - final_soc) * hohe_strafe ) # `hohe_strafe` ist ein vorher festgelegter Strafwert - gesamtbilanz += strafe - #if strafe > 0.0: - # print(min_soc_eauto," - ",final_soc,"*10 = ",strafe) - + gesamtbilanz += strafe return (gesamtbilanz,) + + + # Werkzeug-Setup creator.create("FitnessMin", base.Fitness, weights=(-1.0,)) creator.create("Individual", list, fitness=creator.FitnessMin) toolbox = base.Toolbox() + toolbox.register("attr_bool", random.randint, 0, 1) -toolbox.register("individual", tools.initRepeat, creator.Individual, toolbox.attr_bool, prediction_hours*2) +toolbox.register("attr_bool", random.randint, 0, 1) +toolbox.register("individual", tools.initCycle, creator.Individual, (toolbox.attr_bool,toolbox.attr_bool), n=prediction_hours) + + + toolbox.register("population", tools.initRepeat, list, toolbox.individual) toolbox.register("evaluate", evaluate) @@ -155,31 +170,69 @@ def optimize(): stats.register("min", np.min) stats.register("max", np.max) - algorithms.eaSimple(population, toolbox, cxpb=0.4, mutpb=0.3, ngen=100, - stats=stats, halloffame=hof, verbose=True) + algorithms.eaMuPlusLambda(population, toolbox, 50, 100, cxpb=0.5, mutpb=0.5, ngen=500, stats=stats, halloffame=hof, verbose=True) + #algorithms.eaSimple(population, toolbox, cxpb=0.2, mutpb=0.2, ngen=1000, stats=stats, halloffame=hof, verbose=True) + return hof[0] + + +start_solution = optimize() + + +print("Start Lösung:", start_solution) + + + + +# Werkzeug-Setup +creator.create("FitnessMin", base.Fitness, weights=(-1.0,)) +creator.create("Individual", list, fitness=creator.FitnessMin) + +toolbox = base.Toolbox() + + + + +toolbox.register("attr_bool", random.randint, 0, 1) +toolbox.register("attr_float", random.uniform, 0.0, 1.0) +toolbox.register("individual", tools.initCycle, creator.Individual, (toolbox.attr_bool,toolbox.attr_float), n=prediction_hours) + +start_individual = toolbox.individual() +start_individual[:] = start_solution + +toolbox.register("population", tools.initRepeat, list, toolbox.individual) + +toolbox.register("evaluate", evaluate) +toolbox.register("mate", tools.cxTwoPoint) +toolbox.register("mutate", tools.mutFlipBit, indpb=0.05) +toolbox.register("select", tools.selTournament, tournsize=3) + +# Genetischer Algorithmus +def optimize(): + population = toolbox.population(n=1000) + population[0] = start_individual + hof = tools.HallOfFame(1) + + stats = tools.Statistics(lambda ind: ind.fitness.values) + stats.register("avg", np.mean) + stats.register("min", np.min) + stats.register("max", np.max) + + algorithms.eaMuPlusLambda(population, toolbox, 100, 200, cxpb=0.5, mutpb=0.2, ngen=1000, stats=stats, halloffame=hof, verbose=True) + #algorithms.eaSimple(population, toolbox, cxpb=0.2, mutpb=0.2, ngen=1000, stats=stats, halloffame=hof, verbose=True) return hof[0] best_solution = optimize() print("Beste Lösung:", best_solution) #ems.set_akku_discharge_hours(best_solution) -ems.reset() -eauto.reset() -ems.set_akku_discharge_hours(best_solution[:prediction_hours]) -eauto.set_laden_moeglich(best_solution[prediction_hours:]) -eauto.berechne_ladevorgang() -leistung_eauto = eauto.get_stuendliche_last() -gesamtlast.hinzufuegen("eauto", leistung_eauto) -ems.set_gesamtlast(gesamtlast.gesamtlast_berechnen()) - -o = ems.simuliere(0) +o,eauto = evaluate_inner(best_solution) soc_eauto = eauto.get_stuendlicher_soc() print(soc_eauto) pprint(o) pprint(eauto.get_stuendlicher_soc()) -visualisiere_ergebnisse(gesamtlast,leistung_haushalt,leistung_wp, pv_forecast, specific_date_prices, o,soc_eauto,best_solution[:prediction_hours],best_solution[prediction_hours:] ) +visualisiere_ergebnisse(gesamtlast,leistung_haushalt,leistung_wp, pv_forecast, specific_date_prices, o,soc_eauto,best_solution[0::2],best_solution[1::2] ) # for data in forecast.get_forecast_data():