tune forecast correction parametersw
This commit is contained in:
@@ -3,12 +3,17 @@
|
||||
-- (aditivní korekce: corrected = max(0, forecast - delta[slot]))
|
||||
-- ============================================================
|
||||
|
||||
drop function if exists ems.fn_pv_forecast_delta_profile;
|
||||
|
||||
create or replace function ems.fn_pv_forecast_delta_profile(
|
||||
p_site_id int,
|
||||
p_data_from timestamptz,
|
||||
p_data_to timestamptz default now(),
|
||||
p_half_life_days numeric default 14,
|
||||
p_threshold_w int default 150
|
||||
p_threshold_w int default 150,
|
||||
p_top_n_days int default null,
|
||||
p_non_top_day_factor numeric default 0.02,
|
||||
p_day_weight_gamma numeric default 1.0
|
||||
)
|
||||
returns jsonb
|
||||
language sql
|
||||
@@ -143,22 +148,45 @@ as $fn$
|
||||
left join day_jump dj on dj.day_local = de.day_local
|
||||
left join day_med dm on dm.day_local = de.day_local
|
||||
),
|
||||
-- Volitelně: jen top N kalendářních dní podle (w_energy * w_smooth); zbytek ztlumit (bez hardcodu data).
|
||||
day_rank as (
|
||||
select
|
||||
ds.day_local,
|
||||
row_number() over (
|
||||
order by
|
||||
(coalesce(ds.w_energy, 0.35) * coalesce(ds.w_smooth, 0.35)) desc,
|
||||
ds.day_local desc
|
||||
) as rn
|
||||
from day_stats ds
|
||||
),
|
||||
filtered as (
|
||||
select
|
||||
s.slot_of_day,
|
||||
(s.forecast_total_w - s.actual_total_w) as error_w,
|
||||
exp(-s.age_days / nullif((select half_life_days from bounds), 0))
|
||||
* (
|
||||
case
|
||||
when p_top_n_days is null then 1::numeric
|
||||
when p_top_n_days < 1 then 1::numeric
|
||||
when dr.rn <= p_top_n_days then 1::numeric
|
||||
else greatest(0::numeric, least(1::numeric, coalesce(p_non_top_day_factor, 0.02)))
|
||||
end
|
||||
)
|
||||
* (
|
||||
0.05
|
||||
+ 0.95
|
||||
* greatest(
|
||||
0.0,
|
||||
least(1.0, coalesce(ds.w_energy, 0.35) * coalesce(ds.w_smooth, 0.35))
|
||||
* power(
|
||||
greatest(
|
||||
0.0,
|
||||
least(1.0, coalesce(ds.w_energy, 0.35) * coalesce(ds.w_smooth, 0.35))
|
||||
),
|
||||
greatest(0.25, least(coalesce(p_day_weight_gamma, 1.0), 8.0))
|
||||
)
|
||||
) as w
|
||||
from slots s
|
||||
cross join bounds b
|
||||
left join day_stats ds on ds.day_local = s.day_local
|
||||
left join day_rank dr on dr.day_local = s.day_local
|
||||
where s.slot_of_day between 0 and 95
|
||||
and (s.actual_total_w > b.threshold_w or s.forecast_total_w > b.threshold_w)
|
||||
),
|
||||
@@ -200,5 +228,5 @@ as $fn$
|
||||
left join agg a on a.slot_of_day = sp.slot_of_day;
|
||||
$fn$;
|
||||
|
||||
comment on function ems.fn_pv_forecast_delta_profile(int, timestamptz, timestamptz, numeric, int) is
|
||||
'Aditivní delta profil chyby PV forecastu po 15min slotu dne (96 slotů). Zdroj: forecast_accuracy, vážení exp(-age/half_life_days) * day_weight (preferuje „clear-ish“ dny: vyšší denní energie vs median v okně + nižší median skoků výkonu mezi 15min v daylight bandu). Vrací JSON {deltas:[{slot_of_day, delta_w, sample_count}], ...}. Interní minimální cutoff dat (2026-04-11 Europe/Prague) brání učení z nekonzistentní historie před kompletním plněním actual.';
|
||||
comment on function ems.fn_pv_forecast_delta_profile is
|
||||
'Aditivní delta profil chyby PV forecastu po 15min slotu dne (96 slotů). Zdroj: forecast_accuracy, vážení exp(-age/half_life_days) * day_weight (clear-ish dny) * volitelně top_n_days (jen N nejlepších kalendářních dní podle w_energy*w_smooth, ostatní ztlumené) * power(day_weight, day_weight_gamma). Vrací JSON {deltas:[{slot_of_day, delta_w, sample_count}], ...}. Cutoff dat od 2026-04-11 Europe/Prague.';
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
-- corrected = max(0, forecast - delta_profile[slot_of_day])
|
||||
-- ============================================================
|
||||
|
||||
drop function if exists ems.fn_forecast_pv_slots_range_corrected;
|
||||
|
||||
create or replace function ems.fn_forecast_pv_slots_range_corrected(
|
||||
p_site_id int,
|
||||
p_from timestamptz,
|
||||
@@ -10,7 +12,10 @@ create or replace function ems.fn_forecast_pv_slots_range_corrected(
|
||||
p_delta_data_from timestamptz,
|
||||
p_delta_data_to timestamptz default now(),
|
||||
p_half_life_days numeric default 14,
|
||||
p_threshold_w int default 150
|
||||
p_threshold_w int default 150,
|
||||
p_top_n_days int default null,
|
||||
p_non_top_day_factor numeric default 0.02,
|
||||
p_day_weight_gamma numeric default 1.0
|
||||
)
|
||||
returns jsonb
|
||||
language sql
|
||||
@@ -67,7 +72,10 @@ as $fn$
|
||||
p_delta_data_from,
|
||||
p_delta_data_to,
|
||||
p_half_life_days,
|
||||
p_threshold_w
|
||||
p_threshold_w,
|
||||
p_top_n_days,
|
||||
p_non_top_day_factor,
|
||||
p_day_weight_gamma
|
||||
) as j
|
||||
),
|
||||
deltas as (
|
||||
@@ -119,5 +127,5 @@ as $fn$
|
||||
left join fc on fc.interval_start = s.interval_start;
|
||||
$fn$;
|
||||
|
||||
comment on function ems.fn_forecast_pv_slots_range_corrected(int, timestamptz, timestamptz, timestamptz, timestamptz, numeric, int) is
|
||||
'JSON pole {interval_start, pv_forecast_total_w, pv_forecast_corrected_w, slot_of_day} po 15 min pro [p_from, p_to). Korekce je aditivní delta profil z fn_pv_forecast_delta_profile. Horizont je omezený na max. 60 dní.';
|
||||
comment on function ems.fn_forecast_pv_slots_range_corrected is
|
||||
'JSON pole {interval_start, pv_forecast_total_w, pv_forecast_corrected_w, slot_of_day} po 15 min pro [p_from, p_to). Korekce je aditivní delta profil z fn_pv_forecast_delta_profile (top_n_days / non_top_day_factor / day_weight_gamma). Horizont je omezený na max. 60 dní.';
|
||||
|
||||
Reference in New Issue
Block a user