Score forecasts against reality; expose forecast trajectories

There was no evidence of how accurate the thermal model is: the only
number was an in-sample 5-minute error.

At every poll, record each room's reading, the outdoor temperature, the
radiator-lag estimate and the model parameters. 15, 30, 60 and 120
minutes later, replay the room from that poll with the parameters it
had then (out of sample), the outdoor temperature held constant and the
radiator lag that actually followed from the relay's real history, and
compare with the reading now. A no-change forecast is scored alongside.
Only spans with regular polls and a well-known lag are scored. 7 days
of per-room statistics are saved with the model (optional "evaluation"
payload key; about 18 KB at most).

Four new sensors, Heating MPC Forecast Error 15/30/60/120 min, show the
mean absolute error with bias, persistence error, skill and per-room
detail. On the synthetic lagged plant the 60-minute error is 0.03 °C
against 0.39 °C for persistence.

Room forecast entities gain forecast_15min and plan_15min attributes
and are labelled counterfactual. Volatile attributes are unrecorded.
The model is now saved after scoring, so saved statistics are current.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
buzeraandClaude Opus 5.5 committed 2026-10-26 22:35:13 +02:00
1 parent 43915ba810
commit 3afb6688a5
9 files changed
+454 -16

No files matched your search

+40 -1
View File
@@ -50,8 +50,13 @@ Entities (entity IDs may vary):
- `sensor.heating_mpc_status` — learning/ready/paused status and diagnostics, including outside weather, active source, all valid alternative weather values, model coefficients, proposed 15-minute plan.
- `sensor.heating_mpc_weighted_temperature` — own room-weighted average, informative only.
- `sensor.mpc_outdoor_temperature` — selected external temp and alternatives.
- Per-room predicted temperatures after 60 minutes.
- Per-room predicted temperatures after 60 minutes. Attributes `forecast_15min` (the
temperature every 15 minutes over the horizon) and `plan_15min` (the proposed
ON/OFF plan). These assume the MPC's plan is executed; while Generic Thermostat
controls the relay they are **counterfactual**.
- `binary_sensor.heating_mpc_proposed_heat` — **hypothetical** heating demand (unavailable until ready).
- **Heating MPC Forecast Error 15/30/60/120 min** — how far the thermal model's
forecasts were from what actually happened (see *Forecast accuracy*).
## Known limitations / safety
@@ -126,6 +131,40 @@ After a day of running, set each limit comfortably above (about 1.5–2×) the l
`max_age_seconds_24h` among the sensors it covers. The relay and thermostat have no
age limit.
## Forecast accuracy
The four **Forecast Error** sensors measure the thermal model against reality,
continuously and out of sample. At every poll the integration records each room's
reading, the outdoor temperature, the radiator-lag estimate and the model's
parameters. 15, 30, 60 and 120 minutes later it replays that room from the earlier
reading using the parameters it had **then**, the outdoor temperature held at its
starting value, and the radiator heat that actually followed from the relay's real
ON/OFF history. The result is compared with the current reading.
This tests the thermal model, not the MPC plan, because the plan is never
executed. Each sensor's state is the mean absolute error (°C) over the last 7 days,
across all rooms. Attributes, all in °C except counts:
- `samples` — number of scored forecasts. Consecutive forecasts overlap, so they
are not independent; treat small counts as indicative only.
- `bias` — mean error: negative means the model predicts too cold.
- `persistence_mae` — error of simply assuming no change; the baseline to beat.
- `skill` — `1 - mae / persistence_mae`: 1 is perfect, 0 is no better than
assuming no change, negative is worse. Empty while the temperature did not change.
- `rooms` — the same numbers per room (not written to the Recorder).
Forecasts are scored only where the inputs were known: polls 4.5–5.5 minutes
apart, a usable reading at the start and the end, and a well-known radiator-lag
estimate throughout. A missing relay, outdoor temperature or all rooms restarts the
replay window, so scores resume 15–120 minutes later. Statistics are kept with the
model and survive restarts; deleting the model resets them.
What it does not cover: outdoor temperature changes during the horizon (held
constant, as in the MPC), and periods when the model was still learning (included,
so early numbers are pessimistic). The roadmap's working target is about
0.3–0.4 °C at 60 minutes with clearly positive skill, before any control is
considered.
## Release notes
See [CHANGELOG.md](CHANGELOG.md) for changes and upgrade notes per version, and