mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2025-06-28 00:46:53 +00:00
EV Bugs
This commit is contained in:
parent
2b5f0ee53c
commit
cafed7eaca
@ -20,7 +20,7 @@ class PVAkku:
|
|||||||
self.soc_wh = (start_soc_prozent / 100) * kapazitaet_wh
|
self.soc_wh = (start_soc_prozent / 100) * kapazitaet_wh
|
||||||
self.hours = hours if hours is not None else 24 # Default to 24 hours if not specified
|
self.hours = hours if hours is not None else 24 # Default to 24 hours if not specified
|
||||||
self.discharge_array = np.full(self.hours, 1)
|
self.discharge_array = np.full(self.hours, 1)
|
||||||
self.charge_array = np.full(self.hours, 1)
|
self.charge_array = np.full(self.hours, 0)
|
||||||
# Charge and discharge efficiency
|
# Charge and discharge efficiency
|
||||||
self.lade_effizienz = lade_effizienz
|
self.lade_effizienz = lade_effizienz
|
||||||
self.entlade_effizienz = entlade_effizienz
|
self.entlade_effizienz = entlade_effizienz
|
||||||
@ -88,7 +88,7 @@ class PVAkku:
|
|||||||
# Ensure no simultaneous charging and discharging in the same hour using NumPy mask
|
# Ensure no simultaneous charging and discharging in the same hour using NumPy mask
|
||||||
conflict_mask = (self.charge_array > 0) & (self.discharge_array > 0)
|
conflict_mask = (self.charge_array > 0) & (self.discharge_array > 0)
|
||||||
# Prioritize discharge by setting charge to 0 where both are > 0
|
# Prioritize discharge by setting charge to 0 where both are > 0
|
||||||
self.charge_array[conflict_mask] = 0
|
self.discharge_array[conflict_mask] = 0
|
||||||
|
|
||||||
|
|
||||||
def ladezustand_in_prozent(self):
|
def ladezustand_in_prozent(self):
|
||||||
|
@ -92,9 +92,7 @@ class EnergieManagementSystem:
|
|||||||
|
|
||||||
# AC PV Battery Charge
|
# AC PV Battery Charge
|
||||||
if self.akku.charge_array[stunde] > 0.0:
|
if self.akku.charge_array[stunde] > 0.0:
|
||||||
#soc_pre = self.akku.ladezustand_in_prozent()
|
|
||||||
geladene_menge, verluste_wh = self.akku.energie_laden(None,stunde)
|
geladene_menge, verluste_wh = self.akku.energie_laden(None,stunde)
|
||||||
#print(self.akku.charge_array[stunde], " ",geladene_menge," ",soc_pre," ",self.akku.ladezustand_in_prozent())
|
|
||||||
verbrauch += geladene_menge
|
verbrauch += geladene_menge
|
||||||
verluste_wh_pro_stunde[stunde_since_now] += verluste_wh
|
verluste_wh_pro_stunde[stunde_since_now] += verluste_wh
|
||||||
|
|
||||||
|
@ -59,6 +59,43 @@ class optimization_problem:
|
|||||||
discharge = np.where(discharge_hours_bin > 0, discharge_hours_bin, 0)
|
discharge = np.where(discharge_hours_bin > 0, discharge_hours_bin, 0)
|
||||||
|
|
||||||
return charge, discharge
|
return charge, discharge
|
||||||
|
|
||||||
|
# Custom mutation function that applies type-specific mutations
|
||||||
|
def mutate(self,individual):
|
||||||
|
# Mutate the discharge state genes (-1, 0, 1)
|
||||||
|
individual[:self.prediction_hours], = self.toolbox.mutate_discharge(
|
||||||
|
individual[:self.prediction_hours]
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.optimize_ev:
|
||||||
|
# Mutate the EV charging indices
|
||||||
|
ev_charge_part = individual[self.prediction_hours : self.prediction_hours * 2]
|
||||||
|
ev_charge_part_mutated, = self.toolbox.mutate_ev_charge_index(ev_charge_part)
|
||||||
|
ev_charge_part_mutated[self.prediction_hours - self.fixed_eauto_hours :] = [0] * self.fixed_eauto_hours
|
||||||
|
individual[self.prediction_hours : self.prediction_hours * 2] = ev_charge_part_mutated
|
||||||
|
|
||||||
|
# Mutate the appliance start hour if present
|
||||||
|
if self.opti_param["haushaltsgeraete"] > 0:
|
||||||
|
appliance_part = [individual[-1]]
|
||||||
|
appliance_part_mutated, = self.toolbox.mutate_hour(appliance_part)
|
||||||
|
individual[-1] = appliance_part_mutated[0]
|
||||||
|
|
||||||
|
return (individual,)
|
||||||
|
|
||||||
|
# Method to create an individual based on the conditions
|
||||||
|
def create_individual(self):
|
||||||
|
# Start with discharge states for the individual
|
||||||
|
individual_components = [self.toolbox.attr_discharge_state() for _ in range(self.prediction_hours)]
|
||||||
|
|
||||||
|
# Add EV charge index values if optimize_ev is True
|
||||||
|
if self.optimize_ev:
|
||||||
|
individual_components += [self.toolbox.attr_ev_charge_index() for _ in range(self.prediction_hours)]
|
||||||
|
|
||||||
|
# Add the start time of the household appliance if it's being optimized
|
||||||
|
if self.opti_param["haushaltsgeraete"] > 0:
|
||||||
|
individual_components += [self.toolbox.attr_int()]
|
||||||
|
|
||||||
|
return creator.Individual(individual_components)
|
||||||
|
|
||||||
def split_individual(
|
def split_individual(
|
||||||
self, individual: List[float]
|
self, individual: List[float]
|
||||||
@ -100,43 +137,10 @@ class optimization_problem:
|
|||||||
self.toolbox.register("attr_ev_charge_index", random.randint, 0, len(possible_ev_charge_currents) - 1)
|
self.toolbox.register("attr_ev_charge_index", random.randint, 0, len(possible_ev_charge_currents) - 1)
|
||||||
self.toolbox.register("attr_int", random.randint, start_hour, 23)
|
self.toolbox.register("attr_int", random.randint, start_hour, 23)
|
||||||
|
|
||||||
# Function to create an individual based on the conditions
|
|
||||||
def create_individual():
|
|
||||||
# Start with discharge states for the individual
|
|
||||||
individual_components = [self.toolbox.attr_discharge_state() for _ in range(self.prediction_hours)]
|
|
||||||
|
|
||||||
# Add EV charge index values if optimize_ev is True
|
|
||||||
if self.optimize_ev:
|
|
||||||
individual_components += [self.toolbox.attr_ev_charge_index() for _ in range(self.prediction_hours)]
|
|
||||||
|
|
||||||
# Add the start time of the household appliance if it's being optimized
|
|
||||||
if self.opti_param["haushaltsgeraete"] > 0:
|
|
||||||
individual_components += [self.toolbox.attr_int()]
|
|
||||||
|
|
||||||
return creator.Individual(individual_components)
|
|
||||||
|
|
||||||
# Register individual creation function
|
# Register individual creation function
|
||||||
self.toolbox.register("individual", create_individual)
|
self.toolbox.register("individual", self.create_individual)
|
||||||
|
|
||||||
|
|
||||||
# # Register individual creation method based on household appliance parameter
|
|
||||||
# if opti_param["haushaltsgeraete"] > 0:
|
|
||||||
# self.toolbox.register(
|
|
||||||
# "individual",
|
|
||||||
# lambda: creator.Individual(
|
|
||||||
# [self.toolbox.attr_discharge_state() for _ in range(self.prediction_hours)]
|
|
||||||
# + [self.toolbox.attr_ev_charge_index() for _ in range(self.prediction_hours)]
|
|
||||||
# + [self.toolbox.attr_int()]
|
|
||||||
# ),
|
|
||||||
# )
|
|
||||||
# else:
|
|
||||||
# self.toolbox.register(
|
|
||||||
# "individual",
|
|
||||||
# lambda: creator.Individual(
|
|
||||||
# [self.toolbox.attr_discharge_state() for _ in range(self.prediction_hours)]
|
|
||||||
# + [self.toolbox.attr_ev_charge_index() for _ in range(self.prediction_hours)]
|
|
||||||
# ),
|
|
||||||
# )
|
|
||||||
|
|
||||||
# Register population, mating, mutation, and selection functions
|
# Register population, mating, mutation, and selection functions
|
||||||
self.toolbox.register("population", tools.initRepeat, list, self.toolbox.individual)
|
self.toolbox.register("population", tools.initRepeat, list, self.toolbox.individual)
|
||||||
@ -150,32 +154,8 @@ class optimization_problem:
|
|||||||
# - Start hour mutation for household devices
|
# - Start hour mutation for household devices
|
||||||
self.toolbox.register("mutate_hour", tools.mutUniformInt, low=start_hour, up=23, indpb=0.1)
|
self.toolbox.register("mutate_hour", tools.mutUniformInt, low=start_hour, up=23, indpb=0.1)
|
||||||
|
|
||||||
# Custom mutation function that applies type-specific mutations
|
|
||||||
def mutate(individual):
|
|
||||||
# Mutate the discharge state genes (-1, 0, 1)
|
|
||||||
individual[:self.prediction_hours], = self.toolbox.mutate_discharge(
|
|
||||||
individual[:self.prediction_hours]
|
|
||||||
)
|
|
||||||
|
|
||||||
if self.optimize_ev:
|
|
||||||
# Mutate the EV charging indices
|
|
||||||
ev_charge_part = individual[self.prediction_hours : self.prediction_hours * 2]
|
|
||||||
ev_charge_part_mutated, = self.toolbox.mutate_ev_charge_index(ev_charge_part)
|
|
||||||
ev_charge_part_mutated[self.prediction_hours - self.fixed_eauto_hours :] = [0] * self.fixed_eauto_hours
|
|
||||||
individual[self.prediction_hours : self.prediction_hours * 2] = ev_charge_part_mutated
|
|
||||||
|
|
||||||
# Mutate the appliance start hour if present
|
|
||||||
if self.opti_param["haushaltsgeraete"] > 0:
|
|
||||||
appliance_part = [individual[-1]]
|
|
||||||
appliance_part_mutated, = self.toolbox.mutate_hour(appliance_part)
|
|
||||||
individual[-1] = appliance_part_mutated[0]
|
|
||||||
|
|
||||||
return (individual,)
|
|
||||||
|
|
||||||
|
|
||||||
# Register custom mutation function
|
# Register custom mutation function
|
||||||
self.toolbox.register("mutate", mutate)
|
self.toolbox.register("mutate", self.mutate)
|
||||||
|
|
||||||
|
|
||||||
self.toolbox.register("select", tools.selTournament, tournsize=3)
|
self.toolbox.register("select", tools.selTournament, tournsize=3)
|
||||||
|
|
||||||
@ -198,13 +178,13 @@ class optimization_problem:
|
|||||||
|
|
||||||
ems.set_akku_discharge_hours(discharge)
|
ems.set_akku_discharge_hours(discharge)
|
||||||
ems.set_akku_charge_hours(charge)
|
ems.set_akku_charge_hours(charge)
|
||||||
#print(charge)
|
|
||||||
|
|
||||||
eautocharge_hours_float = [
|
|
||||||
possible_ev_charge_currents[i] for i in eautocharge_hours_index
|
|
||||||
]
|
|
||||||
if self.optimize_ev:
|
if self.optimize_ev:
|
||||||
|
eautocharge_hours_float = [
|
||||||
|
possible_ev_charge_currents[i] for i in eautocharge_hours_index
|
||||||
|
]
|
||||||
ems.set_eauto_charge_hours(eautocharge_hours_float)
|
ems.set_eauto_charge_hours(eautocharge_hours_float)
|
||||||
|
|
||||||
return ems.simuliere(start_hour)
|
return ems.simuliere(start_hour)
|
||||||
|
|
||||||
def evaluate(
|
def evaluate(
|
||||||
@ -226,7 +206,6 @@ class optimization_problem:
|
|||||||
gesamtbilanz = o["Gesamtbilanz_Euro"] * (-1.0 if worst_case else 1.0)
|
gesamtbilanz = o["Gesamtbilanz_Euro"] * (-1.0 if worst_case else 1.0)
|
||||||
|
|
||||||
discharge_hours_bin, eautocharge_hours_float, _ = self.split_individual(individual)
|
discharge_hours_bin, eautocharge_hours_float, _ = self.split_individual(individual)
|
||||||
#max_ladeleistung = np.max(possible_ev_charge_currents)
|
|
||||||
|
|
||||||
# Small Penalty for not discharging
|
# Small Penalty for not discharging
|
||||||
gesamtbilanz += sum(
|
gesamtbilanz += sum(
|
||||||
|
@ -160,39 +160,39 @@ def visualisiere_ergebnisse(
|
|||||||
plt.grid(True, which="both", axis="x") # Grid for every hour
|
plt.grid(True, which="both", axis="x") # Grid for every hour
|
||||||
|
|
||||||
ax1 = plt.subplot(3, 2, 3)
|
ax1 = plt.subplot(3, 2, 3)
|
||||||
# Plot für die discharge_hours-Werte
|
# Plot charge and discharge values
|
||||||
for hour, value in enumerate(discharge_hours):
|
for hour, value in enumerate(discharge_hours):
|
||||||
# Festlegen der Farbe und des Labels basierend auf dem Wert
|
# Determine color and label based on the value
|
||||||
if value > 0: # Positive Werte (Entladung)
|
if value > 0: # Positive values (discharge)
|
||||||
color = "red"
|
color = "red"
|
||||||
label = "Discharge" if hour == 0 else "" # Label nur beim ersten Eintrag hinzufügen
|
label = "Discharge" if hour == 0 else ""
|
||||||
elif value < 0: # Negative Werte (Ladung)
|
elif value < 0: # Negative values (charge)
|
||||||
color = "blue"
|
color = "blue"
|
||||||
label = "Charge" if hour == 0 else ""
|
label = "Charge" if hour == 0 else ""
|
||||||
else:
|
|
||||||
continue # Überspringe 0-Werte
|
|
||||||
|
|
||||||
# Erstellen der Farbbereiche mit `axvspan`
|
else:
|
||||||
|
continue # Skip zero values
|
||||||
|
|
||||||
|
# Create colored areas with `axvspan`
|
||||||
ax1.axvspan(
|
ax1.axvspan(
|
||||||
hour, # Start der Stunde
|
hour, # Start of the hour
|
||||||
hour + 1, # Ende der Stunde
|
hour + 1, # End of the hour
|
||||||
ymin=0, # Untere Grenze
|
ymin=0, # Lower bound
|
||||||
ymax=abs(value), # Obere Grenze: abs(value), um die Höhe richtig darzustellen
|
ymax=abs(value) / 5 if value < 0 else value, # Adjust height based on the value
|
||||||
color=color,
|
color=color,
|
||||||
alpha=0.3,
|
alpha=0.3,
|
||||||
label=label
|
label=label
|
||||||
)
|
)
|
||||||
|
|
||||||
# Annotieren der Werte in der Mitte des Farbbereichs
|
|
||||||
ax1.text(
|
# Configure the plot
|
||||||
hour + 0.5, # In der Mitte des Bereichs
|
ax1.legend(loc="upper left")
|
||||||
abs(value) / 2, # In der Mitte der Höhe
|
ax1.set_xlim(0, prediction_hours)
|
||||||
f'{value:.2f}', # Wert mit zwei Dezimalstellen
|
ax1.set_xlabel("Hour")
|
||||||
ha='center',
|
ax1.set_ylabel("Charge/Discharge Level")
|
||||||
va='center',
|
ax1.set_title("Charge and Discharge Hours Overview")
|
||||||
fontsize=8,
|
ax1.grid(True)
|
||||||
color='black'
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
pdf.savefig() # Save the current figure state to the PDF
|
pdf.savefig() # Save the current figure state to the PDF
|
||||||
|
Loading…
x
Reference in New Issue
Block a user