Files
ems/db/routines/R__005_fn_cop_estimate.sql
2026-04-19 20:15:46 +02:00

138 lines
4.9 KiB
PL/PgSQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- =============================================================
-- R__005_fn_cop_estimate.sql
-- EMS Platform odhad COP tepelného čerpadla dle venkovní teploty
-- Repeatable migration
-- =============================================================
CREATE OR REPLACE FUNCTION ems.fn_cop_estimate(
p_heat_pump_id INT,
p_outdoor_temp_c NUMERIC
)
RETURNS NUMERIC(4,2)
LANGUAGE plpgsql
STABLE
AS $$
DECLARE
v_cop_rated NUMERIC;
v_cop_ref_temp NUMERIC;
v_cop_estimated NUMERIC;
BEGIN
-- Načíst referenční COP a teplotu z konfigurace čerpadla
SELECT cop_rated, cop_temp_reference_c
INTO v_cop_rated, v_cop_ref_temp
FROM ems.asset_heat_pump
WHERE id = p_heat_pump_id;
IF v_cop_rated IS NULL OR v_cop_ref_temp IS NULL THEN
-- Fallback: obecný odhad pro vzduch-voda TČ bez konfigurace
-- Zdroj: přibližná lineární závislost COP na venkovní teplotě
-- COP ≈ 2.0 při -10°C, COP ≈ 4.5 při +15°C
v_cop_estimated := 2.0 + (p_outdoor_temp_c + 10.0) * (4.5 - 2.0) / 25.0;
ELSE
-- Lineární interpolace od referenčního bodu
-- COP klesá přibližně o 0.10 na každý stupeň poklesu venkovní teploty
-- Toto je zjednodušený model zpřesnit dle skutečných dat z tepelky
v_cop_estimated := v_cop_rated + (p_outdoor_temp_c - v_cop_ref_temp) * 0.10;
END IF;
-- Omezit na rozumné hodnoty (COP vzduch-voda reálně 1.56.0)
v_cop_estimated := GREATEST(1.5, LEAST(6.0, v_cop_estimated));
RETURN ROUND(v_cop_estimated, 2);
END;
$$;
COMMENT ON FUNCTION ems.fn_cop_estimate(INT, NUMERIC) IS
'Odhadne COP tepelného čerpadla pro danou venkovní teplotu.
Používá lineární model od referenčního bodu (cop_rated při cop_temp_reference_c).
Výstup slouží k rozhodnutí zda je výhodné spustit TČ v daném intervalu.
Přesnost modelu zlepšit kalibrací na historická data (cop_actual z telemetrie).
Výsledek omezen na rozsah 1.56.0.';
-- ------------------------------------------------------------
CREATE OR REPLACE FUNCTION ems.fn_heat_pump_cost_per_kwh_heat(
p_heat_pump_id INT,
p_outdoor_temp_c NUMERIC,
p_buy_price_czk_kwh NUMERIC
)
RETURNS NUMERIC(8,4)
LANGUAGE sql
STABLE
AS $$
-- Cena za 1 kWh tepla = cena elektřiny / COP
-- Čím vyšší COP, tím levnější teplo
SELECT ROUND(
p_buy_price_czk_kwh / NULLIF(ems.fn_cop_estimate(p_heat_pump_id, p_outdoor_temp_c), 0),
4
);
$$;
COMMENT ON FUNCTION ems.fn_heat_pump_cost_per_kwh_heat(INT, NUMERIC, NUMERIC) IS
'Vypočte efektivní cenu za 1 kWh dodaného tepla v Kč.
Vstup: ID tepelného čerpadla, venkovní teplota, nákupní cena elektřiny.
Výstup slouží k porovnání výhodnosti ohřevu v různých časových intervalech.
Nižší hodnota = výhodnější čas pro provoz TČ.';
-- ------------------------------------------------------------
CREATE OR REPLACE FUNCTION ems.fn_heat_pump_should_run(
p_heat_pump_id INT,
p_interval_start TIMESTAMPTZ,
p_outdoor_temp_c NUMERIC,
p_tuv_tank_temp_c NUMERIC,
p_buy_price_czk_kwh NUMERIC,
p_max_cost_threshold NUMERIC DEFAULT 3.0 -- Kč/kWh tepla maximální akceptovatelná cena
)
RETURNS BOOLEAN
LANGUAGE plpgsql
STABLE
AS $$
DECLARE
v_hp ems.asset_heat_pump%ROWTYPE;
v_cost_per_kwh NUMERIC;
v_override BOOLEAN;
BEGIN
SELECT * INTO v_hp FROM ems.asset_heat_pump WHERE id = p_heat_pump_id;
-- Kontrola override (blokování TČ)
SELECT EXISTS(
SELECT 1 FROM ems.site_override
WHERE site_id = v_hp.site_id
AND override_type = 'block_heat_pump'
AND valid_from <= p_interval_start
AND (valid_to IS NULL OR valid_to > p_interval_start)
) INTO v_override;
IF v_override THEN
RETURN false;
END IF;
-- Povinný ohřev: teplota pod minimem
IF p_tuv_tank_temp_c IS NOT NULL AND p_tuv_tank_temp_c < v_hp.tuv_min_temp_c THEN
RETURN true;
END IF;
-- Zásobník je plný
IF p_tuv_tank_temp_c IS NOT NULL AND p_tuv_tank_temp_c >= v_hp.tuv_max_temp_c THEN
RETURN false;
END IF;
-- Ekonomické rozhodnutí: spustit pokud cena tepla je pod prahem
v_cost_per_kwh := ems.fn_heat_pump_cost_per_kwh_heat(
p_heat_pump_id, p_outdoor_temp_c, p_buy_price_czk_kwh
);
RETURN v_cost_per_kwh <= p_max_cost_threshold;
END;
$$;
COMMENT ON FUNCTION ems.fn_heat_pump_should_run(INT, TIMESTAMPTZ, NUMERIC, NUMERIC, NUMERIC, NUMERIC) IS
'Rozhodne zda má tepelné čerpadlo v daném intervalu běžet.
Logika priorit:
1. Pokud existuje override block_heat_pump → false.
2. Pokud teplota zásobníku pod tuv_min_temp_c → true (povinný ohřev).
3. Pokud zásobník nad tuv_max_temp_c → false.
4. Jinak ekonomické rozhodnutí: spustit pokud cena tepla ≤ p_max_cost_threshold Kč/kWh.
Výhodné časy jsou přes poledne v chladných měsících (vyšší venkovní teplota = lepší COP).';