From efc6e54f0eb937df6a69e2d89395613a3a24b28a Mon Sep 17 00:00:00 2001 From: Dusan Vojacek Date: Wed, 29 Apr 2026 15:27:54 +0200 Subject: [PATCH] fix lock charge on 100% SOC --- db/routines/R__063_fn_load_planning_slots_full.sql | 4 +++- docs/04-modules/planning.md | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/db/routines/R__063_fn_load_planning_slots_full.sql b/db/routines/R__063_fn_load_planning_slots_full.sql index d719d90..46daec2 100644 --- a/db/routines/R__063_fn_load_planning_slots_full.sql +++ b/db/routines/R__063_fn_load_planning_slots_full.sql @@ -346,7 +346,9 @@ begin if v_charge_buf <= 0 then update _ems_plan_slot_wk wk set allow_charge = true; elsif v_energy_to_fill <= 0 then - update _ems_plan_slot_wk wk set allow_charge = false; + -- Pokud rolling replan startuje s baterií plnou, nechceme zablokovat budoucí nabíjení po vybití. + -- Povolit alespoň nabíjení v PV surplus slotech, aby solver mohl vytvořit headroom a pak ho znovu zaplnit z FVE. + update _ems_plan_slot_wk wk set allow_charge = (wk.pv_surplus_w > 0); else update _ems_plan_slot_wk wk set allow_charge = (wk.pv_surplus_w > 0); v_cum := 0; diff --git a/docs/04-modules/planning.md b/docs/04-modules/planning.md index 671f7d0..6004df6 100644 --- a/docs/04-modules/planning.md +++ b/docs/04-modules/planning.md @@ -9,6 +9,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[T−1]` (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). +- **Masky `allow_charge` / `allow_discharge_export` (anti-mikrocyklování):** generuje `ems.fn_load_planning_slots_full`. Důležité: pokud rolling replan startuje s baterií na 100 %, `allow_charge` se nesmí stát globálně `false` pro celý horizont – jinak solver nemá motivaci baterii před PV špičkou „uvolnit“ (headroom), protože ji pak nesmí z PV znovu nabít. Aktuálně se v tomto případě `allow_charge` ponechá povolené alespoň pro sloty s `pv_surplus_w > 0`. - **Runtime guard v exportu setpointů (legacy):** - při `AUTO` + `is_predicted_price=true` se na exportní vrstvě vynutí PASSIVE/no-export chování (u nových plánů by `is_predicted_price` v horizontu nemělo nastat). - **Ekonomika baterie:** @@ -33,6 +34,19 @@ Solver optimalizuje celý horizont (typicky do konce známých OTE dat, strop z - pohled dopředu (ráno ví že přes poledne bude záporná cena → prodává z baterie) - kompromisy mezi prodejem, nabíjením, TČ a EV v globálním optimu +### Verifikace (DB) + +Pro kontrolu masek nabíjení: + +```sql +select * +from ems.fn_load_planning_slots_full(, , , ) +where allow_charge is true +order by interval_start; +``` + +- Pokud `current_soc_wh` odpovídá plné baterii (`soc_max_wh`), měly by být `allow_charge=true` alespoň sloty s PV přebytkem (`pv_surplus_w > 0`). + --- ## Klíčové předpoklady a specifika home-01