feat(devices): add load-dependent DC-to-AC efficiency curve for GENETIC inverters (#1375)

* feat(devices): add load-dependent DC-to-AC efficiency curve for GENETIC inverters

Real inverters are much less efficient at low load than at rated power
(e.g. 0.80 at 2 % vs. 0.93 at 7 % load). A constant dc_to_ac_efficiency
overrates night-time battery discharge into a small base load and, with
it, arbitrage and grid charging.

Add two optional inverter settings for the GENETIC optimizer:

- dc_to_ac_efficiency_curve: list of (load_fraction, efficiency) points,
  load fraction = AC power / max_power_w. Points must be strictly
  increasing in [0, 1] with efficiencies in (0, 1]; at least two points.
  Linear interpolation, clamped at both ends. When set, the curve
  replaces dc_to_ac_efficiency.
- dc_to_ac_efficiency_reference_load_fraction (default 0.06): load at
  which the curve values stored energy without a specific conversion.

Battery discharges in Inverter.process_energy() use the efficiency at
the AC energy of each conversion. The end-of-horizon value, the terminal
and tail value curves and the AC charge break-even penalty use
Inverter.reference_dc_to_ac_efficiency.

Without a curve, dc_to_ac_efficiency_at() and the reference efficiency
return dc_to_ac_efficiency itself, so results are bit-identical to the
previous model. GENETIC0 is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(devices): evaluate the efficiency curve at the delivered AC load

When the battery limits a discharge (low state of charge or its power
limit), the conversion ran with the efficiency of the requested AC energy.
With a 1000 Wh battery at 10 % SoC, a 1000 W inverter and the curve
[(0, .8), (.5, .95), (1, .95)], a request of 500 Wh AC returned 95 Wh AC
from the available 100 Wh DC, although the curve gives 82.5 % at that load.

The delivered AC energy now solves a = dc * efficiency(a / rated) exactly on
the piecewise-linear curve (solve_ac_for_dc_energy), bounded by the request.
Unlimited discharges and inverters without a curve are unchanged.

Regression tests use a real Battery: low SoC and a power-limited discharge,
each with 60- and 15-minute slots, battery discharge losses, the load path
through process_energy, and constant efficiency.

* docs: regenerate OpenAPI for the efficiency-curve fix

---------

Co-authored-by: Christin <christin@BigBrother.bikini.bottom.zone>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Andreas <drbacke@gmx.de>
This commit is contained in:
Christin
2026-10-11 10:45:44 +02:00
committed by GitHub
co-authored by Christin Claude Opus 5.5 Andreas
parent 560370281f
commit 7f26ea3f3f
10 changed files with 1175 additions and 22 deletions
+33
View File
@@ -299,6 +299,39 @@ The inverter supports separate AC↔DC conversion efficiencies:
Must be > 0. Default `1.0`.
- `max_ac_charge_power_w`: Maximum AC charging power in watts. `null` = no additional limit.
Set to `0` to disable AC charging. Default `null`.
- `dc_to_ac_efficiency_curve`: Optional load-dependent DC→AC efficiency as a list of
`[load_fraction, efficiency]` points, with the load fraction relative to `max_power_w`.
Real inverters are much less efficient at low load, e.g. when the battery serves a small
night-time base load. The points must be strictly increasing in load fraction (0-1) with
efficiencies in (0, 1]; values in between are interpolated linearly, values outside are
clamped to the first/last point. When set, the curve replaces `dc_to_ac_efficiency` for
battery discharge. The efficiency is always the one at the AC power that is delivered: if
the battery limits a discharge (low state of charge or its power limit), the conversion is
evaluated at that lower load, not at the requested one. Default `null` (constant
`dc_to_ac_efficiency`, unchanged behaviour).
- `dc_to_ac_efficiency_reference_load_fraction`: Load fraction at which the curve is evaluated
where stored energy is valued without a specific discharge, e.g. the energy left in the
battery at the end of the horizon and the AC charge break-even. Choose the typical load
the battery serves. Only used with `dc_to_ac_efficiency_curve`. Default `0.06`.
**Example with an efficiency curve:**
```json
{
"devices": {
"inverters": {
"inv1": {
"max_power_w": 10000,
"battery_id": "bat1",
"dc_to_ac_efficiency_curve": [
[0.02, 0.80], [0.07, 0.93], [0.30, 0.96], [1.00, 0.95]
],
"dc_to_ac_efficiency_reference_load_fraction": 0.06
}
}
}
}
```
#### Electric vehicle simulation configuration