Skip to content

fix(loadmodel): bound the heating estimate by the house's own use - #1495

Merged
frahlg merged 1 commit into
masterfrom
1491-heating-bound
Oct 1, 2026
Merged

frahlg merged 1 commit into
masterfrom
1491-heating-bound

Conversation

@frahlg

@frahlg frahlg commented Oct 1, 2026

Copy link
Copy Markdown
Member

Problem

The legacy load twin cannot lower a heating coefficient that is set too high:

  • Update skips an hour's base sample whenever the heating estimate exceeds the measured load.
  • The fit that moves the coefficient runs only in hours with eight trained days.

So an overstated coefficient never trains the hours it overstates, and never comes down. The home box had weather.heating_w_per_degc: 300: about 2.4 kW of assumed heat at 10 °C against a measured night load of 0.35–0.45 kW. The plan's night load was about 2 kW too high every night. (That setting is now removed on the box.)

Change

Heating is part of the house's load, so over a day's cold samples coef × Σ(18 °C − T) ≤ Σ load.

  • Each local day with at least six hours of samples below 15 °C yields that bound.
  • Once the last three such days all put the coefficient above their bound, it moves halfway toward the highest of them.
  • The bound needs no trained hours. It only lowers the coefficient; the existing fit still raises it.
  • The model saves the day's sums and the last three bounds in new fields. Old state loads with empty sums and the same feature hash, so no site loses what it has learned.

Three days, not one: a single day with a wood stove or the heating off has a low bound, and would otherwise halve a correct coefficient. Only the slow fit would raise it again.

Results (simulated, one sample a minute)

Case Coefficient 02:00 error before → after
Home box: 300 W/°C prior, flat 400 W at 10 °C 175 → 112.5 → 81.25 → … → 50 2,650 → 650 W
Real heating: 300 W + 200 W/°C, start 150 or 200 unchanged —
Real heating, start 400 falls to about 223, never below 200 —
Real heating, one day with the heating off unchanged at 200 —

What this does not fix

Night hours still do not train in a house whose night load is below its daily average. The bound settles near the day's mean load ÷ mean ΔT, so the heating estimate stays above the night load and those buckets keep their prior. A day-shaped house without electric heating (mean 1,209 W, 300 W at night, 10 °C) improves from 2,750 to about 1,560 W too high at 02:00, but not to zero. #1491 stays open for that. Options for the owner:

Tests

  • TestHeatingBoundLowersAnOverstatedPrior: the home box case steps at Thu, Fri and Sat midnight.
  • TestHeatingBoundKeepsRealHeating, TestHeatingBoundIgnoresOneUnusualDay, TestHeatingBoundIgnoresMildDays, TestHeatingBoundNeedsSixColdHours.
  • TestHeatingBoundSumsSurviveRestart, TestStateWithoutHeatingBoundStillLoads; TestFeatureHashPinned unchanged.
  • A single-day bound fails three of these tests. make verify clean.

Refs #1491. One of four forecast fixes found while evaluating #1482, with #1492, #1493 and #1494. It shares no files with them. No forecast policy bump: #1494 already starts a new evaluation cohort in the same release.

🤖 Generated with Claude Code

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-01T17:33:08.071708Z 742b3d0 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

A heating coefficient set too high could not come down. The fit that
moves it runs only in an hour of the week with eight trained days, and
an hour trains only when the heating estimate is at or below the
measured load. On the home box, 300 W/°C against a 400 W night load at
10 °C put the plan's night load about 2 kW too high, and the night hours
never trained.

Heating is part of the house's load, so over a day's cold samples
coef × Σ(18 °C − T) ≤ Σ load. Each local day with at least six hours
of samples below 15 °C yields that bound. Once the last three such days
all put the coefficient above their bound, it moves halfway toward the
highest of them, so one day with a wood stove or the heating off cannot
pull a correct coefficient down. The bound needs no trained hours and
never raises the coefficient.

The model saves the day's sums and the last three bounds in new
fields. State saved before this change loads with empty sums, and the
feature hash stays the same, so no site loses what it has learned.

Refs #1491

Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@frahlg
frahlg force-pushed the 1491-heating-bound branch from 0924a23 to 695e9ec Compare October 1, 2026 18:29
@frahlg
frahlg merged commit a9dc0e3 into master Oct 1, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant