a dalsi oprava
This commit is contained in:
@@ -71,7 +71,7 @@ NEG_BUY_CHARGE_SHORTFALL_PENALTY_CZK_KWH = 100.0
|
|||||||
PRE_NEG_CHARGE_PENALTY_CZK_KWH = 400.0
|
PRE_NEG_CHARGE_PENALTY_CZK_KWH = 400.0
|
||||||
PRE_NEG_BATT_EXPORT_SHORTFALL_PENALTY_CZK_KWH = 80.0
|
PRE_NEG_BATT_EXPORT_SHORTFALL_PENALTY_CZK_KWH = 80.0
|
||||||
PRE_NEG_BATT_EXPORT_MIN_SELL_CZK_KWH = 1.0
|
PRE_NEG_BATT_EXPORT_MIN_SELL_CZK_KWH = 1.0
|
||||||
PLANNER_BUILD_TAG = "2026-05-29-neg-day-pv-headroom-v44"
|
PLANNER_BUILD_TAG = "2026-05-29-neg-window-charge-night-v45"
|
||||||
# Mimo evening_push: preferovat bd pro dům místo gi, když buy >> acq (účinná cena importu).
|
# Mimo evening_push: preferovat bd pro dům místo gi, když buy >> acq (účinná cena importu).
|
||||||
NIGHT_SELF_CONSUME_IMPORT_SURCHARGE_CZK_KWH = 4.0
|
NIGHT_SELF_CONSUME_IMPORT_SURCHARGE_CZK_KWH = 4.0
|
||||||
# Po t_detach v prep: necpát PV do bat (měkké; tvrdý hold přes soc_target z rampy).
|
# Po t_detach v prep: necpát PV do bat (měkké; tvrdý hold přes soc_target z rampy).
|
||||||
@@ -1711,20 +1711,25 @@ def _evening_push_calendar_segments(
|
|||||||
|
|
||||||
def _night_self_consume_discourage_import_indices(
|
def _night_self_consume_discourage_import_indices(
|
||||||
slots: list[PlanningSlot],
|
slots: list[PlanningSlot],
|
||||||
evening_early_export_penalty_ts: set[int],
|
|
||||||
*,
|
*,
|
||||||
|
evening_push_ts: set[int],
|
||||||
charge_acquisition_czk_kwh: float,
|
charge_acquisition_czk_kwh: float,
|
||||||
min_spread: float,
|
min_spread: float,
|
||||||
) -> set[int]:
|
) -> set[int]:
|
||||||
"""
|
"""
|
||||||
Sloty mimo evening_push, kde import pro dům nahrazuje levnou zásobu z baterie.
|
Noční sloty mimo evening_push: penalizace importu pro dům (preferovat bd).
|
||||||
|
v45: celé noční okno, ne jen evening_early_export_ban subset.
|
||||||
"""
|
"""
|
||||||
out: set[int] = set()
|
out: set[int] = set()
|
||||||
for t in evening_early_export_penalty_ts:
|
for t, s in enumerate(slots):
|
||||||
buy_t = float(slots[t].buy_price)
|
if t in evening_push_ts:
|
||||||
|
continue
|
||||||
|
if not _in_night_battery_export_window(s):
|
||||||
|
continue
|
||||||
|
buy_t = float(s.buy_price)
|
||||||
if buy_t <= float(charge_acquisition_czk_kwh) + float(min_spread):
|
if buy_t <= float(charge_acquisition_czk_kwh) + float(min_spread):
|
||||||
continue
|
continue
|
||||||
if float(slots[t].load_baseline_w) <= 0:
|
if float(s.load_baseline_w) <= 0:
|
||||||
continue
|
continue
|
||||||
out.add(t)
|
out.add(t)
|
||||||
return out
|
return out
|
||||||
@@ -2532,7 +2537,7 @@ def solve_dispatch(
|
|||||||
)
|
)
|
||||||
night_self_consume_discourage_ts = _night_self_consume_discourage_import_indices(
|
night_self_consume_discourage_ts = _night_self_consume_discourage_import_indices(
|
||||||
slots,
|
slots,
|
||||||
evening_early_export_penalty_ts,
|
evening_push_ts=evening_push_ts,
|
||||||
charge_acquisition_czk_kwh=charge_acquisition_czk_kwh,
|
charge_acquisition_czk_kwh=charge_acquisition_czk_kwh,
|
||||||
min_spread=float(degradation_cost_effective),
|
min_spread=float(degradation_cost_effective),
|
||||||
)
|
)
|
||||||
@@ -2785,7 +2790,7 @@ def solve_dispatch(
|
|||||||
cap_w = float(min(pv_surplus_w, battery.max_charge_power_w))
|
cap_w = float(min(pv_surplus_w, battery.max_charge_power_w))
|
||||||
sf_pv = pulp.LpVariable(f"post_neg_pv_shortfall_{t}", 0, cap_w)
|
sf_pv = pulp.LpVariable(f"post_neg_pv_shortfall_{t}", 0, cap_w)
|
||||||
pv_charge_shortfall.append((t, sf_pv, cap_w))
|
pv_charge_shortfall.append((t, sf_pv, cap_w))
|
||||||
if neg_sell_phases_en:
|
if neg_sell_phases_en and not relaxed_neg_prep_window:
|
||||||
for t_ns in range(T):
|
for t_ns in range(T):
|
||||||
phase_ns = neg_sell_phase_by_t[t_ns]
|
phase_ns = neg_sell_phase_by_t[t_ns]
|
||||||
tgt_ns = neg_sell_soc_target_by_t[t_ns]
|
tgt_ns = neg_sell_soc_target_by_t[t_ns]
|
||||||
|
|||||||
@@ -1002,6 +1002,21 @@ begin
|
|||||||
where wk.sell_price < 0
|
where wk.sell_price < 0
|
||||||
and wk.pv_surplus_w > 0;
|
and wk.pv_surplus_w > 0;
|
||||||
|
|
||||||
|
-- v45: v sell<0 okně neg dne — grid nabíjení při kladném buy (prep), i bez pv_surplus (ranní 07:45).
|
||||||
|
if v_first_neg_sell_ord is not null and v_first_neg_prague_date is not null then
|
||||||
|
update _ems_plan_slot_wk wk
|
||||||
|
set allow_charge = true,
|
||||||
|
allow_grid_charge = true,
|
||||||
|
grid_charge_suppressed_reason = coalesce(
|
||||||
|
wk.grid_charge_suppressed_reason,
|
||||||
|
'neg_window_grid_charge'
|
||||||
|
)
|
||||||
|
where wk.slot_ord >= v_first_neg_sell_ord
|
||||||
|
and wk.sell_price < 0
|
||||||
|
and wk.buy_price >= 0
|
||||||
|
and (wk.interval_start at time zone 'Europe/Prague')::date = v_first_neg_prague_date;
|
||||||
|
end if;
|
||||||
|
|
||||||
-- Acquisition: grid nabíjení před prvním exportem ve STEJNÝ den jako záporné výkupní okno
|
-- Acquisition: grid nabíjení před prvním exportem ve STEJNÝ den jako záporné výkupní okno
|
||||||
-- (ne dřívější večerní export v horizontu rolling replanu).
|
-- (ne dřívější večerní export v horizontu rolling replanu).
|
||||||
select min(wk.interval_start)
|
select min(wk.interval_start)
|
||||||
|
|||||||
@@ -108,7 +108,12 @@ flowchart TD
|
|||||||
- **`_neg_sell_pv_forecast_charge_wh`:** zpětná soc_need z **A+B** FVE, ne jen pole B;
|
- **`_neg_sell_pv_forecast_charge_wh`:** zpětná soc_need z **A+B** FVE, ne jen pole B;
|
||||||
- LP **`bc_gi=0`** před 1. sell<0 na neg den.
|
- LP **`bc_gi=0`** před 1. sell<0 na neg den.
|
||||||
|
|
||||||
**Funkce:** `_evening_push_calendar_segments`, `_night_self_consume_discourage_import_indices`, `_neg_sell_pv_forecast_charge_wh`, … Tag: **`2026-05-29-neg-day-pv-headroom-v44`**.
|
5. **v45 — neg okno + noc z baterie:**
|
||||||
|
- **`neg_window_grid_charge`:** v sell<0 okně neg dne grid nabíjení i bez `pv_surplus` (07:45+);
|
||||||
|
- **`night_self_consume_discourage`** na **celé** noční okno mimo push;
|
||||||
|
- při `relaxed_neg_prep_window` bez prep shortfall penalizace.
|
||||||
|
|
||||||
|
**Funkce:** … Tag: **`2026-05-29-neg-window-charge-night-v45`**.
|
||||||
|
|
||||||
### Arbitráž baterie — účtování mezi sloty (povinné čtení)
|
### Arbitráž baterie — účtování mezi sloty (povinné čtení)
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,19 @@ Formát: **datum (ISO)** · stručný důvod · soubory · chování / ověřen
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 2026-05-29 — Neg okno: grid nabíjení + noc z baterie (v45)
|
||||||
|
|
||||||
|
**Problém (v44 běh 20282):** (1) Po večerním pushu **22:00+** import ze sítě ~3,3 kW při SoC **56 %** — `night_self_consume` jen na podmnožině `evening_early_export_ban`, ne celá noc. (2) **07:45–08:15** sell<0 prep: **`allow_charge=false`** (jen `pv_surplus>0`) → SoC stojí, **penalty ~11k Kč/slot**, solver **`relaxed_neg_prep_window`**. (3) **11:45** panické grid+bat 17 kW.
|
||||||
|
|
||||||
|
**Změna (v45):**
|
||||||
|
- **`_night_self_consume_discourage`:** všechny noční sloty mimo `evening_push` (buy > acq+spread).
|
||||||
|
- **R__063 `neg_window_grid_charge`:** od 1. sell<0 na neg den `allow_charge`+`allow_grid_charge` pro sell<0 a buy≥0 i bez FVE přebytku.
|
||||||
|
- **LP:** při `relaxed_neg_prep_window` **bez** `prep_soc_shortfall` penalizace (žádné fiktivní 11k Kč).
|
||||||
|
|
||||||
|
Tag **`2026-05-29-neg-window-charge-night-v45`**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 2026-05-29 — Neg den: headroom pro FVE, ne grid za 3 Kč před sell<0 (v44)
|
## 2026-05-29 — Neg den: headroom pro FVE, ne grid za 3 Kč před sell<0 (v44)
|
||||||
|
|
||||||
**Problém (v43 na home-01 30. 5.):** Ráno **05:45–07:30** grid+bat nabíjení za **~2,6–3,7 Kč/kWh** → SoC **~99 %** ještě před **07:45 sell<0**. Pak **PV A plně utlumena**, **PV B** do site za záporný sell; levný **buy ~0,48 Kč** v 11h nevyužit. Příčiny: (1) **`evening_arbitrage_unlock`** povolil drahý grid před neg oknem; (2) AM maska brala nejlevnější buy **před polednem**, ne v neg okně; (3) **`soc_need`** zpětně počítal jen **PV B**, ne A+B → cíl prep ≈ **soc_max**.
|
**Problém (v43 na home-01 30. 5.):** Ráno **05:45–07:30** grid+bat nabíjení za **~2,6–3,7 Kč/kWh** → SoC **~99 %** ještě před **07:45 sell<0**. Pak **PV A plně utlumena**, **PV B** do site za záporný sell; levný **buy ~0,48 Kč** v 11h nevyužit. Příčiny: (1) **`evening_arbitrage_unlock`** povolil drahý grid před neg oknem; (2) AM maska brala nejlevnější buy **před polednem**, ne v neg okně; (3) **`soc_need`** zpětně počítal jen **PV B**, ne A+B → cíl prep ≈ **soc_max**.
|
||||||
|
|||||||
Reference in New Issue
Block a user