fix cyklovani
This commit is contained in:
@@ -57,8 +57,6 @@ declare
|
||||
v_n_pm int;
|
||||
v_chg_am_wh numeric;
|
||||
v_chg_pm_wh numeric;
|
||||
v_dis_am_wh numeric;
|
||||
v_dis_pm_wh numeric;
|
||||
v_reserve_wh numeric;
|
||||
v_daytime_en boolean;
|
||||
v_night_buf_pct numeric;
|
||||
@@ -229,24 +227,18 @@ begin
|
||||
v_per_slot_discharge_wh := v_max_discharge_w * v_discharge_eff * 0.25;
|
||||
v_energy_to_fill := v_soc_max_wh - p_current_soc_wh;
|
||||
v_exportable := v_soc_max_wh - v_min_soc_wh;
|
||||
v_grid_target_wh := v_energy_to_fill * v_charge_buf;
|
||||
v_grid_target_wh := greatest(v_energy_to_fill, 0) * v_charge_buf;
|
||||
v_discharge_target_wh := v_exportable * v_discharge_buf;
|
||||
|
||||
-- Rozpočet na půl dne (Europe/Prague): 00:00–12:00 vs 12:00–24:00; chybějící segment dostane celý budget.
|
||||
-- Nabíjecí rozpočet dál dělíme 50/50 (kvůli rozprostření v rámci dne), ale exportní vybíjení volíme globálně podle sell_price.
|
||||
-- AM/PM rozpočet grid charging (Europe/Prague 00–12 vs 12–24).
|
||||
-- Chybějící segment dostane celý budget.
|
||||
select
|
||||
coalesce(
|
||||
count(*) filter (
|
||||
where extract(hour from wk.interval_start at time zone 'Europe/Prague') < 12
|
||||
),
|
||||
0
|
||||
)::int,
|
||||
coalesce(
|
||||
count(*) filter (
|
||||
where extract(hour from wk.interval_start at time zone 'Europe/Prague') >= 12
|
||||
),
|
||||
0
|
||||
)::int
|
||||
coalesce(count(*) filter (
|
||||
where extract(hour from wk.interval_start at time zone 'Europe/Prague') < 12
|
||||
), 0)::int,
|
||||
coalesce(count(*) filter (
|
||||
where extract(hour from wk.interval_start at time zone 'Europe/Prague') >= 12
|
||||
), 0)::int
|
||||
into v_n_am, v_n_pm
|
||||
from _ems_plan_slot_wk wk;
|
||||
|
||||
@@ -261,35 +253,65 @@ begin
|
||||
v_chg_pm_wh := v_grid_target_wh - v_chg_am_wh;
|
||||
end if;
|
||||
|
||||
-- charge mask (sloupce temp tabulky kvalifikujeme: RETURNS TABLE dělá PL proměnné stejných jmen)
|
||||
-- charge mask: dvě nezávislé vrstvy
|
||||
--
|
||||
-- A) PV-surplus sloty (pv_surplus_w > 0): ranking dle sell_price ASC.
|
||||
-- Nejlevnější PV-surplus sloty vybereme, dokud kumulativní
|
||||
-- PV surplus nepokryje charge target (energy_to_fill × charge_buf).
|
||||
-- Zbylé PV-surplus sloty mají allow_charge = false → PV jde do sítě.
|
||||
-- Toto je hlavní mechanismus proti mikro-cyklování z PV:
|
||||
-- v drahých slotech se PV prodává přímo, nabíjení jen v levných.
|
||||
--
|
||||
-- B) Non-PV sloty (pv_surplus_w <= 0): AM/PM budget, OTE-first.
|
||||
-- Nejlevnější non-PV sloty (dle buy_price) s prioritou OTE cen
|
||||
-- před predikovanými (is_predicted_price::int ASC). AM a PM mají
|
||||
-- oddělený rozpočet (50/50), aby solver nekoncentroval veškeré
|
||||
-- nabíjení/vybíjení do jediné půlky dne (double-cycle ochrana).
|
||||
-- OTE-first: levné OTE sloty aktuálního dne nesmí být vytlačeny
|
||||
-- levnějšími predikovanými cenami vzdálených dní (den 3–4 z 96h).
|
||||
if v_charge_buf <= 0 then
|
||||
update _ems_plan_slot_wk wk set allow_charge = true;
|
||||
elsif v_energy_to_fill <= 0 then
|
||||
-- Pokud rolling replan startuje s baterií plnou, nechceme zablokovat budoucí nabíjení po vybití.
|
||||
-- Povolit alespoň nabíjení v PV surplus slotech, aby solver mohl vytvořit headroom a pak ho znovu zaplnit z FVE.
|
||||
update _ems_plan_slot_wk wk set allow_charge = (wk.pv_surplus_w > 0);
|
||||
update _ems_plan_slot_wk wk set allow_charge = true;
|
||||
else
|
||||
update _ems_plan_slot_wk wk set allow_charge = (wk.pv_surplus_w > 0);
|
||||
update _ems_plan_slot_wk wk set allow_charge = false;
|
||||
|
||||
-- A) PV-surplus: cheapest sell_price first
|
||||
v_cum := 0;
|
||||
for r_slot in
|
||||
select wk.slot_ord, wk.pv_surplus_w
|
||||
from _ems_plan_slot_wk wk
|
||||
where wk.pv_surplus_w > 0
|
||||
order by wk.sell_price, wk.slot_ord
|
||||
loop
|
||||
exit when v_cum >= v_grid_target_wh;
|
||||
update _ems_plan_slot_wk wk set allow_charge = true where wk.slot_ord = r_slot.slot_ord;
|
||||
v_cum := v_cum + least(r_slot.pv_surplus_w, v_max_charge_w) * v_charge_eff * 0.25;
|
||||
end loop;
|
||||
|
||||
-- B) Non-PV AM: OTE-first, then predicted, ordered by buy_price
|
||||
v_cum := 0;
|
||||
for r_slot in
|
||||
select wk.slot_ord
|
||||
from _ems_plan_slot_wk wk
|
||||
where wk.pv_surplus_w <= 0
|
||||
and extract(hour from wk.interval_start at time zone 'Europe/Prague') < 12
|
||||
order by wk.buy_price, wk.slot_ord
|
||||
order by wk.is_predicted_price::int, wk.buy_price, wk.slot_ord
|
||||
loop
|
||||
exit when v_cum >= v_chg_am_wh;
|
||||
exit when v_per_slot_charge_wh <= 0;
|
||||
update _ems_plan_slot_wk wk set allow_charge = true where wk.slot_ord = r_slot.slot_ord;
|
||||
v_cum := v_cum + v_per_slot_charge_wh;
|
||||
end loop;
|
||||
|
||||
-- B) Non-PV PM: OTE-first, then predicted, ordered by buy_price
|
||||
v_cum := 0;
|
||||
for r_slot in
|
||||
select wk.slot_ord
|
||||
from _ems_plan_slot_wk wk
|
||||
where wk.pv_surplus_w <= 0
|
||||
and extract(hour from wk.interval_start at time zone 'Europe/Prague') >= 12
|
||||
order by wk.buy_price, wk.slot_ord
|
||||
order by wk.is_predicted_price::int, wk.buy_price, wk.slot_ord
|
||||
loop
|
||||
exit when v_cum >= v_chg_pm_wh;
|
||||
exit when v_per_slot_charge_wh <= 0;
|
||||
@@ -409,7 +431,9 @@ $fn$;
|
||||
|
||||
comment on function ems.fn_load_planning_slots_full is
|
||||
'15min sloty s cenami, forecastem, baseline a maskami proti mikro-cyklu (charge/discharge-export). '
|
||||
'Masky charge/discharge-export se berou zvlášť pro 00–12 a 12–24 Europe/Prague (polovina budgetu na segment). '
|
||||
'Charge mask: PV-surplus sloty rankované dle sell_price ASC – nejlevnější pokrývají charge target, zbytek → PV do sítě; '
|
||||
'non-PV sloty dle buy_price s AM/PM rozpočtem 50/50 a OTE-first prioritou (is_predicted_price::int ASC). '
|
||||
'Discharge-export mask: nejdražší sell_price sloty globálně. '
|
||||
'Strop SoC pro výpočet energie k dobití: coalesce(planner_max_soc_percent, max_soc_percent). '
|
||||
'Denní safety vstupy: night_baseload_* (20:00–06:00 Europe/Prague), safety_soc_target_wh (6–19), '
|
||||
'lookahead max buy/sell pro měkké LP penalizace.';
|
||||
|
||||
Reference in New Issue
Block a user