mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2026-08-31 12:46:38 +00:00
fix(optimization): add battery self-consumption state
This commit is contained in:
@@ -80,6 +80,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
are deprecated in favour of `appliance_starts` and `result.home_appliance_energy_wh`.
|
||||
|
||||
### Fixed
|
||||
- Allow the direct-marketing optimizer to select a true battery self-consumption state with DC
|
||||
charging and local-load discharge enabled in the same slot. Existing warm-start state numbers
|
||||
remain compatible, and educated guesses now use the combined state for PV/load overlap instead
|
||||
of unnecessarily bypassing PV while serving loads such as EV charging.
|
||||
- Account for EV charging losses in the AC load seen by the inverter and grid, so fitness and
|
||||
energy costs use the charger's raw input rather than only the energy stored in the EV battery.
|
||||
- Treat fitness memoization as disabled for lightweight optimizer instances constructed without
|
||||
the normal initializer, preserving isolated penalty evaluation and test callers.
|
||||
- Re-simulate genetic candidates after removing EV charging genes from slots that begin at full
|
||||
SoC, keeping the repaired genome and its assigned fitness consistent.
|
||||
- FeedInTariffEnergyCharts no longer aborts the whole prediction/optimization when the
|
||||
|
||||
@@ -357,6 +357,11 @@ smaller values (e.g. `0.0`) disable the penalty entirely.
|
||||
- `discharge_allowed`: Battery discharge permission for local self-consumption/load coverage (0 or 1)
|
||||
- `battery_grid_export_allowed`: Battery discharge permission for grid export/direct marketing (0 or 1)
|
||||
|
||||
With direct marketing enabled, `dc_charge = 1` and `discharge_allowed = 1` may occur together. This
|
||||
is the normal self-consumption mode: within a coarse optimization slot, the battery may cover
|
||||
probabilistic load gaps and store PV surplus from different sub-intervals. A discharge-only state
|
||||
remains available when deliberately bypassing PV charging is economically preferable.
|
||||
|
||||
0 (no charge)
|
||||
1 (charge with full load)
|
||||
|
||||
|
||||
@@ -85,6 +85,17 @@ class FitnessCacheEntry:
|
||||
extra_data: tuple[float, float, float]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class BatteryStateLayout:
|
||||
"""Indices of optional battery states appended to the legacy state ranges."""
|
||||
|
||||
total_states: int
|
||||
dc_not_allowed_state: Optional[int] = None
|
||||
dc_allowed_state: Optional[int] = None
|
||||
grid_export_state: Optional[int] = None
|
||||
self_consumption_state: Optional[int] = None
|
||||
|
||||
|
||||
class GeneticSimulation(PydanticBaseModel):
|
||||
"""Device simulation for GENETIC optimization algorithm."""
|
||||
|
||||
@@ -411,10 +422,12 @@ class GeneticSimulation(PydanticBaseModel):
|
||||
if ev_fast:
|
||||
soc_ev_per_hour[hour_idx] = ev_fast.current_soc_percentage() # save begin state
|
||||
if ev_charge_hours_fast[hour] > 0:
|
||||
loaded_energy_ev, verluste_eauto = ev_fast.charge_energy(
|
||||
stored_energy_ev, verluste_eauto = ev_fast.charge_energy(
|
||||
wh=None, hour=hour, charge_factor=ev_charge_hours_fast[hour]
|
||||
)
|
||||
consumption += loaded_energy_ev
|
||||
# The inverter/grid must supply the EV charger's raw input,
|
||||
# not only the energy stored after charging losses.
|
||||
consumption += stored_energy_ev + verluste_eauto
|
||||
losses_wh_per_hour[hour_idx] += verluste_eauto
|
||||
|
||||
# Save battery SOC before inverter processing = true begin-of-interval state.
|
||||
@@ -663,6 +676,40 @@ class GeneticOptimization(OptimizationBase):
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
def _battery_state_layout(self) -> BatteryStateLayout:
|
||||
"""Build optional state indices without renumbering legacy warm starts.
|
||||
|
||||
The pre-existing order is retained exactly: base charge/discharge ranges,
|
||||
two optional DC states, then optional grid export. SELF_CONSUMPTION is
|
||||
appended last so an old export gene never changes its meaning.
|
||||
"""
|
||||
next_state = 3 * len(self.bat_possible_charge_values)
|
||||
dc_not_allowed_state: Optional[int] = None
|
||||
dc_allowed_state: Optional[int] = None
|
||||
grid_export_state: Optional[int] = None
|
||||
self_consumption_state: Optional[int] = None
|
||||
|
||||
if self.optimize_dc_charge:
|
||||
dc_not_allowed_state = next_state
|
||||
dc_allowed_state = next_state + 1
|
||||
next_state += 2
|
||||
|
||||
if self.optimize_battery_grid_export:
|
||||
grid_export_state = next_state
|
||||
next_state += 1
|
||||
|
||||
if self.optimize_dc_charge:
|
||||
self_consumption_state = next_state
|
||||
next_state += 1
|
||||
|
||||
return BatteryStateLayout(
|
||||
total_states=next_state,
|
||||
dc_not_allowed_state=dc_not_allowed_state,
|
||||
dc_allowed_state=dc_allowed_state,
|
||||
grid_export_state=grid_export_state,
|
||||
self_consumption_state=self_consumption_state,
|
||||
)
|
||||
|
||||
def _appliance_horizon_end_slot(self) -> int:
|
||||
"""Exclusive upper slot bound for appliance runs (end of horizon).
|
||||
|
||||
@@ -966,9 +1013,8 @@ class GeneticOptimization(OptimizationBase):
|
||||
# AC Charge: 2*len_bat .. 3*len_bat - 1 (maps to bat_possible_charge_values)
|
||||
# DC optional: 3*len_bat (not allowed), 3*len_bat + 1 (allowed)
|
||||
# Grid export: next state, if direct marketing/export optimization is enabled
|
||||
|
||||
# Idle states
|
||||
idle_mask = (discharge_hours_bin_np >= 0) & (discharge_hours_bin_np < len_bat)
|
||||
# Self-consumption: final state, with DC charging and local discharge enabled
|
||||
state_layout = self._battery_state_layout()
|
||||
|
||||
# Discharge states
|
||||
discharge_mask = (discharge_hours_bin_np >= len_bat) & (
|
||||
@@ -980,24 +1026,28 @@ class GeneticOptimization(OptimizationBase):
|
||||
ac_indices = (discharge_hours_bin_np[ac_mask] - 2 * len_bat).astype(int)
|
||||
|
||||
# DC states (if enabled)
|
||||
if self.optimize_dc_charge:
|
||||
dc_not_allowed_state = 3 * len_bat
|
||||
dc_allowed_state = 3 * len_bat + 1
|
||||
dc_charge = np.where(discharge_hours_bin_np == dc_allowed_state, 1, 0)
|
||||
if state_layout.dc_allowed_state is not None:
|
||||
dc_mask = discharge_hours_bin_np == state_layout.dc_allowed_state
|
||||
if state_layout.self_consumption_state is not None:
|
||||
dc_mask |= discharge_hours_bin_np == state_layout.self_consumption_state
|
||||
dc_charge = np.where(dc_mask, 1, 0)
|
||||
else:
|
||||
dc_charge = np.ones_like(discharge_hours_bin_np, dtype=float)
|
||||
|
||||
# Generate the result arrays
|
||||
discharge = np.zeros_like(discharge_hours_bin_np, dtype=int)
|
||||
discharge[discharge_mask] = 1 # Set Discharge states to 1
|
||||
if state_layout.self_consumption_state is not None:
|
||||
discharge[discharge_hours_bin_np == state_layout.self_consumption_state] = 1
|
||||
|
||||
ac_charge = np.zeros_like(discharge_hours_bin_np, dtype=float)
|
||||
ac_charge[ac_mask] = [self.bat_possible_charge_values[i] for i in ac_indices]
|
||||
|
||||
battery_grid_export = np.zeros_like(discharge_hours_bin_np, dtype=int)
|
||||
if self.optimize_battery_grid_export:
|
||||
grid_export_state = 3 * len_bat + (2 if self.optimize_dc_charge else 0)
|
||||
battery_grid_export = np.where(discharge_hours_bin_np == grid_export_state, 1, 0)
|
||||
if state_layout.grid_export_state is not None:
|
||||
battery_grid_export = np.where(
|
||||
discharge_hours_bin_np == state_layout.grid_export_state, 1, 0
|
||||
)
|
||||
|
||||
# Idle is just 0, already default.
|
||||
|
||||
@@ -1005,14 +1055,7 @@ class GeneticOptimization(OptimizationBase):
|
||||
|
||||
def mutate(self, individual: list[int]) -> tuple[list[int]]:
|
||||
"""Custom mutation function for the individual."""
|
||||
# Calculate the number of states using battery charge levels
|
||||
len_bat = len(self.bat_possible_charge_values)
|
||||
if self.optimize_dc_charge:
|
||||
total_states = 3 * len_bat + 2
|
||||
else:
|
||||
total_states = 3 * len_bat
|
||||
if self.optimize_battery_grid_export:
|
||||
total_states += 1
|
||||
total_states = self._battery_state_layout().total_states
|
||||
|
||||
# 1. Mutating the charge_discharge part
|
||||
charge_discharge_part = individual[: self.total_slots]
|
||||
@@ -1146,14 +1189,15 @@ class GeneticOptimization(OptimizationBase):
|
||||
must re-simulate after a change so the individual's genome, simulation
|
||||
state and assigned fitness always describe the same schedule.
|
||||
"""
|
||||
if not self.optimize_ev or not self.ev_possible_charge_values:
|
||||
ev_possible_charge_values = getattr(self, "ev_possible_charge_values", None)
|
||||
if not self.optimize_ev or not ev_possible_charge_values:
|
||||
return False
|
||||
|
||||
zero_charge_index = min(
|
||||
range(len(self.ev_possible_charge_values)),
|
||||
key=lambda index: abs(self.ev_possible_charge_values[index]),
|
||||
range(len(ev_possible_charge_values)),
|
||||
key=lambda index: abs(ev_possible_charge_values[index]),
|
||||
)
|
||||
if abs(self.ev_possible_charge_values[zero_charge_index]) > 1e-12:
|
||||
if abs(ev_possible_charge_values[zero_charge_index]) > 1e-12:
|
||||
return False
|
||||
|
||||
_, ev_charge_indices, _ = self.split_individual(individual)
|
||||
@@ -1172,7 +1216,7 @@ class GeneticOptimization(OptimizationBase):
|
||||
charge_index = int(ev_charge_indices[slot])
|
||||
if (
|
||||
ev_soc[offset] >= 100.0 - 1e-9
|
||||
and self.ev_possible_charge_values[charge_index] > 0.0
|
||||
and ev_possible_charge_values[charge_index] > 0.0
|
||||
):
|
||||
ev_charge_indices[slot] = zero_charge_index
|
||||
changed = True
|
||||
@@ -1279,11 +1323,13 @@ class GeneticOptimization(OptimizationBase):
|
||||
slots = self.total_slots
|
||||
start_slot = self._start_day_slot()
|
||||
len_bat = len(self.bat_possible_charge_values)
|
||||
state_layout = self._battery_state_layout()
|
||||
idle_state = 0
|
||||
discharge_state = len_bat
|
||||
ac_charge_state = 3 * len_bat - 1
|
||||
dc_allowed_state = 3 * len_bat + 1
|
||||
export_state = 3 * len_bat + (2 if self.optimize_dc_charge else 0)
|
||||
dc_allowed_state = state_layout.dc_allowed_state
|
||||
export_state = state_layout.grid_export_state
|
||||
self_consumption_state = state_layout.self_consumption_state
|
||||
|
||||
prices = np.asarray(self.simulation.elect_price_hourly, dtype=float)
|
||||
feed_in = np.asarray(self.simulation.elect_revenue_per_hour_arr, dtype=float)
|
||||
@@ -1333,15 +1379,20 @@ class GeneticOptimization(OptimizationBase):
|
||||
for slot in range(start_slot, slots):
|
||||
high_feed_in = (
|
||||
export_quantile is not None
|
||||
and self.optimize_battery_grid_export
|
||||
and export_state is not None
|
||||
and feed_spread > 1e-12
|
||||
and feed_in[slot] > 0.0
|
||||
and feed_in[slot] >= export_threshold
|
||||
)
|
||||
pv_surplus = pv[slot] > load[slot] * pv_surplus_ratio
|
||||
if high_feed_in:
|
||||
if high_feed_in and export_state is not None:
|
||||
battery_genes[slot] = export_state
|
||||
elif self.optimize_dc_charge and pv_surplus:
|
||||
elif self_consumption_state is not None and pv[slot] > 0.0 and load[slot] > 0.0:
|
||||
# The probabilistic inverter model can see a residual load
|
||||
# and a PV surplus within the same coarse slot. Normal
|
||||
# self-consumption must therefore allow both directions.
|
||||
battery_genes[slot] = self_consumption_state
|
||||
elif dc_allowed_state is not None and pv_surplus:
|
||||
battery_genes[slot] = dc_allowed_state
|
||||
elif allow_ac_arbitrage and prices[slot] <= low_price_threshold:
|
||||
battery_genes[slot] = ac_charge_state
|
||||
@@ -1415,7 +1466,9 @@ class GeneticOptimization(OptimizationBase):
|
||||
for slot in random.sample(future_slots, min(perturbations, len(future_slots))): # noqa: S311
|
||||
if randomized[slot] != idle_state:
|
||||
randomized[slot] = idle_state
|
||||
elif self.optimize_dc_charge and pv[slot] > load[slot]:
|
||||
elif self_consumption_state is not None and pv[slot] > 0.0 and load[slot] > 0.0:
|
||||
randomized[slot] = self_consumption_state
|
||||
elif dc_allowed_state is not None and pv[slot] > load[slot]:
|
||||
randomized[slot] = dc_allowed_state
|
||||
elif load[slot] > pv[slot] and prices[slot] >= high_import_price:
|
||||
randomized[slot] = discharge_state
|
||||
@@ -1480,12 +1533,8 @@ class GeneticOptimization(OptimizationBase):
|
||||
# AC-Charge: len_bat states (maps to bat_possible_charge_values)
|
||||
# With DC: + 2 additional states
|
||||
# With battery grid export: + 1 additional state
|
||||
if self.optimize_dc_charge:
|
||||
total_states = 3 * len_bat + 2
|
||||
else:
|
||||
total_states = 3 * len_bat
|
||||
if self.optimize_battery_grid_export:
|
||||
total_states += 1
|
||||
# With DC: + 1 final SELF_CONSUMPTION state
|
||||
total_states = self._battery_state_layout().total_states
|
||||
|
||||
# State space: 0 .. (total_states - 1)
|
||||
self.toolbox.register("attr_discharge_state", random.randint, 0, total_states - 1)
|
||||
@@ -1579,7 +1628,10 @@ class GeneticOptimization(OptimizationBase):
|
||||
worst_case: bool,
|
||||
) -> tuple[float]:
|
||||
"""Evaluate an individual, using run-local canonical memoization when active."""
|
||||
if not self._fitness_cache_enabled:
|
||||
# Some lightweight callers construct the optimizer without __init__
|
||||
# (for example isolated penalty evaluations). Memoization is opt-in, so
|
||||
# a missing flag must behave exactly like a disabled cache.
|
||||
if not getattr(self, "_fitness_cache_enabled", False):
|
||||
return self._evaluate_uncached(individual, parameters, start_hour, worst_case)
|
||||
|
||||
original_key = tuple(int(value) for value in individual)
|
||||
|
||||
@@ -187,9 +187,11 @@ def test_educated_guesses_encode_high_price_direct_marketing(config_eos: ConfigE
|
||||
|
||||
dc_allowed_state = 4
|
||||
export_state = 5
|
||||
self_consumption_state = 6
|
||||
assert len(guesses) == opt.EDUCATED_GUESS_TARGET
|
||||
assert all(len(guess) == slots for guess in guesses)
|
||||
assert any(guess[0] == dc_allowed_state for guess in guesses)
|
||||
assert any(dc_allowed_state in guess or self_consumption_state in guess for guess in guesses)
|
||||
assert any(self_consumption_state in guess for guess in guesses)
|
||||
assert any(guess[-1] == export_state for guess in guesses)
|
||||
|
||||
|
||||
|
||||
@@ -338,7 +338,7 @@ def test_simulation(genetic_simulation):
|
||||
|
||||
# Verify the total balance
|
||||
assert (
|
||||
abs(result["Gesamtbilanz_Euro"] - 7.025236588371921) < 1e-5
|
||||
abs(result["Gesamtbilanz_Euro"] - 7.224316588371922) < 1e-5
|
||||
), "Total balance should reflect the shared per-slot battery power limit."
|
||||
|
||||
# Check total revenue and total costs
|
||||
@@ -346,7 +346,7 @@ def test_simulation(genetic_simulation):
|
||||
abs(result["Gesamteinnahmen_Euro"] - 2.3247787887715) < 1e-5
|
||||
), "Total revenue should respect the shared per-slot battery power limit."
|
||||
assert (
|
||||
abs(result["Gesamtkosten_Euro"] - 9.350015377143421) < 1e-5
|
||||
abs(result["Gesamtkosten_Euro"] - 9.549095377143422) < 1e-5
|
||||
), "Total costs should respect the shared per-slot battery power limit."
|
||||
|
||||
# Check the losses
|
||||
@@ -379,6 +379,47 @@ def test_simulation(genetic_simulation):
|
||||
print("All tests passed successfully.")
|
||||
|
||||
|
||||
def test_ev_charging_uses_raw_input_energy_for_load_and_grid(config_eos):
|
||||
config_eos.merge_settings_from_dict(
|
||||
{"prediction": {"hours": 1}, "optimization": {"horizon_hours": 1}}
|
||||
)
|
||||
ev = Battery(
|
||||
ElectricVehicleParameters(
|
||||
device_id="ev1",
|
||||
capacity_wh=1000,
|
||||
charging_efficiency=0.8,
|
||||
max_charge_power_w=100,
|
||||
initial_soc_percentage=0,
|
||||
min_soc_percentage=0,
|
||||
),
|
||||
prediction_hours=1,
|
||||
)
|
||||
inverter = Inverter(InverterParameters(device_id="inverter1", max_power_wh=1000.0))
|
||||
simulation = GeneticSimulation()
|
||||
simulation.prepare(
|
||||
GeneticEnergyManagementParameters(
|
||||
pv_prognose_wh=[0.0],
|
||||
strompreis_euro_pro_wh=[0.001],
|
||||
einspeiseverguetung_euro_pro_wh=[0.0],
|
||||
preis_euro_pro_wh_akku=0.0,
|
||||
gesamtlast=[0.0],
|
||||
),
|
||||
optimization_hours=1,
|
||||
prediction_hours=1,
|
||||
inverter=inverter,
|
||||
ev=ev,
|
||||
)
|
||||
simulation.ev_charge_hours = np.array([1.0])
|
||||
|
||||
result = simulation.simulate(start_hour=0)
|
||||
|
||||
assert result["Last_Wh_pro_Stunde"][0] == pytest.approx(100.0)
|
||||
assert result["Netzbezug_Wh_pro_Stunde"][0] == pytest.approx(100.0)
|
||||
assert result["Kosten_Euro_pro_Stunde"][0] == pytest.approx(0.1)
|
||||
assert result["Verluste_Pro_Stunde"][0] == pytest.approx(20.0)
|
||||
assert ev.current_soc_percentage() == pytest.approx(8.0)
|
||||
|
||||
|
||||
def test_direct_marketing_curtails_negative_feed_in(config_eos, monkeypatch):
|
||||
config_eos.merge_settings_from_dict(
|
||||
{"prediction": {"hours": 2}, "optimization": {"horizon_hours": 2}}
|
||||
|
||||
@@ -54,3 +54,23 @@ def test_decode_charge_discharge_has_separate_battery_grid_export_state():
|
||||
assert dc_charge.tolist() == [0]
|
||||
assert discharge.tolist() == [0]
|
||||
assert battery_grid_export.tolist() == [1]
|
||||
|
||||
|
||||
def test_decode_charge_discharge_has_self_consumption_state_after_legacy_export():
|
||||
optimization = GeneticOptimization()
|
||||
optimization.bat_possible_charge_values = [1.0]
|
||||
optimization.optimize_dc_charge = True
|
||||
optimization.optimize_battery_grid_export = True
|
||||
|
||||
layout = optimization._battery_state_layout()
|
||||
ac_charge, dc_charge, discharge, battery_grid_export = (
|
||||
optimization.decode_charge_discharge(np.array([6]))
|
||||
)
|
||||
|
||||
assert layout.total_states == 7
|
||||
assert layout.grid_export_state == 5
|
||||
assert layout.self_consumption_state == 6
|
||||
assert ac_charge.tolist() == [0.0]
|
||||
assert dc_charge.tolist() == [1]
|
||||
assert discharge.tolist() == [1]
|
||||
assert battery_grid_export.tolist() == [0]
|
||||
|
||||
BIN
Binary file not shown.
+71
-71
@@ -202,15 +202,15 @@
|
||||
],
|
||||
"result": {
|
||||
"Last_Wh_pro_Stunde": [
|
||||
10230.07,
|
||||
7618.91,
|
||||
7875.5599999999995,
|
||||
7565.03,
|
||||
12840.67,
|
||||
9042.82,
|
||||
9082.22,
|
||||
5036.78,
|
||||
2177.92,
|
||||
10713.07,
|
||||
7963.91,
|
||||
8220.56,
|
||||
7772.03,
|
||||
13323.67,
|
||||
9456.82,
|
||||
9496.22,
|
||||
5243.78,
|
||||
2233.12,
|
||||
1178.71,
|
||||
1050.98,
|
||||
988.56,
|
||||
@@ -313,7 +313,7 @@
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.05936927575872234,
|
||||
0.053661230306193436,
|
||||
0.05435777788576338,
|
||||
0.0,
|
||||
0.0,
|
||||
@@ -322,9 +322,9 @@
|
||||
0.0
|
||||
],
|
||||
"Gesamt_Verluste": 6227.580163897914,
|
||||
"Gesamtbilanz_Euro": 11.420868526053463,
|
||||
"Gesamteinnahmen_Euro": 0.11372705364448572,
|
||||
"Gesamtkosten_Euro": 11.534595579697948,
|
||||
"Gesamtbilanz_Euro": 12.033027623527284,
|
||||
"Gesamteinnahmen_Euro": 0.10801900819195681,
|
||||
"Gesamtkosten_Euro": 12.14104663171924,
|
||||
"Home_appliance_wh_per_hour": [
|
||||
0.0,
|
||||
0.0,
|
||||
@@ -408,15 +408,15 @@
|
||||
]
|
||||
},
|
||||
"Kosten_Euro_pro_Stunde": [
|
||||
2.1203521199999997,
|
||||
1.4545721927072854,
|
||||
1.4167558060312964,
|
||||
1.2032659414129376,
|
||||
1.2892826874611185,
|
||||
0.770122611209644,
|
||||
1.1459236583154115,
|
||||
0.4965507655670841,
|
||||
0.1912938683161112,
|
||||
2.23047612,
|
||||
1.5308798733801507,
|
||||
1.4889564723943407,
|
||||
1.242149738556099,
|
||||
1.3742255912165289,
|
||||
0.8479283355019763,
|
||||
1.2336553365360492,
|
||||
0.5407163922683618,
|
||||
0.20558284318867343,
|
||||
0.1614775630079859,
|
||||
0.0,
|
||||
0.0,
|
||||
@@ -448,15 +448,15 @@
|
||||
0.16484566
|
||||
],
|
||||
"Netzbezug_Wh_pro_Stunde": [
|
||||
9299.789999999999,
|
||||
6575.823656000386,
|
||||
6769.01961792306,
|
||||
6403.757005923032,
|
||||
7014.595688036554,
|
||||
3842.9272016449304,
|
||||
5213.483431826258,
|
||||
2187.4483064629258,
|
||||
638.2845122326032,
|
||||
9782.789999999999,
|
||||
6920.795087613701,
|
||||
7113.9821901306295,
|
||||
6610.695787951565,
|
||||
7476.74423948057,
|
||||
4231.179318872138,
|
||||
5612.626644840988,
|
||||
2382.0105386271443,
|
||||
685.962106068313,
|
||||
505.40708296709204,
|
||||
0.0,
|
||||
0.0,
|
||||
@@ -519,7 +519,7 @@
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
848.1325108388907,
|
||||
766.589004374192,
|
||||
776.5396840823341,
|
||||
0.0,
|
||||
0.0,
|
||||
@@ -529,14 +529,14 @@
|
||||
],
|
||||
"Verluste_Pro_Stunde": [
|
||||
483.0,
|
||||
345.0196387200463,
|
||||
345.0239541507672,
|
||||
207.05004071076388,
|
||||
506.1294825643864,
|
||||
452.3012641973916,
|
||||
426.13721181915116,
|
||||
227.23539677555112,
|
||||
103.61214146791241,
|
||||
345.0162105136441,
|
||||
345.0194628156755,
|
||||
207.04269455418785,
|
||||
503.6273087376684,
|
||||
449.2115182646565,
|
||||
424.3543973809186,
|
||||
225.74286463525735,
|
||||
102.70945272819762,
|
||||
40.06404995605101,
|
||||
106.80230977350088,
|
||||
133.7321802766326,
|
||||
@@ -559,7 +559,7 @@
|
||||
538.2984000000001,
|
||||
441.9379674303641,
|
||||
261.1952696860876,
|
||||
75.0748095419566,
|
||||
84.86003031772043,
|
||||
0.0,
|
||||
111.78035844493081,
|
||||
90.18403329253945,
|
||||
@@ -570,36 +570,36 @@
|
||||
"akku_soc_pro_stunde": [
|
||||
80.0,
|
||||
80.0,
|
||||
80.00054552000128,
|
||||
80.00121091307815,
|
||||
80.0026009328216,
|
||||
80.6450865596101,
|
||||
81.70901056509321,
|
||||
82.04615533784741,
|
||||
82.60824969272383,
|
||||
83.95303140016584,
|
||||
85.06592167672281,
|
||||
81.89125383667168,
|
||||
77.66999557804807,
|
||||
77.66999557804807,
|
||||
77.66999557804807,
|
||||
75.44732856702878,
|
||||
71.71088745132629,
|
||||
68.72216499953565,
|
||||
66.10168462763482,
|
||||
63.7070995725384,
|
||||
61.60271768548606,
|
||||
59.42077037143647,
|
||||
55.97788013048819,
|
||||
52.48021001194556,
|
||||
53.09999027665313,
|
||||
54.60520137546928,
|
||||
57.01140766586834,
|
||||
61.59918181733974,
|
||||
63.43037648171088,
|
||||
78.38310981504422,
|
||||
90.65916446588767,
|
||||
97.91458862383455,
|
||||
80.00045029204567,
|
||||
80.00099092581443,
|
||||
80.00217688565297,
|
||||
80.57515768392155,
|
||||
81.55325541349534,
|
||||
81.8408775629653,
|
||||
82.36151269172245,
|
||||
83.68121971195016,
|
||||
84.79410998850713,
|
||||
81.619442148456,
|
||||
77.39818388983241,
|
||||
77.39818388983241,
|
||||
77.39818388983241,
|
||||
75.17551687881311,
|
||||
71.43907576311062,
|
||||
68.45035331131999,
|
||||
65.82987293941916,
|
||||
63.43528788432273,
|
||||
61.33090599727039,
|
||||
59.14895868322081,
|
||||
55.706068442272525,
|
||||
52.208398323729895,
|
||||
52.82817858843747,
|
||||
54.33338968725362,
|
||||
56.73959597765268,
|
||||
61.327370129124084,
|
||||
63.158564793495216,
|
||||
78.11129812682856,
|
||||
90.387352777672,
|
||||
97.64277693561888,
|
||||
100.0,
|
||||
100.0,
|
||||
98.60068046043587,
|
||||
|
||||
+70
-70
@@ -202,14 +202,14 @@
|
||||
],
|
||||
"result": {
|
||||
"Last_Wh_pro_Stunde": [
|
||||
11541.07,
|
||||
6307.91,
|
||||
9186.56,
|
||||
10309.03,
|
||||
6407.67,
|
||||
5109.82,
|
||||
11704.22,
|
||||
5036.78,
|
||||
12093.07,
|
||||
6583.91,
|
||||
9600.56,
|
||||
10792.03,
|
||||
6683.67,
|
||||
5316.82,
|
||||
12256.22,
|
||||
5243.78,
|
||||
1129.12,
|
||||
1178.71,
|
||||
1050.98,
|
||||
@@ -321,10 +321,10 @@
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"Gesamt_Verluste": 7430.87215820259,
|
||||
"Gesamtbilanz_Euro": 9.4881560601163,
|
||||
"Gesamt_Verluste": 7415.050669156861,
|
||||
"Gesamtbilanz_Euro": 10.086958235191952,
|
||||
"Gesamteinnahmen_Euro": 0.0,
|
||||
"Gesamtkosten_Euro": 9.4881560601163,
|
||||
"Gesamtkosten_Euro": 10.086958235191952,
|
||||
"Home_appliance_wh_per_hour": [
|
||||
0.0,
|
||||
0.0,
|
||||
@@ -408,14 +408,14 @@
|
||||
]
|
||||
},
|
||||
"Kosten_Euro_pro_Stunde": [
|
||||
1.4160601199999998,
|
||||
0.19137741085396395,
|
||||
1.691123530177008,
|
||||
1.7187910298948639,
|
||||
0.20791005863613377,
|
||||
0.09234842570092357,
|
||||
1.709869129414328,
|
||||
0.4965507655670841,
|
||||
1.5419161199999998,
|
||||
0.2524105556335792,
|
||||
1.7777665549410084,
|
||||
1.809540886,
|
||||
0.24971825220475874,
|
||||
0.12061259291950001,
|
||||
1.83015129135275,
|
||||
0.5407163922683618,
|
||||
0.05258762370598476,
|
||||
0.1614775630079859,
|
||||
0.0,
|
||||
@@ -448,14 +448,14 @@
|
||||
0.16484566
|
||||
],
|
||||
"Netzbezug_Wh_pro_Stunde": [
|
||||
6210.789999999999,
|
||||
865.1781684175585,
|
||||
8079.902198647912,
|
||||
9147.371101090283,
|
||||
1131.1755094457767,
|
||||
460.8204875295587,
|
||||
7779.204410438253,
|
||||
2187.4483064629258,
|
||||
6762.789999999999,
|
||||
1141.0965444556023,
|
||||
8493.867916583891,
|
||||
9630.34,
|
||||
1358.64119806724,
|
||||
601.8592461052895,
|
||||
8326.43899614536,
|
||||
2382.0105386271443,
|
||||
175.4675465665157,
|
||||
505.40708296709204,
|
||||
0.0,
|
||||
@@ -529,13 +529,13 @@
|
||||
],
|
||||
"Verluste_Pro_Stunde": [
|
||||
1152.0,
|
||||
876.0621802101069,
|
||||
414.00986383774955,
|
||||
483.00373213083384,
|
||||
365.07906113349316,
|
||||
311.4084585035471,
|
||||
557.3837292525905,
|
||||
227.23539677555112,
|
||||
876.0523853346722,
|
||||
414.00574999006693,
|
||||
483.0,
|
||||
359.25494376806876,
|
||||
303.4931095326348,
|
||||
556.8118795374434,
|
||||
225.74286463525735,
|
||||
118.73010558798194,
|
||||
40.06404995605101,
|
||||
106.80230977350088,
|
||||
@@ -570,42 +570,42 @@
|
||||
"akku_soc_pro_stunde": [
|
||||
80.0,
|
||||
61.06060606060606,
|
||||
42.12293934927065,
|
||||
42.12321334476369,
|
||||
42.123317015064636,
|
||||
44.59773537988389,
|
||||
47.49797033831576,
|
||||
47.64751837310994,
|
||||
48.209612727986354,
|
||||
51.507671216541404,
|
||||
52.620561493098386,
|
||||
49.44589365304724,
|
||||
45.224635394423636,
|
||||
45.224635394423636,
|
||||
45.224635394423636,
|
||||
43.00196838340435,
|
||||
39.26552726770188,
|
||||
36.27680481591124,
|
||||
33.656324444010416,
|
||||
31.261739388913995,
|
||||
29.157357501861657,
|
||||
26.97541018781207,
|
||||
23.53251994686378,
|
||||
20.034849828321157,
|
||||
20.654630093028718,
|
||||
22.159841191844876,
|
||||
24.566047482243945,
|
||||
29.15382163371534,
|
||||
29.229581775454538,
|
||||
35.84898177545453,
|
||||
48.12503642629798,
|
||||
55.38046058424485,
|
||||
60.29298032987328,
|
||||
61.68112016833327,
|
||||
62.6777205736456,
|
||||
60.18956135662841,
|
||||
55.94106789932813,
|
||||
55.94106789932813
|
||||
42.12266726939745,
|
||||
42.122826991343764,
|
||||
42.122826991343764,
|
||||
44.435464318234565,
|
||||
47.11582847191886,
|
||||
47.249491792403404,
|
||||
47.770126921160546,
|
||||
51.0681854097156,
|
||||
52.181075686272585,
|
||||
49.006407846221435,
|
||||
44.78514958759783,
|
||||
44.78514958759783,
|
||||
44.78514958759783,
|
||||
42.562482576578546,
|
||||
38.82604146087607,
|
||||
35.837319009085434,
|
||||
33.2168386371846,
|
||||
30.822253582088187,
|
||||
28.717871695035846,
|
||||
26.53592438098626,
|
||||
23.09303414003797,
|
||||
19.595364021495346,
|
||||
20.215144286202914,
|
||||
21.72035538501907,
|
||||
24.126561675418138,
|
||||
28.71433582688953,
|
||||
28.79009596862873,
|
||||
35.40949596862873,
|
||||
47.68555061947217,
|
||||
54.94097477741905,
|
||||
59.85349452304748,
|
||||
61.241634361507465,
|
||||
62.2382347668198,
|
||||
59.7500755498026,
|
||||
55.50158209250233,
|
||||
55.50158209250233
|
||||
],
|
||||
"Electricity_price": [
|
||||
0.000228,
|
||||
|
||||
Reference in New Issue
Block a user