Skip to content

Commit 4169e03

Browse files
Fixes for coarse/fine and update docs (#3230)
1 parent 46b94db commit 4169e03

File tree

4 files changed

+39
-21
lines changed

4 files changed

+39
-21
lines changed

apps/predbat/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2099,4 +2099,5 @@
20992099
"predheat": {"type": "dict"},
21002100
"forecast_solar": {"type": "dict_list"},
21012101
"forecast_solar_max_age": {"type": "float"},
2102+
"enable_coarse_fine_levels": {"type": "boolean"},
21022103
}

apps/predbat/plan.py

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ def __init__(self, result):
4040
Store the data into the class
4141
"""
4242
self.result = result
43+
time.sleep(0) # Yield control
4344

4445
def get(self):
4546
"""
@@ -322,31 +323,32 @@ def optimise_charge_limit_price_threads(
322323

323324
FINE_SLOT_LENGTHS = [48, 32, 24, 16, 14, 12, 10, 8, 6, 5, 4, 3, 2, 1]
324325
COARSE_SLOT_LENGTHS = [32, 16, 8, 4, 2, 1]
326+
min_freeze_percent = calc_percent_limit(self.best_soc_min, self.soc_max)
325327

326328
# Start loop of trials
327-
for coarse in [True, False] if enable_coarse_fine else [False]:
328-
if not enable_coarse_fine:
329-
charge_slot_choices = FINE_SLOT_LENGTHS
330-
export_slot_choices = FINE_SLOT_LENGTHS
331-
elif coarse:
332-
charge_slot_choices = COARSE_SLOT_LENGTHS
333-
export_slot_choices = COARSE_SLOT_LENGTHS
334-
else:
335-
charge_slot_choices = slots_around(best_max_charge_slots, FINE_SLOT_LENGTHS)
336-
export_slot_choices = slots_around(best_max_export_slots, FINE_SLOT_LENGTHS)
329+
for loop_price in all_prices:
330+
if best_level_score is not None:
331+
this_level_score = levels_score.get(loop_price, 9999999)
332+
if abs(this_level_score - best_level_score) > (0.3 * level_score_range):
333+
if self.debug_enable:
334+
self.log("Skipping price {} as level score {} is not within 30% of best {}".format(loop_price, this_level_score, best_level_score))
335+
continue
337336

338-
for loop_price in all_prices:
339-
if best_level_score is not None:
340-
this_level_score = levels_score.get(loop_price, 9999999)
341-
if abs(this_level_score - best_level_score) > (0.3 * level_score_range):
342-
if self.debug_enable:
343-
self.log("Skipping price {} as level score {} is not within 30% of best {}".format(loop_price, this_level_score, best_level_score))
344-
continue
337+
for coarse in [True, False] if enable_coarse_fine else [False]:
338+
if not enable_coarse_fine:
339+
charge_slot_choices = FINE_SLOT_LENGTHS
340+
export_slot_choices = FINE_SLOT_LENGTHS
341+
elif coarse:
342+
charge_slot_choices = COARSE_SLOT_LENGTHS
343+
export_slot_choices = COARSE_SLOT_LENGTHS
344+
else:
345+
charge_slot_choices = slots_around(best_max_charge_slots, FINE_SLOT_LENGTHS)
346+
export_slot_choices = slots_around(best_max_export_slots, FINE_SLOT_LENGTHS)
345347

346348
pred_table = []
347-
charge_freeze_options = [True, False] if self.set_charge_freeze and not coarse else [False]
348-
export_freeze_options = [True, False] if self.set_export_freeze and not coarse else [False]
349-
min_freeze_percent = calc_percent_limit(self.best_soc_min, self.soc_max)
349+
charge_freeze_options = [True, False] if (self.set_charge_freeze and not coarse) else [False]
350+
export_freeze_options = [True, False] if (self.set_export_freeze and not coarse) else [False]
351+
350352
for max_charge_slots in charge_slot_choices:
351353
for max_export_slots in export_slot_choices:
352354
for try_charge_freeze in charge_freeze_options:
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{"charge_limit_best": [0.38, 0.38, 0.52, 0.38, 0.52, 9.52, 9.52, 9.52, 9.52, 0.38, 0.38, 0.38, 9.52, 9.52], "charge_window_best": [{"start": 1020, "end": 1080, "average": 25.58, "target": 0.38}, {"start": 1140, "end": 1170, "average": 25.58, "target": 0.38}, {"start": 1170, "end": 1230, "average": 25.58, "target": 0.52}, {"start": 1230, "end": 1350, "average": 25.58, "target": 0.38}, {"start": 1350, "end": 1380, "average": 25.58, "target": 0.52}, {"start": 1410, "end": 1660, "average": 7.0, "target": 9.505}, {"start": 1680, "end": 1735, "average": 7.0, "target": 9.519}, {"start": 1740, "end": 1770, "average": 7.0, "target": 9.518}, {"start": 1770, "end": 1980, "average": 25.58, "target": 9.52}, {"start": 2100, "end": 2130, "average": 25.58, "target": 0.38}, {"start": 2520, "end": 2580, "average": 25.58, "target": 0.38}, {"start": 2640, "end": 2700, "average": 25.58, "target": 0.38}, {"start": 2850, "end": 3210, "average": 7.0, "target": 9.52}, {"start": 3210, "end": 3900, "average": 25.58, "target": 9.52}], "export_window_best": [{"average": 75.0, "end": 1140, "start": 1080, "set": 69.8, "target": 9}, {"average": 15.0, "end": 1680, "start": 1660, "set": 14.0, "target": 90}, {"average": 15.0, "end": 1740, "start": 1735, "set": 14.0, "start_orig": 1710, "target": 98}], "export_limits_best": [4, 86.0, 93.0]}
1+
{"charge_limit_best": [0.38, 0.38, 0.52, 0.38, 0.52, 9.52, 9.52, 9.52, 9.52, 0.38, 9.52, 9.52], "charge_window_best": [{"start": 1020, "end": 1080, "average": 25.58, "target": 0.38}, {"start": 1140, "end": 1170, "average": 25.58, "target": 0.38}, {"start": 1170, "end": 1230, "average": 25.58, "target": 0.52}, {"start": 1230, "end": 1350, "average": 25.58, "target": 0.38}, {"start": 1350, "end": 1380, "average": 25.58, "target": 0.52}, {"start": 1410, "end": 1660, "average": 7.0, "target": 9.505}, {"start": 1680, "end": 1735, "average": 7.0, "target": 9.519}, {"start": 1740, "end": 1770, "average": 7.0, "target": 9.518}, {"start": 1770, "end": 1980, "average": 25.58, "target": 9.52}, {"start": 2700, "end": 2820, "average": 25.58, "target": 0.38}, {"start": 2850, "end": 3210, "average": 7.0, "target": 9.52}, {"start": 3210, "end": 3900, "average": 25.58, "target": 9.52}], "export_window_best": [{"average": 75.0, "end": 1140, "start": 1080, "set": 69.8, "target": 9}, {"average": 15.0, "end": 1680, "start": 1660, "set": 14.0, "target": 90}, {"average": 15.0, "end": 1740, "start": 1735, "set": 14.0, "start_orig": 1710, "target": 98}], "export_limits_best": [4, 86.0, 93.0]}

docs/apps-yaml.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,21 @@ Valid values are:
215215
threads: auto
216216
```
217217

218+
### enable_coarse_fine_levels
219+
220+
Controls the two-pass coarse/fine optimization algorithm for improved planning performance. The default is True (enabled).
221+
222+
When enabled, Predbat uses a two-pass optimization strategy:
223+
224+
- **Coarse pass**: Quickly evaluates a reduced set of slot length combinations to identify approximately optimal charge/export window sizes
225+
- **Fine pass**: Refines the search by focusing only on slot lengths near those identified as optimal
226+
227+
This significantly reduces planning time while maintaining near-optimal results. You can disable this by setting it to False if needed.
228+
229+
```yaml
230+
enable_coarse_fine_levels: True
231+
```
232+
218233
### Web interface
219234

220235
Docker users can change the web port for the Predbat web interface by setting **web_port** to a new port number. The default port of 5052 must always be used for the Predbat add-on.

0 commit comments

Comments
 (0)