EV possible currents -> Work now (new Mutate Function)

-> Some Penalties are removed (deprecated)
AC Charge -> Parameter in Optimization -1,0,1
-> Missing integration in class_ems
This commit is contained in:
Andreas 2024-10-11 10:47:29 +02:00 committed by Andreas
parent e65eb6b6dd
commit 6881710295
4 changed files with 72 additions and 26 deletions

View File

@ -1,6 +1,7 @@
#!/usr/bin/env python3
import json
import time
# Import necessary modules from the project
from akkudoktoreos.class_optimize import optimization_problem
@ -241,7 +242,7 @@ parameter = {
# Electricity price forecast (48 hours)
"strompreis_euro_pro_wh": strompreis_euro_pro_wh,
# Minimum SOC for electric car
"eauto_min_soc": 80,
"eauto_min_soc": 20,
# Electric car battery capacity (Wh)
"eauto_cap": 60000,
# Charging efficiency of the electric car
@ -262,6 +263,9 @@ parameter = {
"min_soc_prozent": 15,
}
# Startzeit nehmen
start_time = time.time()
# Initialize the optimization problem
opt_class = optimization_problem(
prediction_hours=48, strafe=10, optimization_hours=24, verbose=True, fixed_seed=42
@ -270,8 +274,16 @@ opt_class = optimization_problem(
# Perform the optimisation based on the provided parameters and start hour
ergebnis = opt_class.optimierung_ems(parameter=parameter, start_hour=start_hour)
# Endzeit nehmen
end_time = time.time()
# Berechnete Zeit ausgeben
elapsed_time = end_time - start_time
print(f"Elapsed time: {elapsed_time:.4f} seconds")
# Print or visualize the result
# pprint(ergebnis)
json_data = json.dumps(ergebnis)
print(json_data)
#json_data = json.dumps(ergebnis)
#print(json_data)

View File

@ -84,7 +84,7 @@ class PVAkku:
return (self.soc_wh / self.kapazitaet_wh) * 100
def energie_abgeben(self, wh, hour):
if self.discharge_array[hour] == 0:
if self.discharge_array[hour] == 0 and self.discharge_array[hour] == -1:
return 0.0, 0.0 # No energy discharge and no losses
# Calculate the maximum energy that can be discharged considering min_soc and efficiency

View File

@ -28,6 +28,7 @@ class EnergieManagementSystem:
self.akku.set_discharge_per_hour(ds)
def set_eauto_charge_hours(self, ds: List[int]) -> None:
self.eauto.set_charge_per_hour(ds)
def set_haushaltsgeraet_start(self, ds: List[int], global_start_hour: int = 0) -> None:

View File

@ -39,7 +39,7 @@ class optimization_problem:
) -> Tuple[List[int], List[float], Optional[int]]:
"""
Split the individual solution into its components:
1. Discharge hours (binary),
1. Discharge hours (-1 (Charge),0 (Nothing),1 (Discharge)),
2. Electric vehicle charge hours (float),
3. Dishwasher start time (integer if applicable).
"""
@ -69,8 +69,8 @@ class optimization_problem:
# Initialize toolbox with attributes and operations
self.toolbox = base.Toolbox()
self.toolbox.register("attr_bool", random.randint, 0, 1)
self.toolbox.register("attr_float", random.uniform, 0, 1)
self.toolbox.register("attr_discharge_state", random.randint, -1, 1)
self.toolbox.register("attr_ev_charge_index", random.randint, 0, len(moegliche_ladestroeme_in_prozent) - 1)
self.toolbox.register("attr_int", random.randint, start_hour, 23)
# Register individual creation method based on household appliance parameter
@ -78,8 +78,8 @@ class optimization_problem:
self.toolbox.register(
"individual",
lambda: creator.Individual(
[self.toolbox.attr_bool() for _ in range(self.prediction_hours)]
+ [self.toolbox.attr_float() for _ in range(self.prediction_hours)]
[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()]
),
)
@ -87,15 +87,48 @@ class optimization_problem:
self.toolbox.register(
"individual",
lambda: creator.Individual(
[self.toolbox.attr_bool() for _ in range(self.prediction_hours)]
+ [self.toolbox.attr_float() for _ in range(self.prediction_hours)]
[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
self.toolbox.register("population", tools.initRepeat, list, self.toolbox.individual)
self.toolbox.register("mate", tools.cxTwoPoint)
self.toolbox.register("mutate", tools.mutFlipBit, indpb=0.1)
#self.toolbox.register("mutate", tools.mutFlipBit, indpb=0.1)
# Register separate mutation functions for each type of value:
# - Discharge state mutation (-1, 0, 1)
self.toolbox.register("mutate_discharge", tools.mutUniformInt, low=0, up=1, indpb=0.1)
# - Float mutation for EV charging values
self.toolbox.register("mutate_ev_charge_index", tools.mutUniformInt, low=0, up=len(moegliche_ladestroeme_in_prozent) - 1, indpb=0.1)
# - Start hour mutation for household devices
self.toolbox.register("mutate_hour", tools.mutUniformInt, low=start_hour, up=23, indpb=0.3)
# 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]
)
# 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)
individual[self.prediction_hours : self.prediction_hours * 2] = ev_charge_part_mutated
# Mutate the appliance start hour if present
if len(individual) > self.prediction_hours * 2:
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
self.toolbox.register("mutate", mutate)
self.toolbox.register("select", tools.selTournament, tournsize=3)
def evaluate_inner(
@ -106,16 +139,22 @@ class optimization_problem:
using the provided individual solution.
"""
ems.reset()
discharge_hours_bin, eautocharge_hours_float, spuelstart_int = self.split_individual(
discharge_hours_bin, eautocharge_hours_index, spuelstart_int = self.split_individual(
individual
)
if self.opti_param.get("haushaltsgeraete", 0) > 0:
ems.set_haushaltsgeraet_start(spuelstart_int, global_start_hour=start_hour)
ems.set_akku_discharge_hours(discharge_hours_bin)
eautocharge_hours_float[self.prediction_hours - self.fixed_eauto_hours :] = [
0.0
eautocharge_hours_index[self.prediction_hours - self.fixed_eauto_hours :] = [
0
] * self.fixed_eauto_hours
eautocharge_hours_float = [
moegliche_ladestroeme_in_prozent[i] for i in eautocharge_hours_index
]
ems.set_eauto_charge_hours(eautocharge_hours_float)
return ems.simuliere(start_hour)
@ -134,16 +173,17 @@ class optimization_problem:
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)
discharge_hours_bin, eautocharge_hours_float, _ = self.split_individual(individual)
max_ladeleistung = np.max(moegliche_ladestroeme_in_prozent)
# Penalty for not discharging
# Small Penalty for not discharging
gesamtbilanz += sum(
0.01 for i in range(self.prediction_hours) if discharge_hours_bin[i] == 0.0
)
# Penalty for charging the electric vehicle during restricted hours
gesamtbilanz += sum(
self.strafe
@ -151,13 +191,6 @@ class optimization_problem:
if eautocharge_hours_float[i] != 0.0
)
# Penalty for exceeding maximum charge power
gesamtbilanz += sum(
self.strafe * 10
for ladeleistung in eautocharge_hours_float
if ladeleistung > max_ladeleistung
)
# 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(
@ -205,7 +238,7 @@ class optimization_problem:
self.toolbox,
mu=100,
lambda_=200,
cxpb=0.5,
cxpb=0.7,
mutpb=0.3,
ngen=ngen,
stats=stats,