Problem
The legacy load twin can stop learning cold hours for good when its heating coefficient is too high:
Update skips the hour's base sample whenever heatingGain(coef, T) exceeds the measured load.
- The coefficient adapts only in buckets with 8 trained days, which takes 8 weeks per hour of the week.
So a coefficient that overstates heating cannot correct itself, and the hours it overstates never train.
Evidence
- The home box had
weather.heating_w_per_degc: 300: about 2.4 kW of assumed heating 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.
- Reproduction against
loadmodel.Model: 300 W/°C, 400 W real load, ten days of 15-minute samples → 0 of 168 buckets warm, coefficient still 300, predicted 3,139 W at 10 °C (959 W at 17 °C).
Fix
Bound the coefficient by physics: over a day, heating cannot exceed the total load, so coef ≤ Σ load / Σ (18 °C − T) for that day's cold samples. Apply the bound at each day's end, independent of bucket warmth.
Related: #1482.
Problem
The legacy load twin can stop learning cold hours for good when its heating coefficient is too high:
Updateskips the hour's base sample wheneverheatingGain(coef, T)exceeds the measured load.So a coefficient that overstates heating cannot correct itself, and the hours it overstates never train.
Evidence
weather.heating_w_per_degc: 300: about 2.4 kW of assumed heating 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.loadmodel.Model: 300 W/°C, 400 W real load, ten days of 15-minute samples → 0 of 168 buckets warm, coefficient still 300, predicted 3,139 W at 10 °C (959 W at 17 °C).Fix
Bound the coefficient by physics: over a day, heating cannot exceed the total load, so
coef ≤ Σ load / Σ (18 °C − T)for that day's cold samples. Apply the bound at each day's end, independent of bucket warmth.Related: #1482.