oprava exportu bateir do site vecer
This commit is contained in:
@@ -68,11 +68,13 @@ 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-evening-peak-full-export-v26"
|
||||
PLANNER_BUILD_TAG = "2026-05-28-evening-peak-full-export-v27"
|
||||
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
|
||||
# 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
|
||||
@@ -818,8 +820,8 @@ def _evening_push_battery_export_w(
|
||||
grid: Any,
|
||||
) -> float:
|
||||
"""
|
||||
Nejvyšší ge_bat v push slotu při load-first: bd+ge_bat ≤ max_discharge, gi ≤ load+bc_gi.
|
||||
Prakticky max export z baterie ≈ min(site/inverter cap, max_discharge − load).
|
||||
Nejvyšší ge_bat v push slotu při drahém importu (gi≈0): bilance dá bd ≈ load + ge_bat,
|
||||
tedy ge_bat + bd ≤ max_discharge → ge_bat ≤ (max_discharge − load) / 2.
|
||||
"""
|
||||
cap = _battery_export_cap_w(battery, grid)
|
||||
load_w = max(0.0, float(slot.load_baseline_w))
|
||||
@@ -827,7 +829,10 @@ def _evening_push_battery_export_w(
|
||||
0.0,
|
||||
float(battery.max_discharge_power_w) - load_w,
|
||||
)
|
||||
return min(cap, discharge_headroom)
|
||||
if discharge_headroom <= 0.0:
|
||||
return 0.0
|
||||
export_from_balance = discharge_headroom / 2.0
|
||||
return min(cap, discharge_headroom, export_from_balance)
|
||||
|
||||
|
||||
def _dispatch_grid_setpoint_w(
|
||||
@@ -1575,17 +1580,23 @@ def solve_dispatch(
|
||||
max_evening_sell_by_day.get(d_ev, 0.0),
|
||||
float(s_ev.sell_price),
|
||||
)
|
||||
for t_ev, s_ev in enumerate(slots):
|
||||
if _prague_hour(s_ev) < 17:
|
||||
continue
|
||||
if t_ev not in profitable_export_ts_pre or t_ev not in discharge_export_slots:
|
||||
continue
|
||||
if t_ev in evening_push_ts:
|
||||
continue
|
||||
d_ev = _prague_calendar_date(s_ev)
|
||||
peak_sell = max_evening_sell_by_day.get(d_ev, 0.0)
|
||||
if float(s_ev.sell_price) < peak_sell - EVENING_PEAK_SELL_EPS_CZK_KWH:
|
||||
evening_early_export_penalty_ts.add(t_ev)
|
||||
# Zákaz ge_bat jen *před* prvním push slotem (ne po něm — jinak terminal SoC + load
|
||||
# drží energii pro 19–21 h bez prodeje, home-01 téměř neexportuje).
|
||||
first_evening_push_t = min(evening_push_ts) if evening_push_ts else None
|
||||
if first_evening_push_t is not None:
|
||||
for t_ev, s_ev in enumerate(slots):
|
||||
if _prague_hour(s_ev) < 17:
|
||||
continue
|
||||
if t_ev >= first_evening_push_t:
|
||||
continue
|
||||
if t_ev not in profitable_export_ts_pre or t_ev not in discharge_export_slots:
|
||||
continue
|
||||
if t_ev in evening_push_ts:
|
||||
continue
|
||||
d_ev = _prague_calendar_date(s_ev)
|
||||
peak_sell = max_evening_sell_by_day.get(d_ev, 0.0)
|
||||
if float(s_ev.sell_price) < peak_sell - EVENING_PEAK_SELL_EPS_CZK_KWH:
|
||||
evening_early_export_penalty_ts.add(t_ev)
|
||||
last_pos_sell_pre_neg_buy = _last_non_negative_sell_before_neg_buy(
|
||||
slots, first_neg_buy_idx
|
||||
)
|
||||
@@ -1947,7 +1958,7 @@ def solve_dispatch(
|
||||
if t in discharge_export_slots and t in profitable_export_ts_pre
|
||||
)
|
||||
+ pulp.lpSum(
|
||||
-250.0 * z_export[t]
|
||||
-EVENING_PUSH_Z_EXPORT_BONUS_CZK * z_export[t]
|
||||
for t in evening_push_ts
|
||||
)
|
||||
)
|
||||
@@ -2002,7 +2013,11 @@ def solve_dispatch(
|
||||
slots[t_peak], battery, grid
|
||||
)
|
||||
if push_floor_w >= GE_MIN_EXPORT_W:
|
||||
prob += ge_bat[t_peak] >= push_floor_w * z_export[t_peak]
|
||||
load_push_w = float(slots[t_peak].load_baseline_w)
|
||||
prob += z_export[t_peak] == 1
|
||||
prob += ge_bat[t_peak] >= push_floor_w
|
||||
# Drahý import (gi≈0): bez bd ≥ load + ge_bat zůstane jen vybíjení do domu.
|
||||
prob += bd[t_peak] + ge_bat[t_peak] >= load_push_w + push_floor_w
|
||||
# Ostatní profitable sloty: měkká shortfall penalizace (ne večerní push).
|
||||
if (
|
||||
last_pos_sell_pre_neg_buy is not None
|
||||
|
||||
Reference in New Issue
Block a user