v2: měkký EV cíl — oportunistické nabíjení nad target (+ strop energie)
Uživatel: 'potřebuju do X % (tvrdý), ale klidně dobij na 100 % když je to skoro zadarmo; při záporných cenách radši do auta než nechat na střeše'. - V094 asset_vehicle.opportunistic_value_czk_kwh (default 1.0; = hodnota ušetřeného BUDOUCÍHO nabíjení — auto neumí zpět, žádný noční prodej) - R__039 ev_sessions: + headroom_wh ((100−target) % kapacity) + opp value; session se nenuluje po dosažení targetu, dokud má headroom - solver_v2: dekompozice Σ(EV) == needed − unmet + opp, opp ∈ [0, headroom], odměna opp×value; zároveň FIX latentního bugu — při buy<0 chyběl strop celkové energie do auta (model mohl pumpovat bez limitu) - 3 testy (neg ceny sají nad target po strop; běžné ceny ne; cap při opp=0); eval fixtures beze změny (sessions null) Víkend (pátek nízký tvrdý cíl + víkendová negativa → samo doplní do 100 %) vyplývá z mechanismu, žádná speciální logika. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,11 @@
|
||||
# indiference v čase; odložení ale spoléhá na predikci (večerní mrak).
|
||||
# Malá prémie za držení energie dřív (DB planner_pv_risk_frontload_czk_kwh)
|
||||
# vede k "nabít plným výkonem hned, pak řezat A" — emergentně, bez rampy.
|
||||
# - oportunistické EV („měkký cíl"): nad tvrdý target smí auto vzít až
|
||||
# headroom_wh (do 100 %), oceněno opportunistic_value_czk_kwh (= budoucí
|
||||
# ušetřené nabíjení, DB) — kupuje jen velmi levnou/zápornou energii.
|
||||
# Dekompozice Σ(EV energie) == needed − unmet + opp zároveň stropuje
|
||||
# celkovou energii do auta (dřív při buy<0 bez stropu).
|
||||
# - denní SoC rampa: deficit pod slot.safety_soc_target_wh (R__063: reserve →
|
||||
# reserve+noc, 6–19 h) platí za slot nájem buy×faktor (DB
|
||||
# planner_safety_soc_risk_factor) — ráno se nejdřív dotáhne rezerva
|
||||
@@ -160,6 +165,7 @@ def solve_dispatch_v2(
|
||||
for e in range(EV)
|
||||
]
|
||||
ev_unmet: list = [] # slack Wh per session (cena V2_EV_UNMET_CZK_KWH)
|
||||
ev_opp: list = [] # (var, value_czk_kwh) — energie nad target (měkký cíl)
|
||||
nb_buffer_wh = [max(0.0, float(s.night_baseload_buffer_wh or 0.0)) for s in slots]
|
||||
safety_risk = float(getattr(battery, "planner_safety_soc_risk_factor", 0.0) or 0.0)
|
||||
safety_tgt_wh = [
|
||||
@@ -281,6 +287,20 @@ def solve_dispatch_v2(
|
||||
>= float(sess.energy_needed_wh)
|
||||
), f"ev_deadline_{e}"
|
||||
|
||||
# měkký cíl: dekompozice celkové energie == needed − unmet + opp
|
||||
headroom = max(0.0, float(getattr(sess, "headroom_wh", 0.0) or 0.0))
|
||||
opp_val = float(getattr(sess, "opportunistic_value_czk_kwh", 0.0) or 0.0)
|
||||
opp = pulp.LpVariable(f"ev_opp_{e}", 0, headroom if opp_val > 0 else 0.0)
|
||||
ev_opp.append((opp, opp_val))
|
||||
prob += (
|
||||
pulp.lpSum(
|
||||
(ev_direct[e][t] + ev_via_bat[e][t]) * INTERVAL_H
|
||||
for t in range(T)
|
||||
if _connected(e, t)
|
||||
)
|
||||
== float(sess.energy_needed_wh) - unmet + opp
|
||||
), f"ev_total_{e}"
|
||||
|
||||
# TUV look-ahead (převzato z v1 — komfortní constraint, ne heuristika)
|
||||
rated_hp = float(heat_pump.rated_heating_power_w)
|
||||
if tuv_delta_stats and rated_hp > 0 and getattr(heat_pump, "tuv_min_temp_c", None):
|
||||
@@ -322,6 +342,8 @@ def solve_dispatch_v2(
|
||||
)
|
||||
if ev_unmet:
|
||||
extras += pulp.lpSum(u * V2_EV_UNMET_CZK_KWH / 1000.0 for u in ev_unmet)
|
||||
if ev_opp:
|
||||
extras -= pulp.lpSum(o / 1000.0 * val for o, val in ev_opp if val > 0)
|
||||
nb_terms = [
|
||||
nb_slack[t] / 1000.0 * max(0.0, float(slots[t].buy_price))
|
||||
for t in range(T)
|
||||
@@ -453,6 +475,7 @@ def solve_dispatch_v2(
|
||||
"extras_czk": round(float(pulp.value(extras)), 3) if not isinstance(extras, float) else 0.0,
|
||||
"terminal_value_czk": round(terminal * _val(soc[T - 1]), 3),
|
||||
"ev_unmet_wh": [round(_val(u), 1) for u in ev_unmet],
|
||||
"ev_opp_wh": [round(_val(o), 1) for o, _v in ev_opp],
|
||||
},
|
||||
"solver_duration_ms": duration_ms,
|
||||
"solver_status": status_str,
|
||||
|
||||
Reference in New Issue
Block a user