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
+186
View File
@@ -11304,6 +11304,70 @@
"GENETIC0"
]
},
"dc_to_ac_efficiency_curve": {
"anyOf": [
{
"items": {
"prefixItems": [
{
"type": "number"
},
{
"type": "number"
}
],
"type": "array",
"maxItems": 2,
"minItems": 2
},
"type": "array"
},
{
"type": "null"
}
],
"title": "Dc To Ac Efficiency Curve",
"description": "Load-dependent efficiency of DC\u2192AC conversion for battery discharging as a list of [load_fraction, efficiency] points. The load fraction is the AC power relative to max_power_w (0\u20131); points must be strictly increasing in load fraction, efficiencies in (0, 1]. Values are interpolated linearly and clamped to the first/last point. When set, the curve replaces dc_to_ac_efficiency. null keeps the constant dc_to_ac_efficiency. Default null.",
"examples": [
null,
[
[
0.02,
0.8
],
[
0.07,
0.93
],
[
0.3,
0.96
],
[
1.0,
0.95
]
]
],
"x-scope": [
"GENETIC"
]
},
"dc_to_ac_efficiency_reference_load_fraction": {
"type": "number",
"maximum": 1.0,
"minimum": 0.0,
"title": "Dc To Ac Efficiency Reference Load Fraction",
"description": "Load fraction of max_power_w (0\u20131) at which dc_to_ac_efficiency_curve is evaluated to value stored battery energy without a specific conversion (remaining energy at the end of the horizon, AC charge break-even). Should represent the typical load served by the battery, e.g. the night-time base load. Only used with dc_to_ac_efficiency_curve. Default 0.06.",
"default": 0.06,
"examples": [
0.06,
0.1
],
"x-scope": [
"GENETIC"
]
},
"max_ac_charge_power_w": {
"anyOf": [
{
@@ -11715,6 +11779,70 @@
"GENETIC0"
]
},
"dc_to_ac_efficiency_curve": {
"anyOf": [
{
"items": {
"prefixItems": [
{
"type": "number"
},
{
"type": "number"
}
],
"type": "array",
"maxItems": 2,
"minItems": 2
},
"type": "array"
},
{
"type": "null"
}
],
"title": "Dc To Ac Efficiency Curve",
"description": "Load-dependent efficiency of DC\u2192AC conversion for battery discharging as a list of [load_fraction, efficiency] points. The load fraction is the AC power relative to max_power_w (0\u20131); points must be strictly increasing in load fraction, efficiencies in (0, 1]. Values are interpolated linearly and clamped to the first/last point. When set, the curve replaces dc_to_ac_efficiency. null keeps the constant dc_to_ac_efficiency. Default null.",
"examples": [
null,
[
[
0.02,
0.8
],
[
0.07,
0.93
],
[
0.3,
0.96
],
[
1.0,
0.95
]
]
],
"x-scope": [
"GENETIC"
]
},
"dc_to_ac_efficiency_reference_load_fraction": {
"type": "number",
"maximum": 1.0,
"minimum": 0.0,
"title": "Dc To Ac Efficiency Reference Load Fraction",
"description": "Load fraction of max_power_w (0\u20131) at which dc_to_ac_efficiency_curve is evaluated to value stored battery energy without a specific conversion (remaining energy at the end of the horizon, AC charge break-even). Should represent the typical load served by the battery, e.g. the night-time base load. Only used with dc_to_ac_efficiency_curve. Default 0.06.",
"default": 0.06,
"examples": [
0.06,
0.1
],
"x-scope": [
"GENETIC"
]
},
"max_ac_charge_power_w": {
"anyOf": [
{
@@ -12147,6 +12275,64 @@
1.0
]
},
"dc_to_ac_efficiency_curve": {
"anyOf": [
{
"items": {
"prefixItems": [
{
"type": "number"
},
{
"type": "number"
}
],
"type": "array",
"maxItems": 2,
"minItems": 2
},
"type": "array"
},
{
"type": "null"
}
],
"title": "Dc To Ac Efficiency Curve",
"description": "Load-dependent efficiency of DC to AC conversion as a list of (load_fraction, efficiency) points. The load fraction is the AC power of the conversion relative to max_power_wh [0.0 ... 1.0]; points must be strictly increasing in load fraction, efficiencies in (0, 1]. Values are interpolated linearly and clamped to the first/last point. When set, the curve replaces dc_to_ac_efficiency. Default None (constant dc_to_ac_efficiency).",
"examples": [
null,
[
[
0.02,
0.8
],
[
0.07,
0.93
],
[
0.3,
0.96
],
[
1.0,
0.95
]
]
]
},
"dc_to_ac_efficiency_reference_load_fraction": {
"type": "number",
"maximum": 1.0,
"minimum": 0.0,
"title": "Dc To Ac Efficiency Reference Load Fraction",
"description": "Load fraction at which dc_to_ac_efficiency_curve is evaluated where stored battery energy is valued without a specific conversion (e.g. remaining battery energy at the end of the horizon, AC charge break-even). Should represent the typical load the battery serves, e.g. the night-time base load. Only used with dc_to_ac_efficiency_curve. Default 0.06.",
"default": 0.06,
"examples": [
0.06,
0.1
]
},
"max_ac_charge_power_w": {
"anyOf": [
{