Skip to content

Fix for inverter clipping bugs#4105

Merged
springfall2008 merged 4 commits into
mainfrom
fix/inverter_clipping
Jun 21, 2026
Merged

Fix for inverter clipping bugs#4105
springfall2008 merged 4 commits into
mainfrom
fix/inverter_clipping

Conversation

@springfall2008

@springfall2008 springfall2008 commented Jun 21, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes an AC/DC unit mismatch in the forced-export logic in prediction.py that caused a small amount of solar to be reported as clipped during export windows, when the battery discharge should instead have been scaled back to make room for the solar.

The export limit and inverter over-export figures are computed in AC / grid terms, but battery_draw is a DC quantity that only reaches the grid through battery_draw * inverter_loss. Several places subtracted/added these mixed units directly, so the battery was never scaled by quite the right amount. The residual left above the export limit was then clipped off the solar by the later "Export limit, clip PV output" stage.

This is the bug behind the tiny Clip kWh figures appearing on Exp rows in the plan table.

Changes

In the forced-export block (run_prediction):

  1. Discharge scale-back (common path) — when battery + solar exceeds the export limit, reduce the battery by the loss-corrected amount (reduce_by * inverter_loss_recp) so grid export lands exactly on the limit, clamped at zero so it never silently flips into charging.
  2. inverter_can_charge_during_export charge branch — when even stopping the battery leaves the solar over the limit, the battery charges from the surplus PV. Two unit fixes:
    • Stopping the battery only removes its AC contribution (battery_draw * inverter_loss), so the remaining AC surplus is computed correctly.
    • Hybrid charges from PV on the DC side, so the AC surplus maps back through the loss reciprocal. The non-hybrid path (charging from the AC grid) was already correct and is left unchanged.

Effect: the battery is scaled back / charges by the correct amount, grid export sits exactly at the export limit, and surplus PV that fits within the battery's charge rate is captured instead of clipped. At realistic inverter efficiencies (~96%) the magnitude is well under 1%; the fix is about correctness and not mis-booking inverter loss as clipping.

Tests

  • Added export_pv_clip_loss — forced export + PV on a lossy hybrid; asserts the discharge scale-back leaves no clipped solar.
  • Added export_pv_charge_clip_loss — PV large enough that the battery must charge from the surplus; asserts the charge branch keeps grid export at the limit with no clipping.
  • Both were verified to fail on the pre-fix code and pass after the fix.
  • Updated battery_discharge_export_limit_ac_pv4: its previous expectations (clip 12 kWh, SOC 62) encoded the bug. With the fix the AC-coupled battery absorbs the full 1.5 kW AC surplus (0.75 kW DC, within the 1 kW charge rate), so nothing is clipped (clip 0, SOC 68). All other export tests run at inverter_loss=1, where the bug is invisible, and are unaffected.

Existing model, clip_export_slots, clip_charge_slots, and units suites pass.

Not changed

The separate inverter-capacity scale-back (the inverter-limit block) is a different limit with its own unit convention, and its residual is genuine inverter clipping rather than export-limit clipping — left as-is.

Copilot AI review requested due to automatic review settings June 21, 2026 19:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR aims to fix an inverter export-limit “clipping” bug in the prediction engine by correcting AC/DC unit conversions when scaling battery discharge/charge on lossy inverters, and by adding/adjusting model tests to prevent regressions.

Changes:

  • Fix AC/DC conversion errors when reducing battery discharge under export-limit conditions (and when charging is allowed during forced export).
  • Add two new regression scenarios for lossy hybrid inverters to ensure PV is not incorrectly clipped.
  • Update an existing export-limit + PV test expectation to reflect the corrected AC/DC handling (no clipping; different final SoC).

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
apps/predbat/prediction.py Adjusts export-limit handling math to correctly map AC over-export into DC battery draw/charge.
apps/predbat/tests/test_model.py Adds/updates regression scenarios asserting “no PV clipping” and updated SoC outcomes under inverter loss.

Comment thread apps/predbat/prediction.py Outdated
Comment thread apps/predbat/prediction.py Outdated
springfall2008 and others added 2 commits June 21, 2026 20:55
The branch deciding between scaling the battery back and stopping it to
charge from surplus PV compared the AC over-export figure against the raw
DC battery_draw. With inverter_loss < 1 there is a band
(battery_draw * inverter_loss < over_limit <= battery_draw) where the
surplus exceeds the battery's actual AC export contribution but not its DC
value, so the code took the scale-back path, stopped the battery and
clipped the residual PV instead of charging to absorb it.

Compare against battery_draw * inverter_loss so the pivot is in consistent
AC units. Adds export_pv_charge_band_loss regression test covering the band
(verified to fail before this change).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The three charge-absorption paths in the forced-export logic (the export
limit and inverter limit charge branches) clamped the charge magnitude by
-battery_to_min (energy available to discharge down to reserve) instead of
-battery_to_max (remaining capacity up to soc_max). Every other charge path
in the model uses battery_to_max.

With SOC near full this let the model request more charging than the battery
can accept; SOC is later clamped to soc_max without adjusting the energy
flows, under-reporting clipping and skewing the export accounting.

Adds export_pv_charge_full_battery regression test (full battery, high PV
forced export) which clips the full surplus once the charge is correctly
bounded by zero headroom; verified to fail before this change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

The hybrid charge branch of the inverter-limit scale-back set the charge to
-reduce_by * inverter_loss, but reduce_by here is in the same DC-equivalent
throughput units as total_inverted (get_total_inverted counts the battery and
the PV diverted to DC 1:1). The battery must therefore charge by reduce_by
directly to bring total_inverted onto the inverter limit - the inverter_loss
factor under-charges and leaves PV to be clipped by the later "Clip solar"
stage that the battery could otherwise have absorbed.

This is the same AC/DC unit class fixed in the export-limit block; it was the
remaining inconsistency in the sibling inverter-limit block (surfaced by code
review). The non-hybrid discharge path is unaffected - its under-correction is
re-clamped correctly downstream.

Adds export_pv_inverter_limit_charge regression test (hybrid, PV above the
inverter limit, non-binding export limit) asserting zero clipping; verified to
fail before this change (clip 9.6kWh, soc short by 0.4kW*24).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@springfall2008 springfall2008 changed the title Fix for inverter clipping bug Fix for inverter clipping bugs Jun 21, 2026
@springfall2008 springfall2008 merged commit 688dfab into main Jun 21, 2026
1 check passed
@springfall2008 springfall2008 deleted the fix/inverter_clipping branch June 21, 2026 20:34
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.

2 participants