dalsi pokus o opravu
This commit is contained in:
@@ -685,6 +685,8 @@ def solve_dispatch(
|
||||
for t in range(T)
|
||||
]
|
||||
ge = [pulp.LpVariable(f"ge_{t}", 0, grid.max_export_power_w) for t in range(T)]
|
||||
ge_pv = [pulp.LpVariable(f"ge_pv_{t}", 0, grid.max_export_power_w) for t in range(T)]
|
||||
ge_bat = [pulp.LpVariable(f"ge_bat_{t}", 0, grid.max_export_power_w) for t in range(T)]
|
||||
bc = [pulp.LpVariable(f"bc_{t}", 0, battery.max_charge_power_w) for t in range(T)]
|
||||
bd = [pulp.LpVariable(f"bd_{t}", 0, battery.max_discharge_power_w) for t in range(T)]
|
||||
soc = [
|
||||
@@ -881,6 +883,9 @@ def solve_dispatch(
|
||||
pv_a_net + pv_b_effective + gi[t] + bd[t]
|
||||
== s.load_baseline_w + ev_total_t + hp[t] + bc[t] + ge[t]
|
||||
)
|
||||
prob += ge[t] == ge_pv[t] + ge_bat[t]
|
||||
# Baterie nesmí „přestrojit“ FVE export: přebytek nad PV musí jít přes ge_bat.
|
||||
prob += ge_bat[t] >= ge[t] - (pv_a_net + pv_b_effective)
|
||||
|
||||
# Měkký breaker cap: gi_over[t] >= max(0, gi[t] - breaker).
|
||||
prob += gi_over[t] >= gi[t] - float(grid.max_import_power_w)
|
||||
@@ -936,6 +941,8 @@ def solve_dispatch(
|
||||
)
|
||||
if z_gen_cutoff is not None or block_neg_sell_export:
|
||||
prob += ge[t] == 0
|
||||
prob += ge_pv[t] == 0
|
||||
prob += ge_bat[t] == 0
|
||||
|
||||
soc_prev_expr = current_soc_wh if t == 0 else soc[t - 1]
|
||||
arb_t = arb_floor_series[t]
|
||||
@@ -946,10 +953,7 @@ def solve_dispatch(
|
||||
arb_cap_t = min(arb_t, soc_low_t)
|
||||
else:
|
||||
arb_cap_t = arb_t
|
||||
if om == "AUTO" and t not in discharge_export_slots:
|
||||
# PASSIVE na střídači: EMS neplánuje vybíjení do load (Deye pokryje skutečnou zátěž).
|
||||
pass
|
||||
elif om == "AUTO" and t in discharge_export_slots:
|
||||
if om == "AUTO" and t in discharge_export_slots:
|
||||
prob += soc_prev_expr >= (
|
||||
arb_cap_t - (arb_cap_t - soc_low_t) * (1 - w_arb[t])
|
||||
)
|
||||
@@ -957,6 +961,17 @@ def solve_dispatch(
|
||||
battery.max_discharge_power_w * w_arb[t]
|
||||
+ pulp.lpSum(ev_via_bat[e][t] for e in range(EV))
|
||||
)
|
||||
elif om == "AUTO":
|
||||
# PASSIVE: vlastní spotřeba (bd); export baterie jen ge_bat (ge_bat=0 níže).
|
||||
prob += soc_prev_expr >= (
|
||||
arb_cap_t - (arb_cap_t - soc_low_t) * (1 - w_arb[t])
|
||||
)
|
||||
prob += bd[t] <= (
|
||||
s.load_baseline_w
|
||||
+ ev_total_t
|
||||
+ hp[t]
|
||||
+ bc[t]
|
||||
)
|
||||
else:
|
||||
prob += soc_prev_expr >= (
|
||||
arb_cap_t - (arb_cap_t - soc_low_t) * (1 - w_arb[t])
|
||||
@@ -969,11 +984,11 @@ def solve_dispatch(
|
||||
+ battery.max_discharge_power_w * w_arb[t]
|
||||
)
|
||||
|
||||
# Významný export ⇒ koncové SoC ≥ podlaha (viz soc_panel_min / arb_base).
|
||||
# Významný export z baterie ⇒ koncové SoC ≥ podlaha (FVE export ge_pv bez této podlahy).
|
||||
m_ge = float(grid.max_export_power_w)
|
||||
m_soc_bigm = float(battery.usable_capacity_wh)
|
||||
prob += ge[t] <= m_ge * z_export[t]
|
||||
prob += ge[t] >= GE_MIN_EXPORT_W * z_export[t]
|
||||
prob += ge_bat[t] <= m_ge * z_export[t]
|
||||
prob += ge_bat[t] >= GE_MIN_EXPORT_W * z_export[t]
|
||||
# Bez hluboké relaxace: export končí ≥ rezerva. Při hluboké relaxaci (soc_panel_min pod min_soc)
|
||||
# sladit s LP spodkem — jinak z_export vynutil arb_base a blokoval vývoz k planner floor.
|
||||
if soc_panel_min[t] < min_soc_wh - 1e-3:
|
||||
@@ -1018,16 +1033,29 @@ def solve_dispatch(
|
||||
elif om == "CHARGE_CHEAP":
|
||||
for t in range(T):
|
||||
prob += ge[t] == 0
|
||||
prob += ge_pv[t] == 0
|
||||
prob += ge_bat[t] == 0
|
||||
prob += bd[t] == 0
|
||||
|
||||
# Slot pre-selection (z DB fn_load_planning_slots_full → allow_*)
|
||||
if om == "AUTO":
|
||||
for t in range(T):
|
||||
if t not in charge_slots:
|
||||
prob += bc[t] == 0
|
||||
s = slots[t]
|
||||
pv_surplus_w = max(
|
||||
0,
|
||||
int(s.pv_a_forecast_w)
|
||||
+ int(s.pv_b_forecast_w)
|
||||
- int(s.load_baseline_w),
|
||||
)
|
||||
# Mimo grid-charge masku smí nabíjet jen z PV přebytku (ne import ze sítě).
|
||||
if pv_surplus_w <= 0:
|
||||
prob += bc[t] == 0
|
||||
else:
|
||||
prob += bc[t] <= pv_surplus_w
|
||||
if t not in discharge_export_slots:
|
||||
prob += bd[t] == 0
|
||||
prob += w_arb[t] == 0
|
||||
prob += ge_bat[t] == 0
|
||||
prob += z_export[t] == 0
|
||||
|
||||
# Deadline constraints pro EV
|
||||
for e, session in enumerate(ev_sessions):
|
||||
@@ -1094,9 +1122,14 @@ def solve_dispatch(
|
||||
grid_w = round(pulp.value(gi[t]) - pulp.value(ge[t]))
|
||||
soc_pct = round(pulp.value(soc[t]) / battery.usable_capacity_wh * 100, 1)
|
||||
export_limit_w = int(grid.max_export_power_w) if grid_w < 0 else 0
|
||||
ge_bat_w = round(float(pulp.value(ge_bat[t]) or 0))
|
||||
export_mode = "NONE"
|
||||
if grid_w < 0:
|
||||
export_mode = "BATTERY_SELL" if batt_w < 0 else "PV_SURPLUS"
|
||||
export_mode = (
|
||||
"BATTERY_SELL"
|
||||
if ge_bat_w >= GE_MIN_EXPORT_W
|
||||
else "PV_SURPLUS"
|
||||
)
|
||||
|
||||
# Deye: default PASSIVE (střídač pokryje load). CHARGE/SELL jen v maskovaných AUTO slotech.
|
||||
deye_mode = "PASSIVE"
|
||||
|
||||
Reference in New Issue
Block a user