Skip to content

fix(prediction): count each charging car's energy once in the house load - #5315

Merged
springfall2008 merged 2 commits into
mainfrom
fix/multi-car-load-double-count-5313
Sep 30, 2026
Merged

springfall2008 merged 2 commits into
mainfrom
fix/multi-car-load-double-count-5313

Conversation

@springfall2008

Copy link
Copy Markdown
Owner

This is an automated draft PR generated from issue #5313 — a maintainer should review it before merging.

Fixes #5313

Summary

When two or more cars charged in the same prediction step, the planner added car_amount_premium, the running total of car energy across the cars, to the house load once per car. The first car was therefore counted once for every car: two 7 kWh cars modelled 21 kWh and three modelled 42 kWh.

Each car now adds its own energy (car_load_scale / car_charging_loss), in both prediction.py and prediction_kernel.cpp. car_amount_premium still accumulates as before, because its other use is correct: it is the energy the car-rate premium applies to, capped at the grid import.

The kernel parity revision is bumped 15 → 16 in both the .cpp and prediction_kernel.py, and the kernel's "mirrors the Python engine exactly" note is replaced.

Only users with car_energy_reported_load On (the default) and two or more cars charging at overlapping times see a change. Cars outside the CT clamp go through car_load_energy_bypass, which already counted each car once and is untouched.

Testing

  • New multi_car_load test (tests/test_multi_car_load.py, registered in TEST_REGISTRY). It runs 1, 2 and 3 cars at 7 kW for an hour with no PV, no house load and an empty battery, at car_charging_loss 1.0 and 0.9, in both the Python engine and the C++ kernel. It asserts that grid import is 7 kWh per car and that the cost matches, and it checks the kernel really ran (kernel_handle), so the kernel leg cannot pass on the Python fallback.
    • Without the fix it fails: all 8 multi-car cases, in both engines, modelled 21 kWh and 42 kWh. The single-car cases pass.
    • With the fix it passes: 12 of 12.
  • Random scenarios (coverage/cases/random_results.json, updated). Only the two scenarios where two cars' slots overlap moved: 5 (metric −345) and 14 (metric −511). Scenarios 1 and 7 also have two cars, but their slots don't overlap, and they are unchanged, as are all the single-car and car-free scenarios (18 of 20).
  • ./run_pre_commit passes: pre-commit is clean and the quick suite passes, including kernel_parity, model and debug_cases.

Notes

  • CI: the committed kernel binaries are still parity 15, so the first run of the binary verification check should fail until the kernel-binaries job rebuilds and commits them. Locally the harness built a fresh kernel.
  • Blast radius: impact(run_prediction) reports MEDIUM with 5 direct callers. The signature is unchanged and behaviour changes only for two or more cars charging in the same step with car_energy_reported_load On.
  • Left as is: car_amount_premium is a misleading name, since it holds all reported car energy in the step and not just energy above the import rate. Renaming it would touch the premium pricing and the kernel for no behaviour change, so it is out of scope here.
  • The triage workaround is not like-for-like: turning switch.predbat_car_energy_reported_load Off avoids the double count, but it also takes the car's energy out of the modelled import and cost entirely. The car is treated as outside the CT clamp and only reduces export credit.

🤖 Generated with Claude Code

The per-car loop added car_amount_premium - the running total across cars - to
the load for every car, so with cars charging in the same step the first was
counted once per car (two 7 kWh cars modelled 21 kWh, three 42 kWh). Add each
car's own energy instead, in both engines; car_amount_premium keeps its other
job as the energy the car-rate premium applies to. Kernel parity 15 -> 16.

Fixes #5313

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@springfall2008 springfall2008 self-assigned this Sep 30, 2026
@springfall2008
springfall2008 marked this pull request as ready for review September 30, 2026 07:30
@springfall2008
springfall2008 merged commit 57ec7bf into main Sep 30, 2026
2 checks passed
@springfall2008
springfall2008 deleted the fix/multi-car-load-double-count-5313 branch September 30, 2026 07:41
springfall2008 added a commit that referenced this pull request Oct 2, 2026
…0-01

docs(debug-journal): fold in the 2026-10-01 queue slice (9 candidates); mark GH#5313 fixed by PR #5315, GH#5136 by PR #5293, GH#5222 by PR #5283, the iog-slot-io-adjusted row by PR #5304, GH#5068 reworked by PRs #5309/#5314; add the dynamic-load car cancel row and the GH#2649/#5302/#5324 findings
gcoan pushed a commit to gcoan/batpred that referenced this pull request Oct 3, 2026
…); mark GH#5313 fixed by PR springfall2008#5315, GH#5136 by PR springfall2008#5293, GH#5222 by PR springfall2008#5283, the iog-slot-io-adjusted row by PR springfall2008#5304, GH#5068 reworked by PRs springfall2008#5309/springfall2008#5314; add the dynamic-load car cancel row and the GH#2649/springfall2008#5302/springfall2008#5324 findings

Co-Authored-By: Claude Code <noreply@anthropic.com>
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.

Planner overstates load when two or more cars charge in the same slot (cumulative car energy added per car)

1 participant