feat: a calibration probe plan — two currents, each with a cold cable and a warm one - #36
Merged
Merged
Conversation
… and a warm one The forecast backtest, once its sampling bias was controlled, left one error standing: heat soak from the charge before. It also showed why the history cannot resolve it - the controller chose every run's current on the strength of the model, so hot days and low currents arrive together and an ambient effect, a current-law error and a warm cable all wear the same signature. The fix is a designed experiment, not another fit. The probe becomes a plan: the product of --probe-amps (now a list) and --probe-cable. "cold" is a probe started in a session's first three minutes after --probe-cold-gap-h (4) without charging; "warm" is a mid-session step-down after --probe-warm-min (30) at full rate, uncapped; "any" is the original behavior and the default, so a single-current install is unchanged. The least-replicated condition goes first, and if it can still be met later in the session the daemon waits for it rather than spending the slot on an easier one, unless the slot is overdue by a whole interval. One probe per session. Weekly (--probe-plan-interval-days) until each condition has --probe-replicates (2), then monthly as before, cycling. The cadence is anchored at the probe's session start: anchored at its completion, a session exactly one interval later fell a few minutes short of due at its first tick - the only minutes a cold probe can start in. Each probe's start is recorded in its amp_capped event (detail.probe), and the backtest groups probe runs by condition from that instead of guessing from the current, which had been mis-tagging foldback runs as probes. Deployed as 32,40 x cold,warm this is eight probes over about two months - in a cooling season, also a fixed-current sweep across 15 C of ambient that the summer's controller-chosen history could not provide. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The forecast backtest (#35), once its sampling bias was controlled, left one error standing: heat soak from the charge before — a step-down after a hot full-rate run reads 2.8–3.6 °C optimistic from the sensor. It also showed why the recorded history cannot resolve it: the controller chose every run's current on the strength of the model, so hot days and low currents arrive together, and an ambient effect, a current-law error and a warm cable all wear the same signature. The fix is a designed experiment, not another fit: the same probe current with a cold cable and with a warm one.
Code touched
contrib/derate_amp_control.py--probe-ampstakes a list; new--probe-cable(any|cold|warm, comma-separated),--probe-plan-interval-days(7),--probe-replicates(2),--probe-cold-gap-h(4),--probe-warm-min(30). The plan is currents × cable conditions.normal_amps, uncapped, as a mid-session step-down. any: whenever due (the original behavior; the default).Action.probeandevent_forput{"amps", "cable"}on the probe'samp_cappedevent.deploy/install-derate-amp-control.sh: passes the new flags through.contrib/backtest_forecast.py: probe runs identified from the controller's events (with the pre-plan probe recognized by its reason text) instead of by current — which had been tagging 24 A foldback runs as probes — and grouped per condition (probe 32A cold…). Docs: amp-control.md "A probe plan"; thermal-model.md cross-reference.Risk
Nothing else changes for an install without
--probe-cable: the single-current,anyconfiguration is byte-for-byte the previous behavior, and the default remains off.Verification
uv run pytest: 163 passed (9 new). The plan is exercised by a tick-by-tick simulation of 85 daily sessions throughdecide()— every condition visited least-replicated-first (32 cold → 32 warm → 40 cold → 40 warm, twice), cold probes at minute 0 and warm at minute 30, then monthly cycling from the top; cold refused after a 2 h gap, on a fresh state file's first session, and on a daemon upgraded mid-session; warm refused under a thermal cap; the wait-for-the-needy-condition rule and its overdue fallback; one per session; the single-currentanyconfiguration keeps its monthly cadence; CLI parsing and rejection; old state file and mid-probe upgrade; event detail. Backtest tags a probe run from the event and groups it./api/thermalwith the deployed flags plus--probe-amps 32,40 --probe-cable cold,warmand a scratch state file: parses, decides, exits 0, touches nothing.Deploy (needs sudo; the installer rewrites the unit and reloads):
The existing state file carries over. Its Sep 14 probe (
32A any, outside the plan) anchors the cadence, so the first plan probe is due Sep 21 on the first eligible session — and the daemon needs one session after deploy to learn when the last charge ended before it can call a session cold-cable, which that week provides.🤖 Generated with Claude Code