nerezta PV A pri prodeji z baterie
This commit is contained in:
@@ -68,7 +68,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-28-night-export-window-midnight-v30"
|
||||
PLANNER_BUILD_TAG = "2026-05-28-morning-pv-export-priority-v31"
|
||||
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
|
||||
@@ -971,6 +971,16 @@ def _slot_pv_surplus_w(slot: PlanningSlot) -> float:
|
||||
return max(0.0, pv_w - load_w)
|
||||
|
||||
|
||||
def _battery_export_push_defer_to_pv(slot: PlanningSlot) -> bool:
|
||||
"""
|
||||
Při kladném sell a PV přebytku nevnucovat plný ge_bat push (pre-neg / ranní větve).
|
||||
Exportní cap má pokrýt ge_pv; baterii řeší večerní push a sell<0 okna.
|
||||
"""
|
||||
if float(slot.sell_price) < 0.0:
|
||||
return False
|
||||
return _slot_pv_surplus_w(slot) > NIGHT_EXPORT_PV_SUNRISE_SURPLUS_W
|
||||
|
||||
|
||||
def _in_night_battery_export_window(slot: PlanningSlot) -> bool:
|
||||
"""
|
||||
Noční okno pro večerní push / peak sell: >=17h Prague, nebo 0–5h (přes půlnoc).
|
||||
@@ -1746,6 +1756,8 @@ def solve_dispatch(
|
||||
continue
|
||||
if t in evening_push_ts:
|
||||
continue
|
||||
if _battery_export_push_defer_to_pv(slots[t]):
|
||||
continue
|
||||
if not _slot_profitable_battery_export(
|
||||
slots[t],
|
||||
charge_acquisition_czk_kwh=charge_acquisition_czk_kwh,
|
||||
@@ -1761,9 +1773,13 @@ def solve_dispatch(
|
||||
peak_export_shortfall.append((t, sf, cap_w))
|
||||
export_cap_w = _battery_export_cap_w(battery, grid)
|
||||
for t_pnd in sorted(pre_neg_buy_discharge_ts):
|
||||
if _battery_export_push_defer_to_pv(slots[t_pnd]):
|
||||
continue
|
||||
sf_pnd = pulp.LpVariable(f"pre_neg_bat_export_sf_{t_pnd}", 0, export_cap_w)
|
||||
pre_neg_batt_export_shortfall.append((t_pnd, sf_pnd, export_cap_w))
|
||||
for t_empty in pre_neg_buy_empty_ts:
|
||||
if _battery_export_push_defer_to_pv(slots[t_empty]):
|
||||
continue
|
||||
sf_e = pulp.LpVariable(f"pre_neg_buy_empty_sf_{t_empty}", 0, export_cap_w)
|
||||
pre_neg_buy_empty_shortfall.append((t_empty, sf_e, export_cap_w))
|
||||
if not relaxed_neg_buy_charge:
|
||||
@@ -2032,11 +2048,17 @@ def solve_dispatch(
|
||||
export_push_w = _battery_export_cap_w(battery, grid)
|
||||
for t_peak in morning_pre_neg_export_ts:
|
||||
if t_peak in profitable_export_ts:
|
||||
if _battery_export_push_defer_to_pv(slots[t_peak]):
|
||||
continue
|
||||
prob += ge_bat[t_peak] >= export_push_w * z_export[t_peak]
|
||||
for t_pnd in pre_neg_buy_discharge_ts:
|
||||
if _battery_export_push_defer_to_pv(slots[t_pnd]):
|
||||
continue
|
||||
prob += ge_bat[t_pnd] >= export_push_w * z_export[t_pnd]
|
||||
for t_empty in pre_neg_buy_empty_ts:
|
||||
if t_empty in discharge_export_slots:
|
||||
if _battery_export_push_defer_to_pv(slots[t_empty]):
|
||||
continue
|
||||
prob += ge_bat[t_empty] >= export_push_w * z_export[t_empty]
|
||||
for t_early in sorted(evening_early_export_penalty_ts):
|
||||
prob += ge_bat[t_early] == 0
|
||||
|
||||
Reference in New Issue
Block a user