Docs: DWD-Regen-Vorhersage-Pipeline gescoppt (Datenformat verifiziert)

DWD RV (composite/rv, kostenlos, alle 5 Min, 25 Frames 0-120min). Format
verifiziert: 194-Byte-ASCII-Header + 1200×1100 uint16 LE, Wert=&0x0FFF×0.01mm,
&0x2000=kein-Daten (PoC: Decode trivial, kein wradlib nötig). Pipeline:
fetch→decode→kolorieren→reprojizieren(DE1200→3857)→Kacheln→PMTiles/Cron 5min;
Frontend hängt Forecast-Frames rechts von 'jetzt' in die Timeline. Knackpunkt:
Georeferenzierung (PoC nötig).
This commit is contained in:
rene 2026-06-05 20:53:51 +02:00
parent ac187dc740
commit 72ee339860

View file

@ -0,0 +1,56 @@
# DWD Regen-Vorhersage (Radar-Nowcast) — Scoping-Plan
**Status:** gescoppt + Datenformat verifiziert (2026-06-05). Umsetzung offen.
**Ziel:** Verlässliche, längere Regen-**Vorhersage** als animiertes Karten-Overlay (bis +2 h) statt RainViewers
unzuverlässigem 30-Min-Nowcast (der oft leer ist). Self-hosted wie die Basemap — passt zur Tile-Server-Philosophie.
## Quelle: DWD RV (Composite RV) — kostenlos, kein API-Key
- `https://opendata.dwd.de/weather/radar/composite/rv/DE1200_RV<YYMMDDHHMM>.tar.bz2`
- **Alle 5 Min** publiziert. Jedes Archiv = ein Vorhersage-Lauf mit **25 Frames** `_000``_120`
(**0 bis +120 Min**, 5-Min-Schritte), je ~2,5 MB unkomprimiert (~1 MB als .tar.bz2).
- **Format (verifiziert):** RADOLAN-Binär. 194-Byte-ASCII-Header bis `ETX (0x03)`, dann **1200×1100 uint16
little-endian** (= 2.640.000 Byte). Header-Felder: `PR E-02` (0,01 mm), `INT 5` (5-Min-Summe),
`GP1200x1100`, `VV<lead>` (Lead-Time). **Wert = `raw & 0x0FFF` × 0,01 mm/5min; `raw & 0x2000` = kein Daten.**
→ Decode trivial, **kein wradlib nötig** (PoC: 1,32 Mio Zellen geparst, Regen korrekt erkannt).
- **Gitter/Projektion:** DE1200 (1 km), polar-stereografisch, fest georeferenziert (Eckkoordinaten dokumentiert;
wradlib `get_radolan_grid` ODER GDAL mit dem bekannten RADOLAN-PROJ-String).
- **Abdeckung:** Deutschland + Randbereiche (reicht etwas nach AT/CH/Nachbarn, aber DE-zentriert).
Voll-AT/CH bräuchte ACG/MeteoSwiss → out of scope.
## Pipeline (Server-seitig, Cron alle 5 Min — analog zum OSM-POI-Job)
1. **Fetch** neueste `DE1200_RV<time>.tar.bz2` (Verzeichnis-Listing → letzte Datei).
2. **Entpacken** → 25 RADOLAN-Grids.
3. **Decode** je Grid → 2D-Niederschlags-Array (eigener ~15-Z.-Parser, PoC-bewiesen).
4. **Kolorieren** → RGBA (transparent bei 0/kein-Regen; Radar-Farbskala wie das aktuelle Overlay).
5. **Reprojektion** DE1200 → EPSG:3857 + **Kacheln z09** (Radar ist grob 1 km → höher zoomen bringt nichts).
Tooling: **GDAL** (gdalwarp + gdal2tiles) oder rasterio/rio-tiler.
6. **Output:** 25 Frame-Tilesets — je eine kleine **PMTiles** pro Lead-Time (`rv_000.pmtiles``rv_120.pmtiles`)
ODER XYZ-PNG. Nur neuesten Lauf behalten (atomarer Swap wie dach.pmtiles). Plus **`rv_manifest.json`**
(Lauf-Zeit, Lead-Times, Tile-URL-Muster).
7. **Ausliefern** von der DS (wie `/tiles`).
## Frontend (bestehende Radar-Timeline erweitern, map.js)
- Manifest laden → DWD-Vorhersage-Frames (0…+120 Min) **rechts von „jetzt"** in die Timeline einhängen
(die Forecast-Markierung `is-forecast` + Scrub/Play gibt es schon).
- **Vergangenheit:** weiter RainViewer (einfach) ODER DWD RADOLAN-RY (5-Min-Analyse) für all-DWD-Konsistenz.
- Quelle pro Frame: Vergangenheit = RainViewer-Tiles, Vorhersage = DWD-PMTiles (byt-/raster-Source).
## Aufwand & offene Entscheidungen
- **Decode:** trivial (verifiziert). **Projektion:** der einzige Knackpunkt — DE1200-Georeferenzierung korrekt
nach 3857 (wradlib nimmt's ab, oder bekannter PROJ-String + Eckkoordinaten). **PoC nötig:** 1 Frame →
Tiles → über MapLibre rendern und gegen RainViewer/echten Regen gegenchecken (Passgenauigkeit).
- **Tiling alle 5 Min × 25 Frames:** z09 für DE ist schnell (Sekunden~1 Min auf der DS). Last beachten
(läuft neben Immich & Co.); ggf. nur jeden 2. Lead-Time tilen (10-Min-Schritte) zum Sparen.
- **Speicher:** Radar-Tiles sind dünn/transparent → wenige MB pro Lauf.
- **Cron alle 5 Min:** neuer Container/Job (analog `docker-compose.osm.yml`); ⚠️ `--remove-orphans`-Falle.
- **Entscheidungen:** (a) Vergangenheit RainViewer vs. DWD-RY; (b) PMTiles-pro-Frame vs. XYZ; (c) Farbskala;
(d) Zoom-Range (z09) + Lead-Schrittweite (5 vs 10 Min); (e) Container-Stack (GDAL/Python) auf der DS.
- **Abhängigkeit:** Docker auf der DS.
## Nächste Schritte
1. **PoC**: 1 RV-Archiv → 1 Frame decode → kolorieren → reprojizieren → 1 PMTiles → headless über MapLibre
rendern. **Kernfrage: stimmt die Georeferenzierung?** (Wenn ja, ist der Rest Fleißarbeit.)
2. Pipeline-Skript (fetch→decode→tile→deploy) + Cron-Job + Manifest.
3. Frontend: Manifest in die Timeline einhängen (Vorhersage-Frames rechts von „jetzt").
Siehe `docs/TILE_SERVER_HANDOVER.md` (Tile-Infra), Memory `project_tile_server_maintenance`.