kalibrace per pole
This commit is contained in:
@@ -12,7 +12,8 @@ BEGIN
|
||||
site_id, pv_array_id, interval_start, run_id,
|
||||
forecast_power_w, forecast_created_at, lead_time_hours,
|
||||
actual_power_w, actual_filled_at,
|
||||
error_w, error_pct
|
||||
error_w, error_pct,
|
||||
learning_eligible, learning_exclude_reason
|
||||
)
|
||||
SELECT
|
||||
fpr.site_id,
|
||||
@@ -25,10 +26,17 @@ BEGIN
|
||||
EXTRACT(EPOCH FROM (fpi.interval_start - fpr.created_at))
|
||||
/ 3600.0, 2
|
||||
) AS lead_time_hours,
|
||||
slot.avg_actual_w::INT AS actual_power_w,
|
||||
now() AS actual_filled_at,
|
||||
fpi.power_w - COALESCE(slot.avg_actual_w::INT, 0) AS error_w,
|
||||
CASE
|
||||
WHEN v.is_curtailed_learning_slot THEN NULL
|
||||
ELSE slot.avg_actual_w::INT
|
||||
END AS actual_power_w,
|
||||
now() AS actual_filled_at,
|
||||
CASE
|
||||
WHEN v.is_curtailed_learning_slot THEN NULL
|
||||
ELSE fpi.power_w - COALESCE(slot.avg_actual_w::INT, 0)
|
||||
END AS error_w,
|
||||
CASE
|
||||
WHEN v.is_curtailed_learning_slot THEN NULL
|
||||
WHEN slot.avg_actual_w IS NOT NULL
|
||||
AND slot.avg_actual_w > 0
|
||||
THEN ROUND(
|
||||
@@ -37,10 +45,62 @@ BEGIN
|
||||
4
|
||||
)
|
||||
ELSE NULL
|
||||
END AS error_pct
|
||||
END AS error_pct,
|
||||
v.learning_eligible,
|
||||
v.learning_exclude_reason
|
||||
FROM ems.forecast_pv_interval fpi
|
||||
JOIN ems.forecast_pv_run fpr ON fpr.id = fpi.run_id
|
||||
JOIN ems.asset_pv_array pa ON pa.id = fpr.pv_array_id
|
||||
LEFT JOIN ems.site_pv_forecast_calibration cal
|
||||
ON cal.site_id = fpr.site_id
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT
|
||||
coalesce(cal.delta_learn_min_ts, timestamptz '2026-04-11T22:00:00Z') AS delta_learn_min_ts,
|
||||
cal.pv_curtailment_policy_effective_from AS policy_from
|
||||
) cal_eff ON true
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT pi.pv_a_curtailed_w, pi.deye_gen_cutoff_enabled
|
||||
FROM ems.planning_interval pi
|
||||
JOIN ems.planning_run pr ON pr.id = pi.run_id
|
||||
WHERE pr.site_id = fpr.site_id
|
||||
AND pr.status = 'active'
|
||||
AND pi.interval_start = fpi.interval_start
|
||||
LIMIT 1
|
||||
) ap ON true
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT
|
||||
(fpi.interval_start < cal_eff.delta_learn_min_ts) AS before_learn_cutoff,
|
||||
(
|
||||
cal_eff.policy_from IS NOT NULL
|
||||
AND fpi.interval_start >= cal_eff.policy_from
|
||||
AND (
|
||||
coalesce(ap.pv_a_curtailed_w, 0) > 50
|
||||
OR coalesce(ap.deye_gen_cutoff_enabled, false) IS TRUE
|
||||
OR EXISTS (
|
||||
SELECT 1
|
||||
FROM ems.cutoff_switch_log l
|
||||
WHERE l.site_id = fpr.site_id
|
||||
AND l.switched_at >= fpi.interval_start
|
||||
AND l.switched_at < fpi.interval_start + INTERVAL '15 minutes'
|
||||
AND l.new_state IS FALSE
|
||||
)
|
||||
)
|
||||
) AS is_curtailed_learning_slot
|
||||
) flags ON true
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT
|
||||
CASE
|
||||
WHEN flags.before_learn_cutoff THEN false
|
||||
WHEN flags.is_curtailed_learning_slot THEN false
|
||||
ELSE true
|
||||
END AS learning_eligible,
|
||||
CASE
|
||||
WHEN flags.before_learn_cutoff THEN 'before_delta_learn_min'
|
||||
WHEN flags.is_curtailed_learning_slot THEN 'curtailment_or_export_cutoff'
|
||||
ELSE NULL
|
||||
END AS learning_exclude_reason,
|
||||
flags.is_curtailed_learning_slot
|
||||
) v ON true
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT AVG(
|
||||
CASE
|
||||
@@ -58,10 +118,12 @@ BEGIN
|
||||
AND fpi.interval_start < now() - INTERVAL '15 minutes'
|
||||
AND fpi.interval_start >= now() - make_interval(hours => p_lookback_hours)
|
||||
ON CONFLICT (run_id, interval_start) DO UPDATE SET
|
||||
actual_power_w = EXCLUDED.actual_power_w,
|
||||
actual_filled_at = EXCLUDED.actual_filled_at,
|
||||
error_w = EXCLUDED.error_w,
|
||||
error_pct = EXCLUDED.error_pct;
|
||||
actual_power_w = EXCLUDED.actual_power_w,
|
||||
actual_filled_at = EXCLUDED.actual_filled_at,
|
||||
error_w = EXCLUDED.error_w,
|
||||
error_pct = EXCLUDED.error_pct,
|
||||
learning_eligible = EXCLUDED.learning_eligible,
|
||||
learning_exclude_reason = EXCLUDED.learning_exclude_reason;
|
||||
|
||||
GET DIAGNOSTICS v_count = ROW_COUNT;
|
||||
RETURN v_count;
|
||||
@@ -70,6 +132,8 @@ $$;
|
||||
|
||||
COMMENT ON FUNCTION ems.fn_fill_forecast_accuracy(INT, INT) IS
|
||||
'Doplní skutečné hodnoty výroby do forecast_accuracy z telemetrie.
|
||||
learning_eligible / learning_exclude_reason: před delta_learn_min_ts (kalibrace site) se nepočítá do učení delty;
|
||||
po pv_curtailment_policy_effective_from sloty s curtailment / gen cutoff / cutoff_switch_log (export off) mají NULL actual a jsou vyloučeny z učení.
|
||||
Volat každých 15 minut (spolu s audit_filler) pro inkrementální plnění.
|
||||
p_lookback_hours: kolik hodin zpět zpracovat (default 48h pro catch-up).
|
||||
Pro první backfill: SELECT ems.fn_fill_forecast_accuracy(2, 8760) -- 1 rok';
|
||||
|
||||
Reference in New Issue
Block a user