mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2025-06-27 16:36:53 +00:00
EV Charge Parameters optional + AC Charge first try (Parameter Reduction)
This commit is contained in:
parent
6881710295
commit
2b5f0ee53c
@ -70,21 +70,32 @@ class PVAkku:
|
|||||||
self.soc_wh = min(max(self.soc_wh, self.min_soc_wh), self.max_soc_wh)
|
self.soc_wh = min(max(self.soc_wh, self.min_soc_wh), self.max_soc_wh)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
def set_discharge_per_hour(self, discharge_array):
|
def set_discharge_per_hour(self, discharge_array):
|
||||||
assert len(discharge_array) == self.hours
|
assert len(discharge_array) == self.hours
|
||||||
self.discharge_array = np.array(discharge_array)
|
self.discharge_array = np.array(discharge_array)
|
||||||
|
|
||||||
|
# Ensure no simultaneous charging and discharging in the same hour using NumPy mask
|
||||||
|
conflict_mask = (self.charge_array > 0) & (self.discharge_array > 0)
|
||||||
|
# Prioritize discharge by setting charge to 0 where both are > 0
|
||||||
|
self.charge_array[conflict_mask] = 0
|
||||||
|
|
||||||
def set_charge_per_hour(self, charge_array):
|
def set_charge_per_hour(self, charge_array):
|
||||||
assert len(charge_array) == self.hours
|
assert len(charge_array) == self.hours
|
||||||
self.charge_array = np.array(charge_array)
|
self.charge_array = np.array(charge_array)
|
||||||
|
|
||||||
|
# Ensure no simultaneous charging and discharging in the same hour using NumPy mask
|
||||||
|
conflict_mask = (self.charge_array > 0) & (self.discharge_array > 0)
|
||||||
|
# Prioritize discharge by setting charge to 0 where both are > 0
|
||||||
|
self.charge_array[conflict_mask] = 0
|
||||||
|
|
||||||
|
|
||||||
def ladezustand_in_prozent(self):
|
def ladezustand_in_prozent(self):
|
||||||
return (self.soc_wh / self.kapazitaet_wh) * 100
|
return (self.soc_wh / self.kapazitaet_wh) * 100
|
||||||
|
|
||||||
def energie_abgeben(self, wh, hour):
|
def energie_abgeben(self, wh, hour):
|
||||||
if self.discharge_array[hour] == 0 and self.discharge_array[hour] == -1:
|
if self.discharge_array[hour] == 0 :
|
||||||
return 0.0, 0.0 # No energy discharge and no losses
|
return 0.0, 0.0 # No energy discharge and no losses
|
||||||
|
|
||||||
# Calculate the maximum energy that can be discharged considering min_soc and efficiency
|
# Calculate the maximum energy that can be discharged considering min_soc and efficiency
|
||||||
|
@ -27,8 +27,10 @@ class EnergieManagementSystem:
|
|||||||
def set_akku_discharge_hours(self, ds: List[int]) -> None:
|
def set_akku_discharge_hours(self, ds: List[int]) -> None:
|
||||||
self.akku.set_discharge_per_hour(ds)
|
self.akku.set_discharge_per_hour(ds)
|
||||||
|
|
||||||
|
def set_akku_charge_hours(self, ds: List[int]) -> None:
|
||||||
|
self.akku.set_charge_per_hour(ds)
|
||||||
|
|
||||||
def set_eauto_charge_hours(self, ds: List[int]) -> None:
|
def set_eauto_charge_hours(self, ds: List[int]) -> None:
|
||||||
|
|
||||||
self.eauto.set_charge_per_hour(ds)
|
self.eauto.set_charge_per_hour(ds)
|
||||||
|
|
||||||
def set_haushaltsgeraet_start(self, ds: List[int], global_start_hour: int = 0) -> None:
|
def set_haushaltsgeraet_start(self, ds: List[int], global_start_hour: int = 0) -> None:
|
||||||
@ -69,7 +71,7 @@ class EnergieManagementSystem:
|
|||||||
akku_soc_pro_stunde[0] = self.akku.ladezustand_in_prozent()
|
akku_soc_pro_stunde[0] = self.akku.ladezustand_in_prozent()
|
||||||
if self.eauto:
|
if self.eauto:
|
||||||
eauto_soc_pro_stunde[0] = self.eauto.ladezustand_in_prozent()
|
eauto_soc_pro_stunde[0] = self.eauto.ladezustand_in_prozent()
|
||||||
|
|
||||||
for stunde in range(start_stunde + 1, ende):
|
for stunde in range(start_stunde + 1, ende):
|
||||||
stunde_since_now = stunde - start_stunde
|
stunde_since_now = stunde - start_stunde
|
||||||
|
|
||||||
@ -88,6 +90,14 @@ class EnergieManagementSystem:
|
|||||||
verluste_wh_pro_stunde[stunde_since_now] += verluste_eauto
|
verluste_wh_pro_stunde[stunde_since_now] += verluste_eauto
|
||||||
eauto_soc_pro_stunde[stunde_since_now] = self.eauto.ladezustand_in_prozent()
|
eauto_soc_pro_stunde[stunde_since_now] = self.eauto.ladezustand_in_prozent()
|
||||||
|
|
||||||
|
# AC PV Battery Charge
|
||||||
|
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)
|
||||||
|
#print(self.akku.charge_array[stunde], " ",geladene_menge," ",soc_pre," ",self.akku.ladezustand_in_prozent())
|
||||||
|
verbrauch += geladene_menge
|
||||||
|
verluste_wh_pro_stunde[stunde_since_now] += verluste_wh
|
||||||
|
|
||||||
# Process inverter logic
|
# Process inverter logic
|
||||||
erzeugung = self.pv_prognose_wh[stunde]
|
erzeugung = self.pv_prognose_wh[stunde]
|
||||||
netzeinspeisung, netzbezug, verluste, eigenverbrauch = (
|
netzeinspeisung, netzbezug, verluste, eigenverbrauch = (
|
||||||
|
@ -8,7 +8,7 @@ from akkudoktoreos.class_akku import PVAkku
|
|||||||
from akkudoktoreos.class_ems import EnergieManagementSystem
|
from akkudoktoreos.class_ems import EnergieManagementSystem
|
||||||
from akkudoktoreos.class_haushaltsgeraet import Haushaltsgeraet
|
from akkudoktoreos.class_haushaltsgeraet import Haushaltsgeraet
|
||||||
from akkudoktoreos.class_inverter import Wechselrichter
|
from akkudoktoreos.class_inverter import Wechselrichter
|
||||||
from akkudoktoreos.config import moegliche_ladestroeme_in_prozent
|
from akkudoktoreos.config import possible_ev_charge_currents
|
||||||
from akkudoktoreos.visualize import visualisiere_ergebnisse
|
from akkudoktoreos.visualize import visualisiere_ergebnisse
|
||||||
|
|
||||||
|
|
||||||
@ -26,21 +26,47 @@ class optimization_problem:
|
|||||||
self.strafe = strafe
|
self.strafe = strafe
|
||||||
self.opti_param = None
|
self.opti_param = None
|
||||||
self.fixed_eauto_hours = prediction_hours - optimization_hours
|
self.fixed_eauto_hours = prediction_hours - optimization_hours
|
||||||
self.possible_charge_values = moegliche_ladestroeme_in_prozent
|
self.possible_charge_values = possible_ev_charge_currents
|
||||||
self.verbose = verbose
|
self.verbose = verbose
|
||||||
self.fix_seed = fixed_seed
|
self.fix_seed = fixed_seed
|
||||||
|
self.optimize_ev = True
|
||||||
|
|
||||||
# Set a fixed seed for random operations if provided
|
# Set a fixed seed for random operations if provided
|
||||||
if fixed_seed is not None:
|
if fixed_seed is not None:
|
||||||
random.seed(fixed_seed)
|
random.seed(fixed_seed)
|
||||||
|
|
||||||
|
def split_charge_discharge(self, discharge_hours_bin: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
|
||||||
|
"""
|
||||||
|
Split the input array `discharge_hours_bin` into two separate arrays:
|
||||||
|
- `charge`: Contains only the negative values from `discharge_hours_bin` (charging values).
|
||||||
|
- `discharge`: Contains only the positive values from `discharge_hours_bin` (discharging values).
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
- discharge_hours_bin (np.ndarray): Input array with both positive and negative values.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
- charge (np.ndarray): Array with negative values from `discharge_hours_bin`, other values set to 0.
|
||||||
|
- discharge (np.ndarray): Array with positive values from `discharge_hours_bin`, other values set to 0.
|
||||||
|
"""
|
||||||
|
# Convert the input list to a NumPy array, if it's not already
|
||||||
|
discharge_hours_bin = np.array(discharge_hours_bin)
|
||||||
|
|
||||||
|
# Create charge array: Keep only negative values, set the rest to 0
|
||||||
|
charge = -np.where(discharge_hours_bin < 0, discharge_hours_bin, 0)
|
||||||
|
charge = charge / np.max(charge)
|
||||||
|
|
||||||
|
# Create discharge array: Keep only positive values, set the rest to 0
|
||||||
|
discharge = np.where(discharge_hours_bin > 0, discharge_hours_bin, 0)
|
||||||
|
|
||||||
|
return charge, discharge
|
||||||
|
|
||||||
def split_individual(
|
def split_individual(
|
||||||
self, individual: List[float]
|
self, individual: List[float]
|
||||||
) -> Tuple[List[int], List[float], Optional[int]]:
|
) -> Tuple[List[int], List[float], Optional[int]]:
|
||||||
"""
|
"""
|
||||||
Split the individual solution into its components:
|
Split the individual solution into its components:
|
||||||
1. Discharge hours (-1 (Charge),0 (Nothing),1 (Discharge)),
|
1. Discharge hours (-1 (Charge),0 (Nothing),1 (Discharge)),
|
||||||
2. Electric vehicle charge hours (float),
|
2. Electric vehicle charge hours (possible_charge_values),
|
||||||
3. Dishwasher start time (integer if applicable).
|
3. Dishwasher start time (integer if applicable).
|
||||||
"""
|
"""
|
||||||
discharge_hours_bin = individual[: self.prediction_hours]
|
discharge_hours_bin = individual[: self.prediction_hours]
|
||||||
@ -69,40 +95,60 @@ class optimization_problem:
|
|||||||
|
|
||||||
# Initialize toolbox with attributes and operations
|
# Initialize toolbox with attributes and operations
|
||||||
self.toolbox = base.Toolbox()
|
self.toolbox = base.Toolbox()
|
||||||
self.toolbox.register("attr_discharge_state", random.randint, -1, 1)
|
self.toolbox.register("attr_discharge_state", random.randint, -5, 1)
|
||||||
self.toolbox.register("attr_ev_charge_index", random.randint, 0, len(moegliche_ladestroeme_in_prozent) - 1)
|
if self.optimize_ev:
|
||||||
|
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)
|
||||||
|
|
||||||
# Register individual creation method based on household appliance parameter
|
# Function to create an individual based on the conditions
|
||||||
if opti_param["haushaltsgeraete"] > 0:
|
def create_individual():
|
||||||
self.toolbox.register(
|
# Start with discharge states for the individual
|
||||||
"individual",
|
individual_components = [self.toolbox.attr_discharge_state() for _ in range(self.prediction_hours)]
|
||||||
lambda: creator.Individual(
|
|
||||||
[self.toolbox.attr_discharge_state() for _ in range(self.prediction_hours)]
|
# Add EV charge index values if optimize_ev is True
|
||||||
+ [self.toolbox.attr_ev_charge_index() for _ in range(self.prediction_hours)]
|
if self.optimize_ev:
|
||||||
+ [self.toolbox.attr_int()]
|
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
|
||||||
else:
|
if self.opti_param["haushaltsgeraete"] > 0:
|
||||||
self.toolbox.register(
|
individual_components += [self.toolbox.attr_int()]
|
||||||
"individual",
|
|
||||||
lambda: creator.Individual(
|
return creator.Individual(individual_components)
|
||||||
[self.toolbox.attr_discharge_state() for _ in range(self.prediction_hours)]
|
|
||||||
+ [self.toolbox.attr_ev_charge_index() for _ in range(self.prediction_hours)]
|
# Register individual creation function
|
||||||
),
|
self.toolbox.register("individual", 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)
|
||||||
self.toolbox.register("mate", tools.cxTwoPoint)
|
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:
|
# Register separate mutation functions for each type of value:
|
||||||
# - Discharge state mutation (-1, 0, 1)
|
# - Discharge state mutation (-5, 0, 1)
|
||||||
self.toolbox.register("mutate_discharge", tools.mutUniformInt, low=0, up=1, indpb=0.1)
|
self.toolbox.register("mutate_discharge", tools.mutUniformInt, low=-5, up=1, indpb=0.1)
|
||||||
# - Float mutation for EV charging values
|
# - 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)
|
self.toolbox.register("mutate_ev_charge_index", tools.mutUniformInt, low=0, up=len(possible_ev_charge_currents) - 1, indpb=0.1)
|
||||||
# - 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.3)
|
self.toolbox.register("mutate_hour", tools.mutUniformInt, low=start_hour, up=23, indpb=0.1)
|
||||||
|
|
||||||
# Custom mutation function that applies type-specific mutations
|
# Custom mutation function that applies type-specific mutations
|
||||||
def mutate(individual):
|
def mutate(individual):
|
||||||
@ -111,13 +157,15 @@ class optimization_problem:
|
|||||||
individual[:self.prediction_hours]
|
individual[:self.prediction_hours]
|
||||||
)
|
)
|
||||||
|
|
||||||
# Mutate the EV charging indices
|
if self.optimize_ev:
|
||||||
ev_charge_part = individual[self.prediction_hours : self.prediction_hours * 2]
|
# Mutate the EV charging indices
|
||||||
ev_charge_part_mutated, = self.toolbox.mutate_ev_charge_index(ev_charge_part)
|
ev_charge_part = individual[self.prediction_hours : self.prediction_hours * 2]
|
||||||
individual[self.prediction_hours : self.prediction_hours * 2] = ev_charge_part_mutated
|
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
|
# Mutate the appliance start hour if present
|
||||||
if len(individual) > self.prediction_hours * 2:
|
if self.opti_param["haushaltsgeraete"] > 0:
|
||||||
appliance_part = [individual[-1]]
|
appliance_part = [individual[-1]]
|
||||||
appliance_part_mutated, = self.toolbox.mutate_hour(appliance_part)
|
appliance_part_mutated, = self.toolbox.mutate_hour(appliance_part)
|
||||||
individual[-1] = appliance_part_mutated[0]
|
individual[-1] = appliance_part_mutated[0]
|
||||||
@ -145,17 +193,18 @@ class optimization_problem:
|
|||||||
if self.opti_param.get("haushaltsgeraete", 0) > 0:
|
if self.opti_param.get("haushaltsgeraete", 0) > 0:
|
||||||
ems.set_haushaltsgeraet_start(spuelstart_int, global_start_hour=start_hour)
|
ems.set_haushaltsgeraet_start(spuelstart_int, global_start_hour=start_hour)
|
||||||
|
|
||||||
ems.set_akku_discharge_hours(discharge_hours_bin)
|
charge, discharge = self.split_charge_discharge(discharge_hours_bin)
|
||||||
eautocharge_hours_index[self.prediction_hours - self.fixed_eauto_hours :] = [
|
|
||||||
0
|
|
||||||
] * self.fixed_eauto_hours
|
ems.set_akku_discharge_hours(discharge)
|
||||||
|
ems.set_akku_charge_hours(charge)
|
||||||
|
#print(charge)
|
||||||
|
|
||||||
eautocharge_hours_float = [
|
eautocharge_hours_float = [
|
||||||
moegliche_ladestroeme_in_prozent[i] for i in eautocharge_hours_index
|
possible_ev_charge_currents[i] for i in eautocharge_hours_index
|
||||||
]
|
]
|
||||||
|
if self.optimize_ev:
|
||||||
|
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(
|
||||||
@ -177,7 +226,7 @@ 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(moegliche_ladestroeme_in_prozent)
|
#max_ladeleistung = np.max(possible_ev_charge_currents)
|
||||||
|
|
||||||
# Small Penalty for not discharging
|
# Small Penalty for not discharging
|
||||||
gesamtbilanz += sum(
|
gesamtbilanz += sum(
|
||||||
@ -185,11 +234,11 @@ class optimization_problem:
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Penalty for charging the electric vehicle during restricted hours
|
# Penalty for charging the electric vehicle during restricted hours
|
||||||
gesamtbilanz += sum(
|
# gesamtbilanz += sum(
|
||||||
self.strafe
|
# self.strafe
|
||||||
for i in range(self.prediction_hours - self.fixed_eauto_hours, self.prediction_hours)
|
# for i in range(self.prediction_hours - self.fixed_eauto_hours, self.prediction_hours)
|
||||||
if eautocharge_hours_float[i] != 0.0
|
# if eautocharge_hours_float[i] != 0.0
|
||||||
)
|
# )
|
||||||
|
|
||||||
# Penalty for not meeting the minimum SOC (State of Charge) requirement
|
# Penalty for not meeting the minimum SOC (State of Charge) requirement
|
||||||
if parameter["eauto_min_soc"] - ems.eauto.ladezustand_in_prozent() <= 0.0:
|
if parameter["eauto_min_soc"] - ems.eauto.ladezustand_in_prozent() <= 0.0:
|
||||||
@ -232,14 +281,14 @@ class optimization_problem:
|
|||||||
for _ in range(3):
|
for _ in range(3):
|
||||||
population.insert(0, creator.Individual(start_solution))
|
population.insert(0, creator.Individual(start_solution))
|
||||||
|
|
||||||
# Run the evolutionary algorithm
|
#Run the evolutionary algorithm
|
||||||
algorithms.eaMuPlusLambda(
|
algorithms.eaMuPlusLambda(
|
||||||
population,
|
population,
|
||||||
self.toolbox,
|
self.toolbox,
|
||||||
mu=100,
|
mu=100,
|
||||||
lambda_=200,
|
lambda_=150,
|
||||||
cxpb=0.7,
|
cxpb=0.5,
|
||||||
mutpb=0.3,
|
mutpb=0.5,
|
||||||
ngen=ngen,
|
ngen=ngen,
|
||||||
stats=stats,
|
stats=stats,
|
||||||
halloffame=hof,
|
halloffame=hof,
|
||||||
@ -282,6 +331,10 @@ class optimization_problem:
|
|||||||
)
|
)
|
||||||
akku.set_charge_per_hour(np.full(self.prediction_hours, 1))
|
akku.set_charge_per_hour(np.full(self.prediction_hours, 1))
|
||||||
|
|
||||||
|
self.optimize_ev = True
|
||||||
|
if parameter["eauto_min_soc"] - parameter["eauto_soc"] <0:
|
||||||
|
self.optimize_ev = False
|
||||||
|
|
||||||
eauto = PVAkku(
|
eauto = PVAkku(
|
||||||
kapazitaet_wh=parameter["eauto_cap"],
|
kapazitaet_wh=parameter["eauto_cap"],
|
||||||
hours=self.prediction_hours,
|
hours=self.prediction_hours,
|
||||||
@ -382,3 +435,4 @@ class optimization_problem:
|
|||||||
"spuelstart": spuelstart_int,
|
"spuelstart": spuelstart_int,
|
||||||
"simulation_data": o,
|
"simulation_data": o,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,18 +5,18 @@ output_dir = "output"
|
|||||||
prediction_hours = 48
|
prediction_hours = 48
|
||||||
optimization_hours = 24
|
optimization_hours = 24
|
||||||
strafe = 10
|
strafe = 10
|
||||||
moegliche_ladestroeme_in_prozent = [
|
possible_ev_charge_currents = [
|
||||||
0.0,
|
0.0,
|
||||||
6.0 / 16.0,
|
6.0 / 16.0,
|
||||||
7.0 / 16.0,
|
#7.0 / 16.0,
|
||||||
8.0 / 16.0,
|
8.0 / 16.0,
|
||||||
9.0 / 16.0,
|
#9.0 / 16.0,
|
||||||
10.0 / 16.0,
|
10.0 / 16.0,
|
||||||
11.0 / 16.0,
|
#11.0 / 16.0,
|
||||||
12.0 / 16.0,
|
12.0 / 16.0,
|
||||||
13.0 / 16.0,
|
#13.0 / 16.0,
|
||||||
14.0 / 16.0,
|
14.0 / 16.0,
|
||||||
15.0 / 16.0,
|
#15.0 / 16.0,
|
||||||
1.0,
|
1.0,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -160,26 +160,40 @@ 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
|
||||||
for hour, value in enumerate(discharge_hours):
|
for hour, value in enumerate(discharge_hours):
|
||||||
|
# Festlegen der Farbe und des Labels basierend auf dem Wert
|
||||||
|
if value > 0: # Positive Werte (Entladung)
|
||||||
|
color = "red"
|
||||||
|
label = "Discharge" if hour == 0 else "" # Label nur beim ersten Eintrag hinzufügen
|
||||||
|
elif value < 0: # Negative Werte (Ladung)
|
||||||
|
color = "blue"
|
||||||
|
label = "Charge" if hour == 0 else ""
|
||||||
|
else:
|
||||||
|
continue # Überspringe 0-Werte
|
||||||
|
|
||||||
|
# Erstellen der Farbbereiche mit `axvspan`
|
||||||
ax1.axvspan(
|
ax1.axvspan(
|
||||||
hour,
|
hour, # Start der Stunde
|
||||||
hour + 1,
|
hour + 1, # Ende der Stunde
|
||||||
color="red",
|
ymin=0, # Untere Grenze
|
||||||
ymax=value,
|
ymax=abs(value), # Obere Grenze: abs(value), um die Höhe richtig darzustellen
|
||||||
|
color=color,
|
||||||
alpha=0.3,
|
alpha=0.3,
|
||||||
label="Discharge Possibility" if hour == 0 else "",
|
label=label
|
||||||
)
|
)
|
||||||
for hour, value in enumerate(laden_moeglich):
|
|
||||||
ax1.axvspan(
|
# Annotieren der Werte in der Mitte des Farbbereichs
|
||||||
hour,
|
ax1.text(
|
||||||
hour + 1,
|
hour + 0.5, # In der Mitte des Bereichs
|
||||||
color="green",
|
abs(value) / 2, # In der Mitte der Höhe
|
||||||
ymax=value,
|
f'{value:.2f}', # Wert mit zwei Dezimalstellen
|
||||||
alpha=0.3,
|
ha='center',
|
||||||
label="Charging Possibility" if hour == 0 else "",
|
va='center',
|
||||||
|
fontsize=8,
|
||||||
|
color='black'
|
||||||
)
|
)
|
||||||
ax1.legend(loc="upper left")
|
|
||||||
ax1.set_xlim(0, prediction_hours)
|
|
||||||
|
|
||||||
pdf.savefig() # Save the current figure state to the PDF
|
pdf.savefig() # Save the current figure state to the PDF
|
||||||
plt.close() # Close the current figure to free up memory
|
plt.close() # Close the current figure to free up memory
|
||||||
@ -192,26 +206,47 @@ def visualisiere_ergebnisse(
|
|||||||
losses = ergebnisse["Gesamt_Verluste"]
|
losses = ergebnisse["Gesamt_Verluste"]
|
||||||
|
|
||||||
# Costs and revenues per hour on the first axis (axs[0])
|
# Costs and revenues per hour on the first axis (axs[0])
|
||||||
|
costs = ergebnisse["Kosten_Euro_pro_Stunde"]
|
||||||
|
revenues = ergebnisse["Einnahmen_Euro_pro_Stunde"]
|
||||||
|
|
||||||
|
# Plot costs
|
||||||
axs[0].plot(
|
axs[0].plot(
|
||||||
hours,
|
hours,
|
||||||
ergebnisse["Kosten_Euro_pro_Stunde"],
|
costs,
|
||||||
label="Costs (Euro)",
|
label="Costs (Euro)",
|
||||||
marker="o",
|
marker="o",
|
||||||
color="red",
|
color="red",
|
||||||
)
|
)
|
||||||
|
# Annotate costs
|
||||||
|
for hour, value in enumerate(costs):
|
||||||
|
print(hour, " ", value)
|
||||||
|
if value == None or np.isnan(value):
|
||||||
|
value=0
|
||||||
|
axs[0].annotate(f'{value:.2f}', (hour, value), textcoords="offset points", xytext=(0,5), ha='center', fontsize=8, color='red')
|
||||||
|
|
||||||
|
# Plot revenues
|
||||||
axs[0].plot(
|
axs[0].plot(
|
||||||
hours,
|
hours,
|
||||||
ergebnisse["Einnahmen_Euro_pro_Stunde"],
|
revenues,
|
||||||
label="Revenue (Euro)",
|
label="Revenue (Euro)",
|
||||||
marker="x",
|
marker="x",
|
||||||
color="green",
|
color="green",
|
||||||
)
|
)
|
||||||
|
# Annotate revenues
|
||||||
|
for hour, value in enumerate(revenues):
|
||||||
|
if value == None or np.isnan(value):
|
||||||
|
value=0
|
||||||
|
axs[0].annotate(f'{value:.2f}', (hour, value), textcoords="offset points", xytext=(0,5), ha='center', fontsize=8, color='green')
|
||||||
|
|
||||||
|
# Title and labels
|
||||||
axs[0].set_title("Financial Balance per Hour")
|
axs[0].set_title("Financial Balance per Hour")
|
||||||
axs[0].set_xlabel("Hour")
|
axs[0].set_xlabel("Hour")
|
||||||
axs[0].set_ylabel("Euro")
|
axs[0].set_ylabel("Euro")
|
||||||
axs[0].legend()
|
axs[0].legend()
|
||||||
axs[0].grid(True)
|
axs[0].grid(True)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Summary of finances on the second axis (axs[1])
|
# Summary of finances on the second axis (axs[1])
|
||||||
labels = ["Total Costs [€]", "Total Revenue [€]", "Total Balance [€]"]
|
labels = ["Total Costs [€]", "Total Revenue [€]", "Total Balance [€]"]
|
||||||
values = [total_costs, total_revenue, total_balance]
|
values = [total_costs, total_revenue, total_balance]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user