MAINT-28: DECISIONS gives the measured reason for the uncapped give (review M-1); ctl_cycle comment one line + pointer (L-1)
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude
parent
7edf8484d1
commit
e7706150e8
@@ -14,7 +14,7 @@ Why 300 W: the house wanders +-50 W; once the charge resumes it settles at (aim
|
|||||||
|
|
||||||
The flag lives only while the charge-only branch is taken: every cycle that reaches the maintenance loop starts it at False, so a maintenance that ended, a mode change or a missing aim cannot carry a stale True into the next charge (test_maint28.py part 1b). `cycle()` has two returns before that loop, and the flag is kept through them on purpose: "inputs missing" and "readings late" (SAFETY-128) are holds of under `stale_after` seconds that write nothing and decide nothing, so the next full cycle sees the same charge and the same peak. A missed poll must not end a peak pause; a reset there would restart the charge on it (`_maint_shape_suspended` is kept through them the same way).
|
The flag lives only while the charge-only branch is taken: every cycle that reaches the maintenance loop starts it at False, so a maintenance that ended, a mode change or a missing aim cannot carry a stale True into the next charge (test_maint28.py part 1b). `cycle()` has two returns before that loop, and the flag is kept through them on purpose: "inputs missing" and "readings late" (SAFETY-128) are holds of under `stale_after` seconds that write nothing and decide nothing, so the next full cycle sees the same charge and the same peak. A missed poll must not end a peak pause; a reset there would restart the charge on it (`_maint_shape_suspended` is kept through them the same way).
|
||||||
|
|
||||||
It only ever keeps the maintenance charge off. No cut-back is delayed or weakened: the guard's claim is filed as before. While the pause is held the loop works as at 02eac3b, so A also gives for the house (quarters then sit under the aim, A's energy goes to the load: 1.67 kWh in the 45 min below, 0.45 kWh on 1b5f7c9). A cap on that give would conflict with the guard's `lo` (`lo > hi` resolves to 0 W), so it is not tried here.
|
It only ever keeps the maintenance charge off. No cut-back is delayed or weakened: the guard's claim is filed as before. While the pause is held the loop works as at 02eac3b, so A also gives for the house (quarters then sit under the aim, A's energy goes to the load: 1.67 kWh in the 45 min below, 0.45 kWh on 1b5f7c9). Measured alternative, A capped at 0 W while held and the guard idle (review scratch, same 45 min run): A gives 0.44 kWh in the load instead of 1.66, quarters 5919/5915 W, but A switches give/idle 32 times in 40 min. The uncapped give costs ~1.2 kWh round trip per 45-min peak (a few cents) and ~50 min more maintenance charge, far inside the 36 h timeout, so the steady give is kept.
|
||||||
|
|
||||||
## Numbers (sim, real `cycle()`, A rated 2500 W)
|
## Numbers (sim, real `cycle()`, A rated 2500 W)
|
||||||
House 3000 -> 6500 W for 45 min -> 3000 W, +-50 W every 5 s, banked month peak 6000 W (aim 5950 W), forecast = quarter average so far plus the rest at the present grid (`scratch/MAINT-28/dev/m28_repro.py`; `test_maint28.py` runs the same shape for 15 min to keep the suite short).
|
House 3000 -> 6500 W for 45 min -> 3000 W, +-50 W every 5 s, banked month peak 6000 W (aim 5950 W), forecast = quarter average so far plus the rest at the present grid (`scratch/MAINT-28/dev/m28_repro.py`; `test_maint28.py` runs the same shape for 15 min to keep the suite short).
|
||||||
|
|||||||
@@ -568,10 +568,8 @@ class CycleMixin:
|
|||||||
maint_aim = peakguard.quarter_target_w(
|
maint_aim = peakguard.quarter_target_w(
|
||||||
float(self.o.get("peak_cap_w", 3500)),
|
float(self.o.get("peak_cap_w", 3500)),
|
||||||
self.peak_margin_w, _reading)
|
self.peak_margin_w, _reading)
|
||||||
# MAINT-28: stays paused until the house is clear of the aim.
|
# MAINT-28: hold the pause in a real peak.
|
||||||
# Only where MAINT-24 moved the aim (a banked peak above the
|
# DECISIONS/MAINT-28-hold-the-pause-in-a-peak.md
|
||||||
# cap) and at N=2 and up: elsewhere the old rule, byte for byte
|
|
||||||
# (SAFETY-87 / SAFETY-119 pins).
|
|
||||||
house = (None if self.grid is None or self.site_batt_w is None
|
house = (None if self.grid is None or self.site_batt_w is None
|
||||||
else float(self.grid) + float(self.site_batt_w))
|
else float(self.grid) + float(self.site_batt_w))
|
||||||
_susp = peakguard.shaping_suspended(
|
_susp = peakguard.shaping_suspended(
|
||||||
|
|||||||
Reference in New Issue
Block a user