Files
ems/docs/04-modules/forecast.md
Dusan Vojacek 9f4126946d second version
2026-04-03 14:23:16 +02:00

7.4 KiB
Raw Blame History

Modul: Forecast (Predikce výroby FVE)

Co modul dělá

  • Stahuje meteorologická data (irradiance, teplota) pro každé FVE pole zvlášť
  • Vypočítává predikovaný výkon v 15min intervalech
  • Ukládá výsledek per pv_array_id + run_id
  • Predikce se spouští denně a před každým plánovacím během

FVE pole na první instalaci (home-01)

Pole Výkon Azimut Sklon Střídač Řízení
A 10 kWp TBD TBD Deye 20kW řídíme
B 10 kWp TBD TBD Ongridový autonomní, nepredikujeme odděleně

Předpoklad: Pole B (ongridový) je zapojeno do GEN portu Deye. Jeho výkon se projeví v pv_power_w telemetrie jako součást celkového výkonu. Pro plánování modelujeme jen pole A. Pole B bereme jako šum / bonus který se projeví v auditu.

Azimuty a sklony je nutné doplnit při konfiguraci lokality do asset_pv_array.


Zdroj meteorologických dat

Primární: Open-Meteo (open-meteo.com)

  • Zdarma pro nekomerční použití, API bez registrace
  • Poskytuje GHI (Global Horizontal Irradiance), DNI, teplotu, oblačnost
  • Historická data + forecast na 716 dní dopředu
  • 15min granularita nativně ✓

Endpoint:

GET https://api.open-meteo.com/v1/forecast
  ?latitude={lat}
  &longitude={lon}
  &hourly=shortwave_radiation,temperature_2m
  &minutely_15=shortwave_radiation,temperature_2m
  &timezone=Europe/Prague
  &forecast_days=3

Záložní / budoucí: Solcast

  • Přesnější pro FVE, ale placený
  • Podporuje per-array predikci s azimutem a sklonem přímo
  • Zatím neimplementujeme, architektura to umožňuje přes forecast_source

Výpočet výkonu z irradiance

Jednoduchý fyzikální model (dostatečný pro plánování):

def calculate_pv_power(
    irradiance_wm2: float,      # GHI ze weather service
    temp_c: float,
    nominal_power_wp: int,
    azimuth_deg: float,
    tilt_deg: float,
    shading_factor: float = 1.0,
    temp_coeff: float = -0.004  # typicky -0.4%/°C pro křemík
) -> int:
    # 1. Korekce na teplotu panelu
    panel_temp = temp_c + 25    # zjednodušený NOCT model
    temp_correction = 1 + temp_coeff * (panel_temp - 25)

    # 2. Korekce na azimut a sklon (zjednodušená, bez přesného GHI→POA)
    # Přesnější model: pvlib knihovna (doporučeno pro produkci)
    orientation_factor = cos_angle_of_incidence(azimuth_deg, tilt_deg)

    # 3. Výsledný výkon
    power_w = (irradiance_wm2 / 1000) * nominal_power_wp * temp_correction * orientation_factor * shading_factor

    return max(0, int(power_w))

Doporučení pro implementaci: Použít knihovnu pvlib (Python) pro přesný POA irradiance výpočet z GHI + azimut + sklon. Je to standardní nástroj, dobře dokumentovaný.


Kdo spouští predikci

Python service: forecast_service

Kdy se spouští

Trigger Čas Popis
Scheduled (cron) každé 2 hodiny v :05 Průběžný refresh forecastu pro všechny aktivní site
Manual trigger na vyžádání POST /api/v1/sites/{site_id}/forecast/run

Implementované provozní změny (2026-03)

  • Forecast horizont je konfigurovatelný přes open_meteo_forecast_days.
  • Runtime guard: hodnota se clampuje do rozmezí 2..16.
  • Default je 7 dní.
  • Endpoint GET /api/v1/sites/{site_id}/forecast/pv?date=YYYY-MM-DD vrací vždy poslední ok run per (interval_start, pv_array_id) (DISTINCT ON), takže UI nevidí duplikáty z historických běhů.

Logika běhu predikce

def run_forecast(site_id: int, horizon_days: int = 2):
    site = db.get_site(site_id)
    arrays = db.get_pv_arrays(site_id, controllable=True)

    for array in arrays:
        # 1. Stáhnout meteorologická data
        weather = open_meteo_client.fetch(
            lat=site.lat, lon=site.lon,
            start=today, end=today + horizon_days
        )

        # 2. Vytvořit forecast_pv_run
        run = db.create_forecast_run(
            site_id=site_id,
            pv_array_id=array.id,
            forecast_source="open_meteo",
            horizon_start=today_00,
            horizon_end=today_end + horizon_days
        )

        # 3. Vypočítat a uložit intervaly (15min)
        intervals = []
        for slot in weather.slots_15min:
            power = calculate_pv_power(
                irradiance_wm2=slot.shortwave_radiation,
                temp_c=slot.temperature_2m,
                nominal_power_wp=array.nominal_power_wp,
                azimuth_deg=array.azimuth_deg,
                tilt_deg=array.tilt_deg,
                shading_factor=array.shading_factor
            )
            intervals.append(ForecastInterval(
                run_id=run.id,
                pv_array_id=array.id,
                interval_start=slot.time,
                power_w=power,
                irradiance_wm2=slot.shortwave_radiation,
                temp_c=slot.temperature_2m
            ))

        db.upsert_forecast_intervals(intervals)
        db.update_forecast_run_status(run.id, "ok")

DB struktura

Viz 03-data-model.md:

  • forecast_pv_run každý běh predikce
  • forecast_pv_interval 15min výsledky per pole a běh

Tracking přesnosti forecastu

  • ems.forecast_accuracy pro každý úspěšný forecast_pv_run a každý 15min slot ukládá predikovaný výkon, čas vzniku predikce, lead time (hodiny před začátkem slotu), později doplněnou skutečnost z telemetrie a odchylku (error_w, error_pct). Záznamy se uchovávají trvale (včetně všech historických běhů v forecast_pv_run / forecast_pv_interval ty se nemazají).
  • ems.fn_fill_forecast_accuracy(site_id, lookback_hours) inkrementálně vloží nebo aktualizuje řádky z forecast_pv_interval + run metadata a dopočte actual_power_w jako průměr 1min telemetrie ve slotu (pole B: gen_port_power_w, pole A: pv1_power_w + pv2_power_w). Volat každých 15 minut (např. spolu s audit fillerem); parametr lookback_hours omezuje okno zpětného zpracování (např. 48 h běžně, větší hodnota pro jednorázový backfill).
  • ems.vw_forecast_accuracy_by_lead_time agregace přesnosti podle bucketů lead time (06 h, …, 48 h+); noční sloty s nízkou výrobou (actual_power_w ≤ 100 W) se v metrikách typicky vynechávají.
  • ems.vw_forecast_accuracy_daily denní součty forecast vs actual v kWh (Praha kalendářní den) a relativní odchylka dne.
  • Po 4+ týdnech dat lze statistiky použít pro kalibraci safety_factor (nebo obdobných parametrů) v solveru viz plánovací modul.

Konfigurace (env proměnné)

OPEN_METEO_API_URL=https://api.open-meteo.com/v1/forecast
OPEN_METEO_FORECAST_DAYS=7
FORECAST_MAX_AGE_HOURS=2      # plánovač odmítne starší predikci
FORECAST_RETRY_COUNT=3

Monitoring

  • Alert pokud forecast pro dnešní den + zítřek není k dispozici do 15:00
  • Endpoint GET /health/forecast?site_id=1&date=YYYY-MM-DD → čerstvost a počet intervalů
  • Log každého běhu (délka horizontu, počet intervalů, trvání, zdroj)

Otevřené body

  • Doplnit přesný azimut a sklon obou FVE polí při instalaci
  • Rozhodnout: pvlib pro přesnější POA výpočet vs jednoduchý model doporučujeme pvlib od začátku
  • Pole B (ongridový) zda vůbec modelovat nebo ignorovat v plánu a jen sledovat v auditu
  • Solcast jako alternativa v budoucnu forecast_source to umožňuje bez DB změn