Kalibratie van oversizing en avondoverlap

Hoe we bepalen wanneer een batterij te groot is voor het dagelijkse overschot, en hoeveel van het avondverbruik een batterij werkelijk kan dekken.

Dit is het onderzoeksdocument zoals het is vastgelegd, ongewijzigd overgenomen uit docs/calibration/oversize-and-overlap.md. Het is in het Engels geschreven.

Run: 29 July 2026 · bun scripts/calibration/harness.tsoversize.ts and overlap.ts Constants: policyAssumptions.oversizeSurplusMultiple (was 2) and policyAssumptions.pvEveningOverlap (0.05)

Both were carried as unverified with the note "calibrate via the chronological harness". The v1 scope memo wrongly said this was a re-run with no decision needed: one needed a different metric than the obvious one, the other was not identifiable from the harness as it stood and needed a new measurement emitted from it. Both are now calibrated from committed data.

Outcome: oversizeSurplusMultiple approved at 1.5 (was 2, too permissive). pvEveningOverlap recommended at 0.07 (was 0.05, biased battery-favourable) — awaiting sign-off.


1. oversizeSurplusMultiple — calibrated, and the current value is too permissive

Method

The guardrail excludes a battery whose usable capacity exceeds multiple × median Apr–Sep daily surplus. For each of the 81 Phase C grid cells the script recomputes the engine's own median Apr–Sep daily surplus, forms the size ratio the guardrail tests, and reports measured utilization against it. No new weather or load data — it reads results.json and the verified assumption set.

The metric matters, and the obvious one is wrong

The first attempt used captureShiftSolved and produced an inverted result: cells the guardrail flags showed higher capture (0.98) than cells it keeps (0.79).

That is not a real effect. captureShiftSolved is the factor that makes the monthly model reproduce the chronological result. When a battery is very large relative to surplus, both models become surplus-limited rather than battery-limited, so they agree and the solved capture rises toward 1. Reading that as "the big battery performs well" would invert the guardrail.

The correct signal is utilization — annual kWh shifted per usable kWh, i.e. equivalent full cycles per year. It is the same quantity the engine already reports as utilizationYear1KwhPerUsableKwh for G12, and it measures what the guardrail is actually about: capacity that never gets cycled.

Result

size ratio (usable ÷ median daily surplus)nutilization p25medianp75
0.0–0.540139177211
0.5–1.0247584111
1.0–1.511465068
1.5–2.02343434
2.0–2.52303539
2.5–3.02272830

Monotonic decline, then a clear flattening: 177 → 84 → 50 → 34, after which added capacity buys almost nothing (34 → 35 → 28). At the current multiple of 2 the guardrail flags only 4 of 81 cells; the 77 it keeps have a median utilization of 117 cycles/yr, but that average hides cells at ratio 1.5–2.0 cycling just 34 times a year — a fifth of a well-sized battery.

Recommendation — 1.5, with a stated caveat

The elbow sits at roughly 1.5: beyond it marginal capacity stops producing throughput. A multiple of 2 only catches the most extreme over-purchases and lets through batteries cycling ~34 times a year, which is exactly the "te groot gekocht" case the guardrail exists to name.

The caveat is real and must travel with the number. The Phase C grid has three battery sizes × three PV ratios × three orientations × three loads, so ratio bands above 1.5 contain only two cells each. The direction is solid; the precise crossing point is not. Two options:

  1. Approve 1.5 now with the thin-sample limitation documented on the methodology page. The guardrail is a flag, not a hard exclusion from the catalogue, so the cost of being slightly wrong is low and the current value is demonstrably too loose.
  2. Densify the grid first — more battery sizes and PV ratios. The harness is deterministic and cheap to re-run; this would firm the crossing before freezing it.

Recommended: option 1, with option 2 queued as a post-launch refinement. This is a calibrated constant, so it needs founder approval on the evidence rather than a self-stamp — the same route the capture factor took.


Status: approved by Ev 29 July 2026 at 1.5, with the thin-sample limitation recorded in the constant's source line and to be disclosed on the methodology page.


2. pvEveningOverlap — calibrated; recommend 0.07, not the least-squares fit

pvEveningOverlap (0.05) is the term in the monthly deficit heuristic (spec §3.3):

deficit(month) = consumption(month) × eveningShare − pv(month) × pvEveningOverlap

The identification problem, and how it was solved

The constant could not be calibrated from the existing harness for two reasons. First, the harness consumed the value when building the baseline it solved the capture factor against — circular. Second, and more fundamentally, the solve matched one quantity (annual shifted energy) that depends on two unknowns: any overlap can be absorbed by a compensating capture factor. That is why 0.05 survived unexamined.

harness.ts now emits, per cell and per month, the chronological dischargeable demand — hourly max(0, load − pv) summed per month. It is the measured counterpart of the heuristic and depends on the overlap alone, supplying the missing second equation. scripts/calibration/overlap.ts fits the heuristic to it across 27 deduplicated cells × 12 months, with eveningShare held at its approved 0.6465.

Result

overlapRMSE (kWh/month)mean bias (kWh/month)
0.0065.4+21.2
0.05 (current)52.1+5.9
0.07 (zero-bias)48.2−0.2
0.1044.4−9.3
0.121 (min RMSE)43.6−15.8
0.2053.1−39.4

A positive bias means the heuristic overstates the demand a battery can serve, letting the monthly model shift more energy than chronology allows — the battery-favourable error. The current 0.05 is biased that way.

Why the least-squares fit is the wrong answer

Re-running the capture-factor solve at each candidate is decisive:

overlapcapture p10 / p50 / p90unsolvable cells
0.05 (as approved)0.518 / 0.794 / 0.9011
0.070.525 / 0.794 / 0.9011
0.1210.654 / 0.834 / 0.9585

At 0.121 the capture distribution shifts materially upward and unsolvable cells rise from 1 to 5 — the tightened heuristic starts binding below chronological reality. Adopting it would invalidate the founder-approved capture triple 0.55/0.70/0.85, which would have to be reopened and re-approved.

At 0.07 the capture distribution is unchanged to three decimals at the median and p90. The approved triple stands.

The two criteria differ because RMSE is dominated by summer months, where the large PV term and the zero-clamp do most of the work, while the annual total is what actually feeds the economics. For a constant that caps annual shifted energy, an unbiased annual total is the right criterion.

Recommendation — 0.07, founder decision required

It removes the battery-favourable bias in the current value (+5.9 → −0.2 kWh/month), improves RMSE (52.1 → 48.2), and leaves the approved capture calibration intact. The minimum-RMSE value fits the monthly shape slightly better but buys that at the cost of reopening a signed-off constant and degrading solvability.

Left unverified pending sign-off — it is a calibrated constant and the approval date belongs to the founder, not to the person who ran the fit.

Effect on the gate

Four constants were open before this work. oversizeSurplusMultiple (1.5) and chargeWindowHoursPerDay (8) are now approved and verified. Two remain: pvEveningOverlap (0.07 recommended above, awaiting sign-off) and degradationToPctYr10 (warranty PDFs — Codex's fixed-track research should surface several retention floors).