Initial commit
Made-with: Cursor
This commit is contained in:
180
docs/04-modules/forecast.md
Normal file
180
docs/04-modules/forecast.md
Normal file
@@ -0,0 +1,180 @@
|
||||
# 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 7–16 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í):
|
||||
|
||||
```python
|
||||
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ý den 14:30 CET | Po importu cen, před plánováním |
|
||||
| Scheduled (cron) | každý den 06:00 CET | Aktualizace predikce na dnešní den |
|
||||
| Před plánováním | automaticky | Plánovač zkontroluje čerstvost, spustí pokud starší než 2h |
|
||||
| Manual trigger | na vyžádání | `POST /admin/run-forecast?site_id=1&date=YYYY-MM-DD` |
|
||||
|
||||
---
|
||||
|
||||
## Logika běhu predikce
|
||||
|
||||
```python
|
||||
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
|
||||
|
||||
---
|
||||
|
||||
## Konfigurace (env proměnné)
|
||||
|
||||
```env
|
||||
OPEN_METEO_API_URL=https://api.open-meteo.com/v1/forecast
|
||||
FORECAST_HORIZON_DAYS=3
|
||||
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
|
||||
Reference in New Issue
Block a user