Skip to content

fix: feedforward numeric corrections to switch arrays and freeze integrator when saturated#6

Open
bvweerd wants to merge 1 commit into
fix/battery-control-layerfrom
fix/control-loop-hardening
Open

fix: feedforward numeric corrections to switch arrays and freeze integrator when saturated#6
bvweerd wants to merge 1 commit into
fix/battery-control-layerfrom
fix/control-loop-hardening

Conversation

@bvweerd

@bvweerd bvweerd commented Jun 11, 2026

Copy link
Copy Markdown
Owner

Stacked on #5 — merge #5 (fix/battery-control-layer) first; this PR's base is set to that branch so it only shows its own changes. After #5 merges, retarget/rebase this PR onto dev.

Problem

  1. Switch arrays double-compensate. The switch-array hysteresis acted on the residual from before this cycle's numeric-array correction. An export that the numeric arrays had just fully curtailed could still toggle a switch array off in the same cycle — both actuators correct the same watts and the grid swings to import.
  2. Integrator windup against a saturated plant. The PID integrator kept accumulating while no actuator could absorb the output (all arrays in their settling window or at their limits, no switch toggled). With persistent import and PV at max, the I-term wound up towards the output clamp and caused an overshoot the moment headroom returned (cloud passing, settling expiring).

Fix

  • _distribute_to_numeric_arrays now returns the unabsorbed remainder; the watts actually absorbed are fed forward into the residual used for switch-array decisions, and each switch toggle also updates the residual for subsequent switches.
  • When the PID output moved nothing (no numeric absorption, no switch action), the integrator is frozen for the next cycle — same mechanism already used for deadband and calibration.

Tests

tests/test_control_loop_hardening.py: switch array stays on when numeric curtailment already absorbed the export, still toggles when nothing else can absorb, integrator stops growing while saturated, and control resumes normally when headroom returns. Full suite: 139 passed.

https://claude.ai/code/session_01RUWpwxbGsgR3PoLHLq4Djz


Generated by Claude Code

…grator when saturated

Two control-loop hardening fixes:

1. Switch-array hysteresis acted on the residual from before this
   cycle's numeric-array correction. An export that the numeric arrays
   had just fully curtailed could still toggle a switch array off — a
   double compensation that swings the grid to import. The watts
   absorbed by numeric arrays (and by each switch toggle) are now fed
   forward into the residual used for subsequent switch decisions.

2. The PID integrator kept accumulating while no actuator could absorb
   the output (all arrays settling or saturated, no switch toggled),
   winding up towards the output clamp and causing an overshoot once
   headroom returned. The integrator is now frozen for the next cycle
   whenever the PID output moved nothing.

https://claude.ai/code/session_01RUWpwxbGsgR3PoLHLq4Djz
@github-actions github-actions Bot added enhancement New feature or request bug Something isn't working labels Jun 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant