Branch 5: dynamický terminal SoC factor při future neg buy
Some checks failed
CI and deploy / migration-check (push) Failing after 15s
CI and deploy / deploy (push) Has been skipped

This commit is contained in:
Dusan Vojacek
2026-06-06 22:38:05 +02:00
parent 0f7dc6ed94
commit 36cb06b9d0
4 changed files with 179 additions and 10 deletions

View File

@@ -8,7 +8,7 @@
- **SQL-first:** horizont a sloty z DB funkcí (`fn_planning_horizon_end`, `fn_load_planning_slots_full`, …); viz **`CLAUDE.md`** → sekce *SQL-first a read-model*.
- **Dynamický horizont (jen OTE):** konec plánu z **`ems.fn_planning_horizon_end(site_id, horizon_start)`** (výchozí strop **36 h**, minimum pro rolling **1 h** obojí jako defaultní argumenty v SQL, úprava přes repeatable migraci). Pomocná `ems.fn_last_effective_ote` vrací konec posledního OTE intervalu. Rolling replan při `NULL` přeskočí; denní plán použije krátký (1 h) fallback v Pythonu. Sloty v solveru jsou bez predikovaných cen v rámci tohoto horizontu.
- **Terminal SoC shadow price:** v objective je člen `(avg_buy_prvních_24h × planner_terminal_soc_value_factor / 1000) × soc[T1]` (Kč), kde faktor je **`ems.asset_battery.planner_terminal_soc_value_factor`** přes **`ems.fn_planning_site_context`** (default v DB **0.9**); viz sekci *Tuning pro malé baterie* níže. Účel: konec horizontu nemusí končit zbytečně vyprázdněnou baterií (receding horizon).
- **Terminal SoC shadow price:** v objective je člen `(avg_buy_prvních_24h × effective_factor / 1000) × soc[T1]` (Kč), kde `effective_factor = planner_terminal_soc_value_factor × (1 terminal_neg_buy_weight)` a základní faktor je **`ems.asset_battery.planner_terminal_soc_value_factor`** přes **`ems.fn_planning_site_context`** (default v DB **0.9**); viz sekci *Tuning pro malé baterie* níže. Při **`buy<0`** v horizontu (36 h) roste **`terminal_neg_buy_weight`** s blízkostí a záporností ceny — LP nemá „šetřit“ baterii před levným importem. Účel: konec horizontu nemusí končit zbytečně vyprázdněnou baterií (receding horizon).
- **SoC kontinuita a export z baterie:** `soc[t]` klesá při **`bd[t]`** — výkon vybíjení na AC sběrnici z energetické bilance `pv + gi + bd = load + bc + ge`. Při exportu z baterie je v `bd` už započten i tok do sítě (`ge_bat` je součást `ge`); **`ge_bat` se v SoC znovu neodečítá** (dříve double-count → plán klesal ~2× rychleji než BMS ve večerním exportu). Tag `2026-05-28-evening-export-soc-balance-v39`.
- **Masky `allow_charge` / `allow_discharge_export` (tenký anti-mikrocyklus):** generuje `ems.fn_load_planning_slots_full` (`R__063`). Ekonomiku primárně řídí LP podle efektivních cen; masky jen omezují počet slotů pro grid nabíjení / export baterie.
- **PV-surplus (vrstva A):** ranking dle **`store_score DESC`** = `future_sell_opportunity sell max(0, buysell)`; jen sloty s `sell ≥ buy degradation`. Kumulativní PV pokrývá `grid_target` (deficit SoC, nad `reserve_soc` bez násobení `charge_slot_buffer`). Zbytek → `allow_charge=false` (PV jen do sítě / `bc ≤ pv_surplus` v LP).
@@ -149,7 +149,11 @@ flowchart TD
17. **v64 — future neg-buy večerní export (Branch 2, home-01):**
- **`future_neg_buy_discharge`**: před **`buy<0`** dnem s dostatečnou FVE v **`sell<0`** zůstává neg-evening push + kotvy **`reserve_soc`** i při **`relaxed_neg_prep_window`**.
- **`pos_sell_pre_neg_buy_ge_exempt_slots`**: večerní peak před **`buy<0`** — výjimka z `ge=0` při ekonomicky výhodném vývozu.
- **`terminal_soc_factor_effective`**: × **0,1** při **`future_neg_buy_discharge`**. Snap: `future_neg_buy_discharge`, `evening_push_hard_suppressed` (jen fallback). Tag **`2026-06-06-future-neg-buy-evening-export-v64`**.
- **`terminal_soc_factor_effective`**: v64 binární × **0,1** při **`future_neg_buy_discharge`** (nahrazeno v65). Tag **`2026-06-06-future-neg-buy-evening-export-v64`**.
18. **v65 — dynamický terminal SoC při future neg buy (Branch 5):**
- **`terminal_neg_buy_weight`** (`w_neg`): `effective_factor = planner_terminal_soc_value_factor × (1 w_neg)`; blížší a zápornější **`buy<0`** v horizontu (36 h) → vyšší `w_neg` (cap 0,95).
- Snap: `terminal_neg_buy_weight`, `terminal_soc_factor_effective`. Tag **`2026-06-06-terminal-soc-future-neg-buy-v65`**.
**Funkce:** … home-01 **v61**; BA81/KV1 fixed **v59** (+ `R__063`).
@@ -637,8 +641,11 @@ Kromě **`planner_terminal_soc_value_factor`** existují od **V077** měkké mec
V účelové funkci LP je člen **„terminal SoC shadow price“**: energie ponechaná v baterii na konci horizontu je oceněná jako záporný příspěvek k nákladům (solver má motivaci držet část SoC, pokud se to ekonomicky vyplatí oproti okamžitému vývozu / nákupu).
**Výpočet (zjednodušeně):**
`terminal_soc_kcz_per_wh = (průměr buy v prvních 24 h slotů) × planner_terminal_soc_value_factor / 1000`
a v objective se přičítá `- terminal_soc_kcz_per_wh × soc[T1]` (viz `solve_dispatch` v `backend/services/planning_engine.py`).
`effective_factor = planner_terminal_soc_value_factor × (1 terminal_neg_buy_weight)`
`terminal_soc_kcz_per_wh = (průměr buy v prvních 24 h slotů) × effective_factor / 1000`
a v objective se přičítá `- terminal_soc_kcz_per_wh × soc[T1]` (viz `_terminal_neg_buy_weight` a `solve_dispatch` v `backend/services/planning_engine.py`).
**`terminal_neg_buy_weight`:** pokud v horizontu existuje **`buy<0`**, váha roste s blízkostí prvního záporného slotu (horizont 36 h) a magnitudou ceny (ref 1 Kč/kWh, cap **0,95**). Bez záporného buy zůstává **0** — chování jako čistý DB faktor.
**Kde se bere faktor (jediný kanonický zdroj):**