docs: plan HOLD-state pid_heat windup fix from overshoot investigation

Records the root cause of the cold-water overshoot in docs/overshoot.png
(integral windup in pid_heat with no anti-windup engagement, since y never
saturated) and the refined fix plan: gate pid_heat by FSM state instead of
a flat yi_max clamp, which was rejected after the numbers showed it would
also cripple legitimate high-rate ramps.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KefnwbGDM8CGrhb4sFhVq9
This commit is contained in:
2026-07-04 12:31:58 +02:00
co-authored by Claude Sonnet 5
parent 8689494be0
commit 13bb011099
3 changed files with 164 additions and 0 deletions
+16
View File
@@ -63,6 +63,22 @@ git history for `temp_controller.py`/`temp_controller_smith.py`).
before that file was removed entirely — `Pot` dropped `gain`
entirely, see `components/plant/TODO.md`.
- [ ] **`pid_heat` can wind up during a `HOLD`-state disturbance with no
anti-windup engagement.** A cold-water disturbance while holding drove
`pid_heat`'s integral term up without ever saturating `y` (peaked at
`y≈0.74` of the `1.0` ceiling), so the existing back-calculation
anti-windup (`Pid.process()`, `pid.py:45-48`) never triggered — the FSM
never even left `HOLD` (`diff` stayed under `HoldHeat=1.0`). The
resulting overshoot took ~35s+ to unwind naturally. A flat `yi_max`
clamp was considered and rejected: sustaining a genuine 1.5 K/min ramp
needs `y≈0.7-0.75` from `yi` alone at steady state, the same range the
disturbance itself peaked at, so no single clamp value can suppress the
windup without also capping legitimate ramps. Plan is instead to gate
`pid_heat`'s activity by FSM state (frozen/offline while `HOLD`, engaged
by command or a new `HoldHeatEngage` threshold) — see
`docs/overshoot_hold_windup.md` for the full writeup, open design
question (threshold relationship with `HoldHeat`), and test plan.
- [ ] **`kalman.py` is now dead code in production.** Neither
`temp_controller.py` nor `temp_controller_smith.py` uses `Kalman`
anymore; the only remaining references are