Enforce inverter power limits in battery dispatch (charge and discharge) #25

Open
opened 2026-07-17 03:06:39 +00:00 by claude-bot · 0 comments
Contributor

chargeBatteryFromGrid (src/lib/simulation.js:395-404) refills the entire bank in one hour regardless of size, and both discharge paths cap on state/load but never on power. Meanwhile calculateInverterUtilization (src/lib/quotes.js:309-369) computes continuous-kW limits and the UI warns when peaks exceed them — but the dispatch model ignores the limit, so savings assume energy transfer the hardware cannot deliver. docs/calculation-logic-audit.md records this as a known caveat; nothing tracks fixing it.

Fix: thread the modeled system's inverter.continuousKw into runHourlySimulation and clamp per-hour charge (gridChargeKwh) and discharge (canDischarge) to it (1-hour steps, so kW ≈ kWh). Charging then spreads across the off-peak window on its own. Apply the same cap in buildDefaultDemandTargets so Ultimate demand targets stay consistent. Note the parametric path (src/lib/rates.js batteryArbSavings) if it should mirror the cap via a daily-throughput ceiling (continuousKw × window hours).

Test: bank of 4+ units with a 5 kW inverter must show charge spread over multiple off-peak hours and discharge clipped at 5 kWh/hour; savings must drop versus the uncapped model for oversized banks.

Acceptance criteria

  • Per-hour charge and discharge clamped to inverter continuous kW in the hourly simulation
  • Ultimate demand-target pass uses the same clamp
  • Parametric path either mirrors the cap or documents why it doesn't
  • Regression test for an inverter-limited configuration
  • Calculation-logic audit doc caveat updated

Relations: relates to #11 (same modeling-depth theme; cycle counting will need the same per-hour flows)

(Audit finding F-04, 2026-07-16 — Severity: Medium, Confidence: High)

`chargeBatteryFromGrid` (`src/lib/simulation.js:395-404`) refills the entire bank in one hour regardless of size, and both discharge paths cap on state/load but never on power. Meanwhile `calculateInverterUtilization` (`src/lib/quotes.js:309-369`) computes continuous-kW limits and the UI warns when peaks exceed them — but the dispatch model ignores the limit, so savings assume energy transfer the hardware cannot deliver. `docs/calculation-logic-audit.md` records this as a known caveat; nothing tracks fixing it. Fix: thread the modeled system's `inverter.continuousKw` into `runHourlySimulation` and clamp per-hour charge (`gridChargeKwh`) and discharge (`canDischarge`) to it (1-hour steps, so kW ≈ kWh). Charging then spreads across the off-peak window on its own. Apply the same cap in `buildDefaultDemandTargets` so Ultimate demand targets stay consistent. Note the parametric path (`src/lib/rates.js` `batteryArbSavings`) if it should mirror the cap via a daily-throughput ceiling (`continuousKw × window hours`). Test: bank of 4+ units with a 5 kW inverter must show charge spread over multiple off-peak hours and discharge clipped at 5 kWh/hour; savings must drop versus the uncapped model for oversized banks. **Acceptance criteria** - [ ] Per-hour charge and discharge clamped to inverter continuous kW in the hourly simulation - [ ] Ultimate demand-target pass uses the same clamp - [ ] Parametric path either mirrors the cap or documents why it doesn't - [ ] Regression test for an inverter-limited configuration - [ ] Calculation-logic audit doc caveat updated **Relations:** relates to #11 (same modeling-depth theme; cycle counting will need the same per-hour flows) *(Audit finding F-04, 2026-07-16 — Severity: Medium, Confidence: High)*
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
rbrooks/BatteryStorageCalculator#25
No description provided.