dalsi
Some checks failed
CI and deploy / migration-check (push) Failing after 23s
CI and deploy / deploy (push) Has been skipped

This commit is contained in:
Dusan Vojacek
2026-05-29 23:34:16 +02:00
parent 308c24f029
commit d3e9caf0fb
5 changed files with 154 additions and 11 deletions

View File

@@ -71,7 +71,7 @@ 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-05-29-night-selfconsume-evening-arb-v43"
PLANNER_BUILD_TAG = "2026-05-29-neg-day-pv-headroom-v44"
# 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).
@@ -895,6 +895,20 @@ def _neg_sell_pv_b_charge_wh(slot: PlanningSlot, battery: Any) -> float:
return cap_w * INTERVAL_H * float(battery.charge_efficiency)
def _neg_sell_pv_forecast_charge_wh(slot: PlanningSlot, battery: Any) -> float:
"""Odhad Wh z FVE A+B v sell<0 slotu pro zpětnou projekci soc_need (v44)."""
pv_surplus = max(
0.0,
float(slot.pv_a_forecast_w)
+ float(slot.pv_b_forecast_w)
- float(slot.load_baseline_w),
)
if pv_surplus <= 500.0:
return 0.0
cap_w = min(pv_surplus, float(battery.max_charge_power_w))
return cap_w * INTERVAL_H * float(battery.charge_efficiency)
def _neg_sell_day_pv_b_usable_wh(
slots: list[PlanningSlot],
first_neg_sell_idx: int | None,
@@ -975,7 +989,9 @@ def _neg_sell_day_phases(
indices.sort()
last_t = indices[-1]
tail_start = max(indices[0], last_t - tail_n + 1) if tail_n > 0 else last_t + 1
charge_b = {t: _neg_sell_pv_b_charge_wh(slots[t], battery) for t in indices}
charge_b = {
t: _neg_sell_pv_forecast_charge_wh(slots[t], battery) for t in indices
}
soc_need: dict[int, float] = {last_t: soc_max}
for i in range(len(indices) - 1, 0, -1):
t_cur = indices[i]
@@ -3586,6 +3602,14 @@ def solve_dispatch(
# v33: při dostatečné FVE v sell<0 okně neukládat ranní PV do baterie — export.
prob += bc_pv[t_pne] == 0
# v44: neg den — před 1. sell<0 žádné grid→bat (AM sloty za ~3 Kč vs FVE v okně).
if neg_sell_phases_en and first_neg_sell_idx is not None:
neg_day = _prague_calendar_date(slots[first_neg_sell_idx])
for t_blk in range(first_neg_sell_idx):
if _prague_calendar_date(slots[t_blk]) != neg_day:
continue
prob += bc_gi[t_blk] == 0
# Ekonomické guardy: ceny v objective nestačí proti maskám / terminal SoC.
# Referenční buy jen z ne-záporných slotů: jinak jeden buy<0 v horizontu označí
# téměř všechny sloty jako „drahé“ (gi=0 pro dům) → Infeasible (home-01).