fix(fetch): make the cloud/load divergence model actually modulate - #4871
Open
chalfontchubby wants to merge 1 commit into
Open
fix(fetch): make the cloud/load divergence model actually modulate#4871chalfontchubby wants to merge 1 commit into
chalfontchubby wants to merge 1 commit into
Conversation
step_data_history()'s divergence model picks the phase with
cloud_on = (int((minute + self.minutes_now) / 5) + 1 if flip else 0) % 2
A conditional expression binds looser than "+", so that parses as
"((int(...) + 1) if flip else 0) % 2" - a constant 0 whenever flip is False.
Every such iteration takes the else branch and subtracts a cloud_diff that never
becomes non-zero, so nothing is modulated at all.
flip=True is passed by exactly one caller, pv_forecast_minute10_step. So
metric_cloud_enable only ever perturbed the PV10 scenario, never the central PV
forecast, and metric_load_divergence - a documented, user-facing setting - did
nothing whatsoever. flip only means anything as an antiphase to a modulated
base, which is what gives away the intent: it is the offset that is conditional,
not the whole expression.
This changes plans for everyone running the defaults, since both settings
default on. The two golden debug cases move: agile1 only trivially (five charge
targets by ~4Wh), but pre_saving1 genuinely - a charge window shifts two hours
later, its limit drops 5.02 -> 3.02kWh and an export target moves 10 -> 15%.
All twenty random benchmark scenarios move too. Baselines regenerated;
runtime_s left at the previous values so the diff shows only real changes.
test_pv90's clamp check compared the nominal and PV10 load totals against the
pure load_scaling ratio. Those arrays take different divergence factors (PV10 is
+0.5), and the model does not redistribute exactly - what it adds to a step it
can only take back off the next one if that step is large enough - so the ratio
no longer holds once divergence is live. Disabled via
metric_load_divergence_enable there, since that test is about the clamp.
Unchanged since a278997 (#1655), so it likely predates that file split. No lint
rule catches it: checked all 918 rules in ruff 0.11.4 with --select ALL and
nothing flags ternary/arithmetic precedence - RUF021 covers only and/or.
Fixes #4870
Co-Authored-By: Claude Opus 5 <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.
Written by Claude, posted on behalf of @chalfontchubby.
Fixes #4870
step_data_history()'s divergence model picks its phase withA conditional expression binds looser than
+, so that is((int(...) + 1) if flip else 0) % 2— a constant0wheneverflipis False. Every such iteration takes theelsebranch and subtracts acloud_diffthat never becomes non-zero, so the series comes back untouched.flip=Trueis passed by exactly one caller,pv_forecast_minute10_step. Soswitch.predbat_metric_cloud_enableonly ever perturbed the PV10 scenario, never the central PV forecast, andmetric_load_divergencedid nothing whatsoever.fliponly means anything as an antiphase to a modulated base, which gives away the intent: it is the offset that should be conditional, not the whole expression.This changes plans on the defaults
Both settings default on, so this is a behaviour change for everyone rather than a quiet fix — flagging it prominently because it wants your judgement, not just a review of the diff.
predbat_debug_agile1predbat_debug_pre_saving1Baselines regenerated.
runtime_sinrandom_results.jsonis left at the previous values so the diff shows only genuine changes rather than 20 lines of timing noise.Testing
New
cloud_modulationtest module asserting the model actually modulates withoutflip, thatflipproduces antiphase, that raises and lowers alternate step by step, and that the total is roughly preserved. Confirmed it fails without the fix:There was no such coverage before — every reference to
cloud_factorunderapps/predbat/tests/was a caller replicating the plan setup, so nothing asserted either knob had an effect and the suite passed either way.test_pv90's clamp check compared the nominal and PV10 load totals against the pureload_scalingratio. Those arrays take different divergence factors (PV10 is +0.5) and the model does not redistribute exactly — what it adds to a step it can only take back off the next one if that step is large enough — so the ratio no longer holds once divergence is live. Disabled there viametric_load_divergence_enable, since that test is about the clamp, not divergence../run_all --quickand./run_all --test debug_casesboth pass.Notes
Unchanged since a278997 (#1655), a file split, so it likely predates that. No lint rule catches this class — all 918 rules in ruff 0.11.4 under
--select ALLare silent on it, and the nearest,RUF021, covers onlyand/orchaining.The total-drift behaviour noted above contradicts the loop's own "keeps the same total" comment. Left alone here as pre-existing and separable, but worth knowing it is now live for the load arrays for the first time.