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:
13
db/migration/V094__ev_opportunistic.sql
Normal file
13
db/migration/V094__ev_opportunistic.sql
Normal file
@@ -0,0 +1,13 @@
|
||||
-- Oportunistické EV nabíjení („měkký cíl"): nad tvrdý target smí auto nasát
|
||||
-- přebytky až do 100 %, oceněné hodnotou BUDOUCÍHO ušetřeného nabíjení
|
||||
-- (~1 Kč/kWh — budoucí nabíjení je stejně v levných slotech). Uplatní se
|
||||
-- hlavně při záporných cenách / plné domácí baterce (lepší než curtail);
|
||||
-- běžné ceny ho nezaplatí. 0 = vypnuto. Víkend: páteční malý tvrdý cíl
|
||||
-- + víkendové negativní ceny → auto se doplní samo, bez speciální logiky.
|
||||
|
||||
alter table ems.asset_vehicle
|
||||
add column if not exists opportunistic_value_czk_kwh numeric(6, 3)
|
||||
not null default 1.0;
|
||||
|
||||
comment on column ems.asset_vehicle.opportunistic_value_czk_kwh is
|
||||
'v2: hodnota kWh nabité NAD target session (do 100 %) = ušetřené budoucí nabíjení. Solver ji zaplatí jen při velmi levné/záporné energii. 0 = vypnuto.';
|
||||
@@ -191,7 +191,11 @@ begin
|
||||
- es.soc_at_connect_pct::numeric) / 100.0
|
||||
* (v.battery_capacity_kwh * 1000)
|
||||
- coalesce(es.energy_delivered_wh, 0)::numeric
|
||||
) <= 0 then null::jsonb
|
||||
) <= 0
|
||||
and (
|
||||
coalesce(v.opportunistic_value_czk_kwh, 0) <= 0
|
||||
or (100 - coalesce(es.target_soc_pct, v.default_target_soc_pct)) <= 0
|
||||
) then null::jsonb
|
||||
else jsonb_build_object(
|
||||
'target_deadline', es.target_deadline,
|
||||
'energy_needed_wh', greatest(
|
||||
@@ -200,7 +204,16 @@ begin
|
||||
- es.soc_at_connect_pct::numeric) / 100.0
|
||||
* (v.battery_capacity_kwh * 1000)
|
||||
- coalesce(es.energy_delivered_wh, 0)::numeric
|
||||
)
|
||||
),
|
||||
'headroom_wh', case
|
||||
when coalesce(v.opportunistic_value_czk_kwh, 0) > 0 then greatest(
|
||||
0,
|
||||
(100 - coalesce(es.target_soc_pct, v.default_target_soc_pct))::numeric
|
||||
/ 100.0 * (v.battery_capacity_kwh * 1000)
|
||||
)
|
||||
else 0
|
||||
end,
|
||||
'opportunistic_value_czk_kwh', coalesce(v.opportunistic_value_czk_kwh, 0)
|
||||
)
|
||||
end
|
||||
from ems.ev_session es
|
||||
@@ -223,7 +236,11 @@ begin
|
||||
- es.soc_at_connect_pct::numeric) / 100.0
|
||||
* (v.battery_capacity_kwh * 1000)
|
||||
- coalesce(es.energy_delivered_wh, 0)::numeric
|
||||
) <= 0 then null::jsonb
|
||||
) <= 0
|
||||
and (
|
||||
coalesce(v.opportunistic_value_czk_kwh, 0) <= 0
|
||||
or (100 - coalesce(es.target_soc_pct, v.default_target_soc_pct)) <= 0
|
||||
) then null::jsonb
|
||||
else jsonb_build_object(
|
||||
'target_deadline', es.target_deadline,
|
||||
'energy_needed_wh', greatest(
|
||||
@@ -232,7 +249,16 @@ begin
|
||||
- es.soc_at_connect_pct::numeric) / 100.0
|
||||
* (v.battery_capacity_kwh * 1000)
|
||||
- coalesce(es.energy_delivered_wh, 0)::numeric
|
||||
)
|
||||
),
|
||||
'headroom_wh', case
|
||||
when coalesce(v.opportunistic_value_czk_kwh, 0) > 0 then greatest(
|
||||
0,
|
||||
(100 - coalesce(es.target_soc_pct, v.default_target_soc_pct))::numeric
|
||||
/ 100.0 * (v.battery_capacity_kwh * 1000)
|
||||
)
|
||||
else 0
|
||||
end,
|
||||
'opportunistic_value_czk_kwh', coalesce(v.opportunistic_value_czk_kwh, 0)
|
||||
)
|
||||
end
|
||||
from ems.ev_session es
|
||||
|
||||
Reference in New Issue
Block a user