Skip to content

fix: don't end a steady-current run on a ramp-up overshoot - #32

Merged
zebraengine merged 1 commit into
mainfrom
fix/steady-prefix-ramp-overshoot
Sep 15, 2026
Merged

zebraengine merged 1 commit into
mainfrom
fix/steady-prefix-ramp-overshoot

Conversation

@zebraengine

Copy link
Copy Markdown
Owner

Problem

The first live calibration probe (session 80, 2026-09-14) held 32.5 A for forty minutes and its window was never fitted — even after a forced refit. The car's ramp-up read 6 → 15 → 24 → 31 → 32.6, 32.7, 32.9, then 37.6, 43.3 (two samples overshooting toward the 48 A it was headed for, in the seconds before the probe cap took effect at +37 s), then 32.5 A for the rest of the hold. _steady_current_prefix treats the first out-of-band sample after a run has started as "the steady run ended", so it kept a 4-sample, 6-second window that failed the very next gate (span >= 1.8 τ).

Every probe lands mid-ramp (the controller caps a few seconds after charging starts), so every probe would have been lost the same way — which defeats both the degradation watch's fixed-condition comparison and the current-exponent fit that #31 added.

Code touched

  • wallmonitor/thermal.py: PREFIX_SETTLE_S = 60. In _steady_current_prefix, an out-of-band sample within the first minute of a run discards the run and restarts it instead of ending it. A current change after that still ends it. Docstring + constant comment explain the incident.
  • tests/test_wallmonitor.py: direct test on the prefix finder with the exact ramp from session 80 (600-sample window recovered, starting at 32.5 A), and a settled run that a later current change still ends.

Left alone: i_ref (median of the first 10 min), the band, the span cap, sag / free-plateau detection.

Risk

  • Fits can appear for sessions that were previously rejected on a ramp wobble. On production that is two: session 80 (the probe, free-running) and session 41 (a 35.5 A regulated window from July — excluded from the drift watch by free_plateau, admitted to the τ/rise medians, where it moves rise_ref_c 36.3 → 36.1).
  • The current exponent moves 1.20 → 1.56 ± 0.09 on production, because the probe is its first 32 A point and has the most leverage. The 32.5 A and 44.4 A fits independently agree on n ≈ 1.7; the two 39.6 A fits (both on the two hottest consecutive evenings) read ~3.5 °C above that line, so the regression splits the difference. Monthly probes will pin it. At the operating point: sustainable at 29.5 °C ambient is 45 A (44 under 1.2, 46 under I²).
  • Drift watch: verdict unchanged (delta +0.13, CI [−2.83, 3.10], not drifting, no lead). Residual sd rises 0.85 → 1.44 because the 39.6 A pair no longer lines up; ambient coefficient 0.35 ± 0.24 — not significant, compromised_by empty.

Verification

  • uv run pytest: 152 passed (one new).
  • Replayed on the production DB (read-only scratch worktree on the mini-PC): session 80 fits at 32.5 A, 18.7 °C raw rise, τ 13.75 min, RMSE 0.26, free-running, ambient bracketed 30.98 → 29.05 (sensor). Model: n 1.56, rise_ref 36.1, 19 rise fits.
  • Gate-by-gate diagnostic of the original failure: prefix = 4 samples over 6 s, current med 32.7 → span >= 1.8 τ False. Raw vitals dump confirmed the overshoot pattern above.

Deploy: pull + sudo systemctl restart wallmonitor.service. The probe's fit appears retroactively — no new charging session needed.

🤖 Generated with Claude Code

The first live calibration probe held 32.5 A for forty minutes and its
window was never fitted. The car's ramp read 6, 15, 24, 31, 32.6, 32.7,
32.9, then 37.6 and 43.3 - two samples overshooting toward the 48 A it was
headed for, in the seconds before the probe cap took effect - and then
32.5 A for the rest of the hold. The steady-prefix finder treats the first
out-of-band sample after a run has started as that run ending, so it kept
a four-sample, six-second window and lost the real one at the very next
gate.

Every probe lands mid-ramp, so every probe would have been lost the same
way. A run that leaves the band within its first minute is now discarded
and restarted rather than ended; a current change after that still ends
it.

On the production database the probe now fits (32.5 A, 18.7 C of rise,
free-running, RMSE 0.26) and joins the current-exponent fit as its first
32 A point: n moves from 1.20 to 1.56 +/- 0.09. The drift verdict is
unchanged. One earlier session whose ramp wobbled the same way (s41, a
regulated window) is admitted too.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@zebraengine
zebraengine merged commit 2d4d58e into main Sep 15, 2026
1 check 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