mirror of
https://github.com/Akkudoktor-EOS/EOS.git
synced 2026-10-08 15:26:38 +00:00
feat(optimization): concave terminal value for the energy left in the battery
The energy still stored when the horizon ends keeps its worth: it replaces grid imports that are paid for afterwards. Crediting that with a single price per kWh cannot describe it, because the value is not linear in the amount stored. The first kWh replaces the most expensive hour that PV cannot cover, the next one the second most expensive, and once every such hour is served, further energy replaces nothing. A scalar has to pick one slope for all of it. High enough for the first kWh means hoarding a full battery; low enough for the last kWh means running it empty by the end of the horizon - which is exactly what the previous default of 0 EUR/kWh did. terminal_value_mode = AUTO (the new default) builds the curve instead. There is no forecast beyond the horizon, so its trailing window stands in for the day that follows: residual load max(load - PV, 0) per slot, priced at its import price, sorted and accumulated. LCOS is subtracted from every marginal value so stored energy is not credited twice, and the tail beyond the residual load is only credited when direct marketing allows an export. The curve is built once per run; the search only interpolates on it. The solution reports what a run used as terminal_value, curve included, so the shape can be inspected instead of guessed. FIXED restores the previous scalar behaviour. In a 48 h scenario with two cheap slots at the end, AUTO keeps the battery at 50 % and credits 3.85 EUR where FIXED with 0 EUR/kWh drains it to empty. The stored optimization results move accordingly - the objective changed.
This commit is contained in:
@@ -53,6 +53,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
`ac_charge` array kept the optimizer's unused gene values. The simulation ignored them, so
|
||||
they were never costed - but a controller acting on the plan would grid-charge the battery
|
||||
anyway. The disabled AC charge is now cleared in the reported plan as well.
|
||||
- The energy left in the battery at the end of the horizon is now valued with a concave curve
|
||||
derived from the trailing horizon window (`optimization.terminal_value_mode = AUTO`, the new
|
||||
default): the first stored kWh replaces the most expensive hour that PV cannot cover, the next
|
||||
one the second most expensive, and energy beyond the residual load is credited only when it can
|
||||
be exported. A single price per kWh could not express this - with the previous default of 0 the
|
||||
optimizer emptied the battery towards the end of the horizon, with a high value it hoarded it.
|
||||
The curve is built once per run and reported as `terminal_value` in the solution.
|
||||
`terminal_value_mode = FIXED` restores the old scalar behaviour.
|
||||
- EV Bug (wrong output in genetic.py / no senseful results)
|
||||
- Direktvermarktung active / Battery discharge into grid (new state / action battery_grid_export_allowed) + (new simulation output Feed_in_tariff)
|
||||
- New PV forecast providers giving operators more cloud forecast sources to choose from in
|
||||
|
||||
Reference in New Issue
Block a user