Refresh design-backlog docs after Pot's gain/theta cleanup

Drop the now-stale "config.json.templ/.sim still carry dead
Model.kn/Plant.kn keys" note (they were deleted), note that Pot now
always starts at theta_amb (no separate initial-temp param) and that
dropping the gain (efficiency) factor entirely is a partial realism
regression, not just a fix. Point the config-validation item at the
gain key that's still dead in config.json.sim. Also update demo_sud.py
to match the Pot params Pot.__init__ actually reads.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-19 18:37:03 +02:00
co-authored by Claude Sonnet 4.6
parent 17ca79da1a
commit 2845051350
3 changed files with 32 additions and 25 deletions
+7 -6
View File
@@ -52,15 +52,16 @@ git history for `temp_controller.py`/`temp_controller_smith.py`).
actually exposes a model to feed. actually exposes a model to feed.
- [ ] **Config access is unchecked `dict[key]` everywhere.** - [ ] **Config access is unchecked `dict[key]` everywhere.**
`params['Hold']`, `model_params['gain']`, etc., throughout, with no `params['Hold']`, `params['Td']`, etc., throughout, with no schema
schema validation at load time. We already hit this bug class once validation at load time. We already hit this bug class once
(`config.json.sim`'s `gain`/`Model` nesting mismatch). A small (`config.json.sim`'s `gain`/`Model` nesting mismatch). A small
schema/dataclass validation layer at config-load would surface schema/dataclass validation layer at config-load would surface
errors immediately instead of mid-`__init__` — and would have caught errors immediately instead of mid-`__init__` — and would have caught
the dead `TempCtrl.Kalman` / `Model.kn` / `Plant.kn` keys still the dead `TempCtrl.Kalman` / `Model.kn` / `Plant.kn` keys that used
sitting in `config.json.templ` and `config.json.sim` (harmless today to sit unused in `config.json.templ`/`.sim` (since deleted) and the
since extra keys are just ignored, but nothing reads them anymore `Model.gain`/`Plant.gain` keys still doing the same in
after the Kalman/`kn` removal — see `components/plant/TODO.md`). `config.json.sim` right now — `Pot` dropped `gain` entirely, see
`components/plant/TODO.md`.
- [ ] **`kalman.py` is now dead code in production.** Neither - [ ] **`kalman.py` is now dead code in production.** Neither
`temp_controller.py` nor `temp_controller_smith.py` uses `Kalman` `temp_controller.py` nor `temp_controller_smith.py` uses `Kalman`
+24 -16
View File
@@ -22,29 +22,37 @@ the current `delay`-line rewrite of `Pot`.
wired up as plant-side measurement noise. Sensor noise is now wired up as plant-side measurement noise. Sensor noise is now
modeled one layer up, in `TempSensorSim` (`temp_offset`/`variance`, modeled one layer up, in `TempSensorSim` (`temp_offset`/`variance`,
wired from `brewpi.py`'s `TempSensorFactory.create(..., temp_offset= wired from `brewpi.py`'s `TempSensorFactory.create(..., temp_offset=
-0.15, variance=0.01)`), not in the plant model. Note: `config.json.templ` -0.15, variance=0.01)`), not in the plant model. The stale
and `config.json.sim` still carry stale `Model.kn`/`Plant.kn` keys `Model.kn`/`Plant.kn` keys this item flagged have since been deleted
that nothing reads anymore — harmless but worth deleting (see from `config.json.templ`/`config.json.sim` too.
`components/pid/TODO.md`'s config-validation item).
- [x] **`theta_amb` is hardcoded, not configured.** Fixed: added a - [x] **`theta_amb` is hardcoded, not configured.** Fixed: added a
top-level `ambient_temperature` key to `config.json`(`.templ`/`.sim`); top-level `ambient_temperature` key to `config.json`(`.templ`/`.sim`);
`brewpi.py` reads it once and passes it to both the real `Pot` and `brewpi.py` reads it once and passes it to both the real `Pot` and
(via a new `theta_amb` param) `temp_controller_smith.py`'s internal (via a new `theta_amb` param) `temp_controller_smith.py`'s internal
models, so the Smith predictor's model matches the real plant's models, so the Smith predictor's model matches the real plant's
assumed ambient instead of silently defaulting to 20. Real ambient assumed ambient instead of silently defaulting to 20. `Pot` also
temperature still isn't modeled as a *drifting* disturbance (it's a dropped its separate `params['theta']` initial-temperature field —
static config value, not a live sensor reading), so robustness to it now always starts at `theta_amb` (so the same config value governs
ambient drift remains untested — that part of the original concern both the assumed ambient *and* the pot's starting temperature; there's
stands. no longer a way to start a sim at a temperature other than ambient).
Real ambient temperature still isn't modeled as a *drifting*
disturbance (it's a static config value, not a live sensor reading,
though `Pot.set_ambient_temperature()` now exists as a hook for that),
so robustness to ambient drift remains untested.
- [ ] **No actuator/process realism.** Partially improved: `process()` - [ ] **No actuator/process realism.** Partially improved (`process()`
now clamps `self.temp` to `min(100, ...)` (won't simulate past clamps `self.temp` to `min(100, ...)`, won't simulate past boiling)
boiling), but there's still no heater power saturation enforced and partially regressed: `Pot` also dropped its `gain` (heater
inside `Pot` itself (handled ad hoc in demo harnesses), no efficiency) factor entirely — `process()` now applies 100% of
evaporation/lid heat loss, and no varying thermal mass `M` as volume commanded power with no loss, whereas before `params['gain']` could
changes (e.g. boil-off, adding water/grain) — `M` is a fixed model e.g. an 80% efficient transfer. `Model.gain`/`Plant.gain` are
constant for the whole simulation. now dead keys in `config.json.sim` (already absent from `.templ`) —
see `components/pid/TODO.md`'s config-validation item. Still no
heater power saturation enforced inside `Pot` itself (handled ad hoc
in demo harnesses), no evaporation/lid heat loss, and no varying
thermal mass `M` as volume changes (e.g. boil-off, adding
water/grain) — `M` is a fixed constant for the whole simulation.
- [x] **Debug `print()`s left in `Pot.process()`.** Fixed: the - [x] **Debug `print()`s left in `Pot.process()`.** Fixed: the
unconditional `p_loss`/`theta_amb`/`temp` prints (leftover from the unconditional `p_loss`/`theta_amb`/`temp` prints (leftover from the
+1 -3
View File
@@ -34,12 +34,10 @@ if __name__ == '__main__':
} }
plant_params = { plant_params = {
"theta" : 20,
"C" : 4190, "C" : 4190,
"M" : 20, "M" : 20,
"L" : 0.2, "L" : 0.2,
"Td" : 30, "Td" : 30
"gain" : 1.0
} }
sud = Sud("sude/sud_0010.json") sud = Sud("sude/sud_0010.json")