Skip to content

Commit fb28dc2

Browse files
committed
[apply-freeze-ac-flow] run clean AC-flow rewrite
1 parent e204026 commit fb28dc2

1 file changed

Lines changed: 55 additions & 0 deletions

File tree

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
from pathlib import Path
2+
3+
4+
def replace_once(path, old, new):
5+
p = Path(path)
6+
text = p.read_text()
7+
count = text.count(old)
8+
if count != 1:
9+
raise RuntimeError(f"{path}: expected exactly one match, found {count}")
10+
p.write_text(text.replace(old, new, 1))
11+
12+
13+
replace_once(
14+
"apps/predbat/prediction.py",
15+
''' # Some inverters (observed on AlphaESS) continue to discharge the battery\n # during Freeze Export to supply house load. The configured value is measured\n # battery-side power, so pass it through the normal discharge and inverter-loss\n # paths, cap it at remaining house demand, and never create additional export.\n if inverter_freeze_export_discharge_rate > 0 and battery_draw >= 0:\n freeze_house_demand = get_diff(battery_draw, pv_dc, pv_ac, load_yesterday, inverter_loss, inverter_loss_recp)\n if freeze_house_demand > 0:\n freeze_soc_available = min(inverter_freeze_export_discharge_rate * step / 60000.0, max(soc - reserve_expected, 0))\n freeze_draw_limit = freeze_soc_available * battery_loss_discharge\n freeze_draw_for_house = freeze_house_demand * inverter_loss_recp\n battery_draw = min(freeze_draw_limit, freeze_draw_for_house)\n''',
16+
''' # Some inverters (observed on AlphaESS) continue a residual battery\n # discharge during Freeze Export. The configured value is measured battery-side\n # power; feed it into the normal AC energy balance so house load consumes it first\n # and any excess naturally becomes grid export.\n if inverter_freeze_export_discharge_rate > 0 and battery_draw >= 0:\n freeze_soc_available = min(inverter_freeze_export_discharge_rate * step / 60000.0, max(soc - reserve_expected, 0))\n freeze_draw_limit = freeze_soc_available * battery_loss_discharge\n battery_draw = max(battery_draw, freeze_draw_limit)\n''',
17+
)
18+
19+
replace_once(
20+
"apps/predbat/prediction_kernel.cpp",
21+
''' // Some inverters (observed on AlphaESS) continue to discharge the battery\n // during Freeze Export to supply house load. The configured value is battery-side\n // power; route it through normal discharge and inverter losses and cap at load.\n if (inverter_freeze_export_discharge_rate > 0 && battery_draw >= 0) {\n const double freeze_house_demand = get_diff(battery_draw, pv_dc, pv_ac, load_yesterday, inverter_loss, inverter_loss_recp);\n if (freeze_house_demand > 0) {\n const double freeze_soc_available = std::min(inverter_freeze_export_discharge_rate * step / 60000.0, std::max(soc - reserve_expected, 0.0));\n const double freeze_draw_limit = freeze_soc_available * battery_loss_discharge;\n const double freeze_draw_for_house = freeze_house_demand * inverter_loss_recp;\n battery_draw = std::min(freeze_draw_limit, freeze_draw_for_house);\n }\n }\n''',
22+
''' // Some inverters (observed on AlphaESS) continue a residual battery\n // discharge during Freeze Export. The configured value is battery-side power; feed\n // it into the normal AC energy balance so house load consumes it first and any excess\n // naturally becomes grid export.\n if (inverter_freeze_export_discharge_rate > 0 && battery_draw >= 0) {\n const double freeze_soc_available = std::min(inverter_freeze_export_discharge_rate * step / 60000.0, std::max(soc - reserve_expected, 0.0));\n const double freeze_draw_limit = freeze_soc_available * battery_loss_discharge;\n battery_draw = std::max(battery_draw, freeze_draw_limit);\n }\n''',
23+
)
24+
25+
replace_once(
26+
"apps/predbat/prediction_kernel.cpp",
27+
"#define PK_PARITY_REVISION 8\n",
28+
"#define PK_PARITY_REVISION 9\n",
29+
)
30+
31+
replace_once(
32+
"apps/predbat/prediction_kernel.py",
33+
"KERNEL_PARITY_REVISION = 8\n",
34+
"KERNEL_PARITY_REVISION = 9\n",
35+
)
36+
37+
replace_once(
38+
"apps/predbat/predbat.py",
39+
" # Battery-side discharge (W) that may continue to supply house load during Freeze Export.\n",
40+
" # Battery-side residual discharge (W) during Freeze Export; AC balance decides house use vs export.\n",
41+
)
42+
43+
replace_once(
44+
"apps/predbat/tests/test_model.py",
45+
''' # Freeze Export discharge should represent real battery energy supplied to house load.\n # Normal battery discharge is disabled here so only this configured path is under test.\n # 240 W for one hour is 0.24 kWh battery-side.\n''',
46+
''' # Freeze Export residual discharge is real battery energy delivered to the AC side.\n # House load consumes it first and any excess can flow to grid export. Normal battery\n # discharge is disabled here so only this configured path is under test.\n # 240 W for one hour is 0.24 kWh battery-side.\n''',
47+
)
48+
49+
replace_once(
50+
"apps/predbat/tests/test_model.py",
51+
''' failed |= simple_scenario(\n "freeze_export_house_supply_no_load",\n my_predbat,\n 0,\n 0,\n assert_final_metric=0,\n assert_final_soc=10.0,\n battery_size=10.0,\n battery_soc=10.0,\n discharge=99,\n end_record=60,\n inverter_freeze_export_discharge_rate=240.0,\n battery_rate_max_charge=0.0,\n assert_battery_cycle=0.0,\n )\n''',
52+
''' failed |= simple_scenario(\n "freeze_export_residual_exports_when_no_load",\n my_predbat,\n 0,\n 0,\n assert_final_metric=-1.2,\n assert_final_soc=9.76,\n battery_size=10.0,\n battery_soc=10.0,\n discharge=99,\n end_record=60,\n inverter_freeze_export_discharge_rate=240.0,\n battery_rate_max_charge=0.0,\n assert_battery_cycle=0.24,\n )\n''',
53+
)
54+
55+
print("Freeze Export residual AC-flow rewrite applied")

0 commit comments

Comments
 (0)