Fáze 1.1: extrakce konstant plánovače do services/planning/constants.py
Čistý přesun 57 konstant (vč. SOLVER_RELAX_STEPS) z planning_engine.py; engine je importuje zpět (fasáda, beze změny chování). Golden replay 5/5, unit testy beze změny vůči baseline (4+1 předexistující faily). Ekonomické penalty/váhy tím získaly jedno místo — kandidáti na DB ve Fázi 2. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
1
backend/services/planning/__init__.py
Normal file
1
backend/services/planning/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
"""EMS plánovač – moduly (Fáze 1 dekompozice planning_engine.py)."""
|
||||||
113
backend/services/planning/constants.py
Normal file
113
backend/services/planning/constants.py
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
# backend/services/planning/constants.py
|
||||||
|
#
|
||||||
|
# EMS plánovač – konstanty (Fáze 1 dekompozice, čistý přesun z planning_engine.py).
|
||||||
|
# POZOR: ekonomické penalty/váhy jsou kandidáti na přesun do DB ve Fázi 2
|
||||||
|
# (CLAUDE.md pravidlo 16: žádný skrytý faktor v Pythonu).
|
||||||
|
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Konstanty
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
# Když DB vrátí NULL (skoro žádná OTE data), denní plán použije krátký fallback (soulad s min hodinami ve fn_planning_horizon_end).
|
||||||
|
_DAILY_FALLBACK_HORIZON_HOURS = 1.0
|
||||||
|
# Shadow cena zbytkové energie na konci horizontu: - (avg_buy * FACTOR / 1000) * soc[T-1] (Kč; soc v Wh).
|
||||||
|
INTERVAL_H = 0.25 # 15 minut v hodinách
|
||||||
|
CURTAILMENT_PENALTY = 0.001 # Kč/Wh – malá penalizace za omezení FVE pole A
|
||||||
|
SOLVER_TIME_LIMIT = 10 # sekund
|
||||||
|
# MILP: významný export ge (W) ⇒ koncové soc[t] ≥ podlaha; mimo arbitrážní relax je to arb_base_wh
|
||||||
|
# (rezerva z DB). Při relaxaci spodku před extrémně záporným buy je podlaha soc_panel_min[t]
|
||||||
|
# (planner floor), jinak by šlo jen do zátěže a nešlo by „vypustit do sítě“ před levným nákupem.
|
||||||
|
GE_MIN_EXPORT_W = 1.0
|
||||||
|
# Dvouprůchodové solve: stop když acquisition z pass1 vs pass2 se liší méně než (Kč/kWh).
|
||||||
|
ACQUISITION_TWO_PASS_EPS_KWH = 0.05
|
||||||
|
# Load-first (Deye): PV nejdřív pokryje load+EV+TČ; bc_pv/ge_pv jen z pv_sp (přebytek).
|
||||||
|
LOAD_FIRST_INCENTIVE_CZK_KWH = 0.05
|
||||||
|
# Dokud je kotva pro hluboký dump (první sell < 0 v horizontu, jinak první extrémní buy) dál než
|
||||||
|
# tento počet 15min slotů, držíme plánovací spodek na rezervě (arb_base_wh) místo planner floor —
|
||||||
|
# priorita: beze „ztráty na prodeji“ (sell >= 0) držet buffer, hluboký vývoz až těsně před záporným prodejem.
|
||||||
|
DEFAULT_PLANNER_DISCHARGE_RELAX_PREWINDOW_SLOTS = 8
|
||||||
|
# Měkká kotva: chceme být u planner floor už v posledním slotu před prvním sell < 0.
|
||||||
|
# Penalizace je v Kč/Wh (např. 0.20 = 200 Kč/kWh). Musí být dost velká, aby přebila
|
||||||
|
# bezpečnostní SoC buffer + terminal shadow cenu a solver skutečně „dovylil“ před sell<0.
|
||||||
|
PRENEG_SELL_SOC_ANCHOR_SLACK_PENALTY_CZK_PER_WH = 0.20
|
||||||
|
PEAK_EXPORT_SHORTFALL_PENALTY_CZK_KWH = 80.0
|
||||||
|
# Měkký tlak: v okně sell<0 + block_export využít PV přebytek do baterie (ne curtail).
|
||||||
|
PV_CHARGE_SHORTFALL_PENALTY_CZK_KWH = 120.0
|
||||||
|
# Curtailment při sell<0 + allow_charge: nesmí být téměř zdarma oproti nabíjení (BA81).
|
||||||
|
NEG_SELL_CURTAIL_PENALTY_CZK_KWH = 1.0
|
||||||
|
# Odměna v objective za FVE→baterie při sell<0 (doplňuje shortfall; BA81 fixed tarif).
|
||||||
|
NEG_SELL_PV_CHARGE_REWARD_CZK_KWH = 0.8
|
||||||
|
# Měkký tlak: v okně sell<0 dobít na soc_max (ne zastavit na ~94 % kvůli curtail).
|
||||||
|
NEG_SELL_SOC_UNDERFILL_PENALTY_CZK_PER_WH = 0.35
|
||||||
|
# Jen ventil nekontrolovatelného pole B při plné baterii a sell<0 (spot); ne celý PV přebytek.
|
||||||
|
NEG_SELL_PV_B_VENT_PENALTY_CZK_KWH = 4.0
|
||||||
|
# Fáze sell<0 (v32): ASAP na prep_soc %, tail rampa na soc_max.
|
||||||
|
NEG_SELL_PREP_SOC_SHORTFALL_PENALTY_CZK_PER_WH = 0.85
|
||||||
|
NEG_SELL_PREP_HOLD_BCPV_PENALTY_CZK_KWH = 60.0
|
||||||
|
# Výboj baterie při sell<0 jen těsně před extrémně záporným buy (round-trip arbitráž).
|
||||||
|
EXTREME_BUY_DUMP_PREWINDOW_SLOTS = 12
|
||||||
|
NEG_SELL_BAT_DUMP_SHORTFALL_PENALTY_CZK_KWH = 80.0
|
||||||
|
NEG_BUY_CHARGE_SHORTFALL_PENALTY_CZK_KWH = 100.0
|
||||||
|
PRE_NEG_CHARGE_PENALTY_CZK_KWH = 400.0
|
||||||
|
PRE_NEG_BATT_EXPORT_SHORTFALL_PENALTY_CZK_KWH = 80.0
|
||||||
|
PRE_NEG_BATT_EXPORT_MIN_SELL_CZK_KWH = 1.0
|
||||||
|
PLANNER_BUILD_TAG = "2026-06-06-home01-strict-late-replan-v5"
|
||||||
|
SOLVER_RELAX_STEPS: tuple[str, ...] = (
|
||||||
|
"strict",
|
||||||
|
"relaxed_expensive_import",
|
||||||
|
"relaxed_neg_buy_charge",
|
||||||
|
"relaxed_neg_prep_hold_only",
|
||||||
|
"relaxed_neg_prep_window",
|
||||||
|
"neg_sell_phases_fallback",
|
||||||
|
"relaxed_pos_sell_ge_block",
|
||||||
|
"relaxed_solver_masks",
|
||||||
|
)
|
||||||
|
# Ranní slabá FVE: neaplikovat pv_store ge_pv=0 (jinak curtail při sell < večerní peak).
|
||||||
|
DAWN_LOW_PV_NO_CURTAIL_W = 1500
|
||||||
|
# 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
|
||||||
|
# Po t_detach v prep: necpát PV do bat (měkké; tvrdý hold přes soc_target z rampy).
|
||||||
|
NEG_SELL_POST_DETACH_BCPV_DISCOURAGE_CZK_KWH = 250.0
|
||||||
|
# Večer před neg dnem: výboj do sítě (měkký shortfall na ge_bat).
|
||||||
|
NEG_EVENING_PREP_DISCHARGE_SHORTFALL_PENALTY_CZK_KWH = 120.0
|
||||||
|
# Kotva: SoC na konci večera D−1 a těsně před 1. sell<0 ráno D ≤ reserve_soc.
|
||||||
|
NEG_EVENING_RESERVE_SOC_MAX_SLACK_WH = 400.0
|
||||||
|
NEG_EVENING_RESERVE_SOC_SLACK_PENALTY_CZK_PER_WH = 55.0
|
||||||
|
# Terminal SoC shadow price: effective_factor = base × (1 − w_neg); w_neg roste s blízkostí a záporností buy<0.
|
||||||
|
TERMINAL_NEG_BUY_WEIGHT_HORIZON_SLOTS = int(36 / INTERVAL_H)
|
||||||
|
TERMINAL_NEG_BUY_MAGNITUDE_REF_CZK = 1.0
|
||||||
|
TERMINAL_NEG_BUY_MAGNITUDE_FLOOR = 0.25
|
||||||
|
TERMINAL_NEG_BUY_WEIGHT_CAP = 0.95
|
||||||
|
# Před prvním sell<0: export FVE jen pokud predikce v sell<0 okně pokryje dobítí na prep cíl.
|
||||||
|
PRE_NEG_PV_EXPORT_FORECAST_MARGIN = 1.15
|
||||||
|
PRE_NEG_PV_EXPORT_MIN_NEEDED_WH = 2500.0
|
||||||
|
PRE_NEG_PV_EXPORT_SHORTFALL_PENALTY_CZK_KWH = 55.0
|
||||||
|
PRE_NEG_PV_BCPV_DISCOURAGE_CZK_KWH = 90.0
|
||||||
|
POS_SELL_PRE_NEG_SOC_SHORTFALL_PENALTY_CZK_PER_WH = 0.30
|
||||||
|
PRE_NEG_BUY_SOC_CEILING_SLACK_PENALTY_CZK_PER_WH = 0.25
|
||||||
|
PRE_NEG_BUY_EMPTY_EXPORT_SHORTFALL_PENALTY_CZK_KWH = 80.0
|
||||||
|
EVENING_PEAK_SELL_EPS_CZK_KWH = 0.05
|
||||||
|
# Rolling replan: držet evening_push_ts při malé změně peak sell / SoC.
|
||||||
|
EVENING_PUSH_HYSTERESIS_SELL_PEAK_DELTA_CZK_KWH = 0.5
|
||||||
|
EVENING_PUSH_HYSTERESIS_SOC_PCT = 5.0
|
||||||
|
# Noční výprodej baterie: večer (≥17h) + ráno do východu FVE (0–5h Prague), jedna špička přes půlnoc.
|
||||||
|
NIGHT_EXPORT_EVENING_START_HOUR = 17
|
||||||
|
NIGHT_EXPORT_MORNING_END_HOUR = 5
|
||||||
|
NIGHT_EXPORT_PV_SUNRISE_SURPLUS_W = 500.0
|
||||||
|
# Převáží terminal SoC shadow price při krátkém večerním horizontu (home-01).
|
||||||
|
EVENING_PUSH_Z_EXPORT_BONUS_CZK = 2500.0
|
||||||
|
# buy<0: preferovat import před PV A→bat (měkké; tvrdé bc_pv=0 láme bilanci s polem B).
|
||||||
|
PRE_NEG_BUY_PV_CHARGE_PENALTY_CZK_KWH = 250.0
|
||||||
|
CORRECTION_WINDOW_H = 1 # hodina zpět pro výpočet korekčního faktoru
|
||||||
|
CORRECTION_MIN_CLAMP = 0.5 # spodní limit korekčního faktoru
|
||||||
|
CORRECTION_MAX_CLAMP = 1.5 # horní limit korekčního faktoru
|
||||||
|
# Útlum korekce: čím dál od aktuálního času, tím méně korigujeme forecast
|
||||||
|
CORRECTION_DECAY_SLOTS = 16 # po 16 slotech (4h) klesne korekce na 0
|
||||||
|
# Dynamická ekonomická podlaha (MILP w_arb): lookahead FVE energie v dalších slotech
|
||||||
|
ARB_LOOKAHEAD_SLOTS = 32 # 8 h při INTERVAL_H=0.25
|
||||||
|
ARB_FLOOR_E_REF_FRAC = 0.5 # má scale Wh = tato frakce usable_capacity (0..1)
|
||||||
|
|
||||||
|
_PRAGUE_TZ = ZoneInfo("Europe/Prague")
|
||||||
|
|
||||||
@@ -24,111 +24,65 @@ from app.config import get_settings
|
|||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
from services.planning.constants import (
|
||||||
# Konstanty
|
ACQUISITION_TWO_PASS_EPS_KWH,
|
||||||
# ============================================================
|
SOLVER_RELAX_STEPS,
|
||||||
|
ARB_FLOOR_E_REF_FRAC,
|
||||||
# Když DB vrátí NULL (skoro žádná OTE data), denní plán použije krátký fallback (soulad s min hodinami ve fn_planning_horizon_end).
|
ARB_LOOKAHEAD_SLOTS,
|
||||||
_DAILY_FALLBACK_HORIZON_HOURS = 1.0
|
CORRECTION_DECAY_SLOTS,
|
||||||
# Shadow cena zbytkové energie na konci horizontu: - (avg_buy * FACTOR / 1000) * soc[T-1] (Kč; soc v Wh).
|
CORRECTION_MAX_CLAMP,
|
||||||
INTERVAL_H = 0.25 # 15 minut v hodinách
|
CORRECTION_MIN_CLAMP,
|
||||||
CURTAILMENT_PENALTY = 0.001 # Kč/Wh – malá penalizace za omezení FVE pole A
|
CORRECTION_WINDOW_H,
|
||||||
SOLVER_TIME_LIMIT = 10 # sekund
|
CURTAILMENT_PENALTY,
|
||||||
# MILP: významný export ge (W) ⇒ koncové soc[t] ≥ podlaha; mimo arbitrážní relax je to arb_base_wh
|
DAWN_LOW_PV_NO_CURTAIL_W,
|
||||||
# (rezerva z DB). Při relaxaci spodku před extrémně záporným buy je podlaha soc_panel_min[t]
|
DEFAULT_PLANNER_DISCHARGE_RELAX_PREWINDOW_SLOTS,
|
||||||
# (planner floor), jinak by šlo jen do zátěže a nešlo by „vypustit do sítě“ před levným nákupem.
|
EVENING_PEAK_SELL_EPS_CZK_KWH,
|
||||||
GE_MIN_EXPORT_W = 1.0
|
EVENING_PUSH_HYSTERESIS_SELL_PEAK_DELTA_CZK_KWH,
|
||||||
# Dvouprůchodové solve: stop když acquisition z pass1 vs pass2 se liší méně než (Kč/kWh).
|
EVENING_PUSH_HYSTERESIS_SOC_PCT,
|
||||||
ACQUISITION_TWO_PASS_EPS_KWH = 0.05
|
EVENING_PUSH_Z_EXPORT_BONUS_CZK,
|
||||||
# Load-first (Deye): PV nejdřív pokryje load+EV+TČ; bc_pv/ge_pv jen z pv_sp (přebytek).
|
EXTREME_BUY_DUMP_PREWINDOW_SLOTS,
|
||||||
LOAD_FIRST_INCENTIVE_CZK_KWH = 0.05
|
GE_MIN_EXPORT_W,
|
||||||
# Dokud je kotva pro hluboký dump (první sell < 0 v horizontu, jinak první extrémní buy) dál než
|
INTERVAL_H,
|
||||||
# tento počet 15min slotů, držíme plánovací spodek na rezervě (arb_base_wh) místo planner floor —
|
LOAD_FIRST_INCENTIVE_CZK_KWH,
|
||||||
# priorita: beze „ztráty na prodeji“ (sell >= 0) držet buffer, hluboký vývoz až těsně před záporným prodejem.
|
NEG_BUY_CHARGE_SHORTFALL_PENALTY_CZK_KWH,
|
||||||
DEFAULT_PLANNER_DISCHARGE_RELAX_PREWINDOW_SLOTS = 8
|
NEG_EVENING_PREP_DISCHARGE_SHORTFALL_PENALTY_CZK_KWH,
|
||||||
# Měkká kotva: chceme být u planner floor už v posledním slotu před prvním sell < 0.
|
NEG_EVENING_RESERVE_SOC_MAX_SLACK_WH,
|
||||||
# Penalizace je v Kč/Wh (např. 0.20 = 200 Kč/kWh). Musí být dost velká, aby přebila
|
NEG_EVENING_RESERVE_SOC_SLACK_PENALTY_CZK_PER_WH,
|
||||||
# bezpečnostní SoC buffer + terminal shadow cenu a solver skutečně „dovylil“ před sell<0.
|
NEG_SELL_BAT_DUMP_SHORTFALL_PENALTY_CZK_KWH,
|
||||||
PRENEG_SELL_SOC_ANCHOR_SLACK_PENALTY_CZK_PER_WH = 0.20
|
NEG_SELL_CURTAIL_PENALTY_CZK_KWH,
|
||||||
PEAK_EXPORT_SHORTFALL_PENALTY_CZK_KWH = 80.0
|
NEG_SELL_POST_DETACH_BCPV_DISCOURAGE_CZK_KWH,
|
||||||
# Měkký tlak: v okně sell<0 + block_export využít PV přebytek do baterie (ne curtail).
|
NEG_SELL_PREP_HOLD_BCPV_PENALTY_CZK_KWH,
|
||||||
PV_CHARGE_SHORTFALL_PENALTY_CZK_KWH = 120.0
|
NEG_SELL_PREP_SOC_SHORTFALL_PENALTY_CZK_PER_WH,
|
||||||
# Curtailment při sell<0 + allow_charge: nesmí být téměř zdarma oproti nabíjení (BA81).
|
NEG_SELL_PV_B_VENT_PENALTY_CZK_KWH,
|
||||||
NEG_SELL_CURTAIL_PENALTY_CZK_KWH = 1.0
|
NEG_SELL_PV_CHARGE_REWARD_CZK_KWH,
|
||||||
# Odměna v objective za FVE→baterie při sell<0 (doplňuje shortfall; BA81 fixed tarif).
|
NEG_SELL_SOC_UNDERFILL_PENALTY_CZK_PER_WH,
|
||||||
NEG_SELL_PV_CHARGE_REWARD_CZK_KWH = 0.8
|
NIGHT_EXPORT_EVENING_START_HOUR,
|
||||||
# Měkký tlak: v okně sell<0 dobít na soc_max (ne zastavit na ~94 % kvůli curtail).
|
NIGHT_EXPORT_MORNING_END_HOUR,
|
||||||
NEG_SELL_SOC_UNDERFILL_PENALTY_CZK_PER_WH = 0.35
|
NIGHT_EXPORT_PV_SUNRISE_SURPLUS_W,
|
||||||
# Jen ventil nekontrolovatelného pole B při plné baterii a sell<0 (spot); ne celý PV přebytek.
|
NIGHT_SELF_CONSUME_IMPORT_SURCHARGE_CZK_KWH,
|
||||||
NEG_SELL_PV_B_VENT_PENALTY_CZK_KWH = 4.0
|
PEAK_EXPORT_SHORTFALL_PENALTY_CZK_KWH,
|
||||||
# Fáze sell<0 (v32): ASAP na prep_soc %, tail rampa na soc_max.
|
PLANNER_BUILD_TAG,
|
||||||
NEG_SELL_PREP_SOC_SHORTFALL_PENALTY_CZK_PER_WH = 0.85
|
POS_SELL_PRE_NEG_SOC_SHORTFALL_PENALTY_CZK_PER_WH,
|
||||||
NEG_SELL_PREP_HOLD_BCPV_PENALTY_CZK_KWH = 60.0
|
PRENEG_SELL_SOC_ANCHOR_SLACK_PENALTY_CZK_PER_WH,
|
||||||
# Výboj baterie při sell<0 jen těsně před extrémně záporným buy (round-trip arbitráž).
|
PRE_NEG_BATT_EXPORT_MIN_SELL_CZK_KWH,
|
||||||
EXTREME_BUY_DUMP_PREWINDOW_SLOTS = 12
|
PRE_NEG_BATT_EXPORT_SHORTFALL_PENALTY_CZK_KWH,
|
||||||
NEG_SELL_BAT_DUMP_SHORTFALL_PENALTY_CZK_KWH = 80.0
|
PRE_NEG_BUY_EMPTY_EXPORT_SHORTFALL_PENALTY_CZK_KWH,
|
||||||
NEG_BUY_CHARGE_SHORTFALL_PENALTY_CZK_KWH = 100.0
|
PRE_NEG_BUY_PV_CHARGE_PENALTY_CZK_KWH,
|
||||||
PRE_NEG_CHARGE_PENALTY_CZK_KWH = 400.0
|
PRE_NEG_BUY_SOC_CEILING_SLACK_PENALTY_CZK_PER_WH,
|
||||||
PRE_NEG_BATT_EXPORT_SHORTFALL_PENALTY_CZK_KWH = 80.0
|
PRE_NEG_CHARGE_PENALTY_CZK_KWH,
|
||||||
PRE_NEG_BATT_EXPORT_MIN_SELL_CZK_KWH = 1.0
|
PRE_NEG_PV_BCPV_DISCOURAGE_CZK_KWH,
|
||||||
PLANNER_BUILD_TAG = "2026-06-06-home01-strict-late-replan-v5"
|
PRE_NEG_PV_EXPORT_FORECAST_MARGIN,
|
||||||
SOLVER_RELAX_STEPS: tuple[str, ...] = (
|
PRE_NEG_PV_EXPORT_MIN_NEEDED_WH,
|
||||||
"strict",
|
PRE_NEG_PV_EXPORT_SHORTFALL_PENALTY_CZK_KWH,
|
||||||
"relaxed_expensive_import",
|
PV_CHARGE_SHORTFALL_PENALTY_CZK_KWH,
|
||||||
"relaxed_neg_buy_charge",
|
SOLVER_TIME_LIMIT,
|
||||||
"relaxed_neg_prep_hold_only",
|
TERMINAL_NEG_BUY_MAGNITUDE_FLOOR,
|
||||||
"relaxed_neg_prep_window",
|
TERMINAL_NEG_BUY_MAGNITUDE_REF_CZK,
|
||||||
"neg_sell_phases_fallback",
|
TERMINAL_NEG_BUY_WEIGHT_CAP,
|
||||||
"relaxed_pos_sell_ge_block",
|
TERMINAL_NEG_BUY_WEIGHT_HORIZON_SLOTS,
|
||||||
"relaxed_solver_masks",
|
_DAILY_FALLBACK_HORIZON_HOURS,
|
||||||
|
_PRAGUE_TZ,
|
||||||
)
|
)
|
||||||
# Ranní slabá FVE: neaplikovat pv_store ge_pv=0 (jinak curtail při sell < večerní peak).
|
|
||||||
DAWN_LOW_PV_NO_CURTAIL_W = 1500
|
|
||||||
# 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
|
|
||||||
# Po t_detach v prep: necpát PV do bat (měkké; tvrdý hold přes soc_target z rampy).
|
|
||||||
NEG_SELL_POST_DETACH_BCPV_DISCOURAGE_CZK_KWH = 250.0
|
|
||||||
# Večer před neg dnem: výboj do sítě (měkký shortfall na ge_bat).
|
|
||||||
NEG_EVENING_PREP_DISCHARGE_SHORTFALL_PENALTY_CZK_KWH = 120.0
|
|
||||||
# Kotva: SoC na konci večera D−1 a těsně před 1. sell<0 ráno D ≤ reserve_soc.
|
|
||||||
NEG_EVENING_RESERVE_SOC_MAX_SLACK_WH = 400.0
|
|
||||||
NEG_EVENING_RESERVE_SOC_SLACK_PENALTY_CZK_PER_WH = 55.0
|
|
||||||
# Terminal SoC shadow price: effective_factor = base × (1 − w_neg); w_neg roste s blízkostí a záporností buy<0.
|
|
||||||
TERMINAL_NEG_BUY_WEIGHT_HORIZON_SLOTS = int(36 / INTERVAL_H)
|
|
||||||
TERMINAL_NEG_BUY_MAGNITUDE_REF_CZK = 1.0
|
|
||||||
TERMINAL_NEG_BUY_MAGNITUDE_FLOOR = 0.25
|
|
||||||
TERMINAL_NEG_BUY_WEIGHT_CAP = 0.95
|
|
||||||
# Před prvním sell<0: export FVE jen pokud predikce v sell<0 okně pokryje dobítí na prep cíl.
|
|
||||||
PRE_NEG_PV_EXPORT_FORECAST_MARGIN = 1.15
|
|
||||||
PRE_NEG_PV_EXPORT_MIN_NEEDED_WH = 2500.0
|
|
||||||
PRE_NEG_PV_EXPORT_SHORTFALL_PENALTY_CZK_KWH = 55.0
|
|
||||||
PRE_NEG_PV_BCPV_DISCOURAGE_CZK_KWH = 90.0
|
|
||||||
POS_SELL_PRE_NEG_SOC_SHORTFALL_PENALTY_CZK_PER_WH = 0.30
|
|
||||||
PRE_NEG_BUY_SOC_CEILING_SLACK_PENALTY_CZK_PER_WH = 0.25
|
|
||||||
PRE_NEG_BUY_EMPTY_EXPORT_SHORTFALL_PENALTY_CZK_KWH = 80.0
|
|
||||||
EVENING_PEAK_SELL_EPS_CZK_KWH = 0.05
|
|
||||||
# Rolling replan: držet evening_push_ts při malé změně peak sell / SoC.
|
|
||||||
EVENING_PUSH_HYSTERESIS_SELL_PEAK_DELTA_CZK_KWH = 0.5
|
|
||||||
EVENING_PUSH_HYSTERESIS_SOC_PCT = 5.0
|
|
||||||
# Noční výprodej baterie: večer (≥17h) + ráno do východu FVE (0–5h Prague), jedna špička přes půlnoc.
|
|
||||||
NIGHT_EXPORT_EVENING_START_HOUR = 17
|
|
||||||
NIGHT_EXPORT_MORNING_END_HOUR = 5
|
|
||||||
NIGHT_EXPORT_PV_SUNRISE_SURPLUS_W = 500.0
|
|
||||||
# Převáží terminal SoC shadow price při krátkém večerním horizontu (home-01).
|
|
||||||
EVENING_PUSH_Z_EXPORT_BONUS_CZK = 2500.0
|
|
||||||
# buy<0: preferovat import před PV A→bat (měkké; tvrdé bc_pv=0 láme bilanci s polem B).
|
|
||||||
PRE_NEG_BUY_PV_CHARGE_PENALTY_CZK_KWH = 250.0
|
|
||||||
CORRECTION_WINDOW_H = 1 # hodina zpět pro výpočet korekčního faktoru
|
|
||||||
CORRECTION_MIN_CLAMP = 0.5 # spodní limit korekčního faktoru
|
|
||||||
CORRECTION_MAX_CLAMP = 1.5 # horní limit korekčního faktoru
|
|
||||||
# Útlum korekce: čím dál od aktuálního času, tím méně korigujeme forecast
|
|
||||||
CORRECTION_DECAY_SLOTS = 16 # po 16 slotech (4h) klesne korekce na 0
|
|
||||||
# Dynamická ekonomická podlaha (MILP w_arb): lookahead FVE energie v dalších slotech
|
|
||||||
ARB_LOOKAHEAD_SLOTS = 32 # 8 h při INTERVAL_H=0.25
|
|
||||||
ARB_FLOOR_E_REF_FRAC = 0.5 # má scale Wh = tato frakce usable_capacity (0..1)
|
|
||||||
|
|
||||||
_PRAGUE_TZ = ZoneInfo("Europe/Prague")
|
|
||||||
|
|
||||||
|
|
||||||
class PlannerSolverError(RuntimeError):
|
class PlannerSolverError(RuntimeError):
|
||||||
"""Solver selhal po vyčerpání retry řetězce (typicky Infeasible)."""
|
"""Solver selhal po vyčerpání retry řetězce (typicky Infeasible)."""
|
||||||
|
|||||||
Reference in New Issue
Block a user