Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minor improvements to optimisation #460

Merged
merged 2 commits into from
Dec 13, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 27 additions & 11 deletions apps/predbat/predbat.py
Original file line number Diff line number Diff line change
Expand Up @@ -945,7 +945,7 @@ def update_status(self, minutes_now, quiet=False):

if not quiet:
self.base.log(
"Inverter {} SOC: {} kw {} % Current charge rate {} w Current discharge rate {} w Current power {} w Current voltage{}".format(
"Inverter {} SOC: {} kw {} % Current charge rate {} w Current discharge rate {} w Current power {} w Current voltage {}".format(
self.id,
self.base.dp2(self.soc_kw),
self.soc_percent,
Expand Down Expand Up @@ -5872,7 +5872,7 @@ def publish_discharge_limit(self, discharge_window, discharge_limits, best):
},
)

def publish_charge_limit(self, charge_limit, charge_window, charge_limit_percent, best):
def publish_charge_limit(self, charge_limit, charge_window, charge_limit_percent, best=False, soc={}):
"""
Create entity to chart charge limit
"""
Expand All @@ -5890,6 +5890,12 @@ def publish_charge_limit(self, charge_limit, charge_window, charge_limit_percent
else:
soc_perc = 0
soc_kw = 0

# Convert % of charge freeze to current SOC number
if self.set_charge_freeze and (soc_perc == self.reserve_percent):
offset = int((minute - self.minutes_now) / 5) * 5
soc_kw = soc.get(offset, soc_kw)

if prev_perc != soc_perc:
charge_limit_time[stamp] = soc_perc
charge_limit_time_kw[stamp] = soc_kw
Expand Down Expand Up @@ -6369,6 +6375,7 @@ def optimise_charge_limit(
best_soc_min = 0
best_soc_min_minute = 0
best_metric = 9999999
on_metric = 9999999
best_cost = 0
prev_soc = self.soc_max + 1
prev_metric = 9999999
Expand Down Expand Up @@ -6495,7 +6502,7 @@ def optimise_charge_limit(
# to try to avoid constant small changes to SOC target
if not all_n and (window_n == self.in_charge_window(charge_window, self.minutes_now)):
try_percent = self.calc_percent_limit(try_soc)
compare_with = max(self.current_charge_limit, self.reserve_current_percent)
compare_with = max(self.current_charge_limit, self.reserve_percent)

if abs(compare_with - try_percent) <= 2:
metric -= max(0.5, self.metric_min_improvement)
Expand Down Expand Up @@ -6531,14 +6538,18 @@ def optimise_charge_limit(

# Only select the lower SOC if it makes a notable improvement has defined by min_improvement (divided in M windows)
# and it doesn't fall below the soc_keep threshold
if (metric + self.metric_min_improvement) <= best_metric:
if ((metric + self.metric_min_improvement) <= on_metric) and (metric <= best_metric):
best_metric = metric
best_soc = try_soc
best_cost = cost
best_soc_min = soc_min
best_soc_min_minute = soc_min_minute
best_keep = metric_keep

# Default on metric
if on_metric == 9999999:
on_metric = metric

prev_soc = try_soc
prev_metric = metric
first_window = False
Expand Down Expand Up @@ -6585,6 +6596,7 @@ def optimise_discharge(
"""
best_discharge = False
best_metric = 9999999
off_metric = 9999999
best_cost = 0
best_soc_min = 0
best_soc_min_minute = 0
Expand Down Expand Up @@ -6680,8 +6692,6 @@ def optimise_discharge(
dwindow = self.discharge_window[0]
if self.minutes_now >= pwindow["start"] and self.minutes_now < pwindow["end"]:
if (self.minutes_now >= dwindow["start"] and self.minutes_now < dwindow["end"]) or (dwindow["end"] == pwindow["start"]):
if self.debug_enable:
self.log("Sim: Discharge window {} - weighting as it falls within currently configured discharge slot (or continues from one)".format(window_n))
metric -= max(0.5, self.metric_min_improvement_discharge)

if self.debug_enable:
Expand All @@ -6706,13 +6716,12 @@ def optimise_discharge(
)
)

window_size = window["end"] - start
window_size = try_discharge_window[window_n]["end"] - start
window_key = str(int(this_discharge_limit)) + "_" + str(window_size)
window_results[window_key] = self.dp2(metric)

# Only select the lower SOC if it makes a notable improvement has defined by min_improvement (divided in M windows)
# and it doesn't fall below the soc_keep threshold
if (metric + self.metric_min_improvement_discharge) <= best_metric:
# Only select a discharge if it makes a notable improvement has defined by min_improvement (divided in M windows)
if ((metric + self.metric_min_improvement_discharge) <= off_metric) and (metric <= best_metric):
best_metric = metric
best_discharge = this_discharge_limit
best_cost = cost
Expand All @@ -6722,6 +6731,10 @@ def optimise_discharge(
best_size = window_size
best_keep = metric_keep

# Store the metric for discharge off
if off_metric == 9999999:
off_metric = metric

if not all_n:
self.log(
"Try optimising discharge window(s) {}: {} - {} price {} selected {}% size {} was {}% results {}".format(
Expand Down Expand Up @@ -8054,7 +8067,7 @@ def calculate_plan(self, recompute=True):

# Publish charge and discharge window best
self.charge_limit_percent_best = self.calc_percent_limit(self.charge_limit_best)
self.publish_charge_limit(self.charge_limit_best, self.charge_window_best, self.charge_limit_percent_best, best=True)
self.publish_charge_limit(self.charge_limit_best, self.charge_window_best, self.charge_limit_percent_best, best=True, soc=self.predict_soc_best)
self.publish_discharge_limit(self.discharge_window_best, self.discharge_limits_best, best=True)

# HTML data
Expand Down Expand Up @@ -8820,6 +8833,7 @@ def fetch_inverter_data(self):
self.soc_kw = 0.0
self.soc_max = 0.0
self.reserve = 0.0
self.reserve_percent = 0.0
self.reserve_current = 0.0
self.reserve_current_percent = 0.0
self.battery_rate_max_charge = 0.0
Expand Down Expand Up @@ -8866,6 +8880,8 @@ def fetch_inverter_data(self):
# Remove extra decimals
self.soc_max = self.dp2(self.soc_max)
self.soc_kw = self.dp2(self.soc_kw)
self.reserve = self.dp2(self.reserve)
self.reserve_percent = int(self.reserve / self.soc_max * 100.0 + 0.5)
self.reserve_current = self.dp2(self.reserve_current)
self.reserve_current_percent = int(self.reserve_current / self.soc_max * 100.0 + 0.5)

Expand Down