Skip to content

Commit

Permalink
Minor improvements to optimisation (#460)
Browse files Browse the repository at this point in the history
* Metric min improvement now used to gate enabling discharge or turning off charging, but not the exact limit picked
* Show charge freeze on the battery chart not at reserve but at the freeze level

* [pre-commit.ci lite] apply automatic fixes

---------

Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
  • Loading branch information
springfall2008 and pre-commit-ci-lite[bot] authored Dec 13, 2023
1 parent e53f8c7 commit 614ecaf
Showing 1 changed file with 27 additions and 11 deletions.
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

0 comments on commit 614ecaf

Please sign in to comment.