Rhein-Pegel · Citizen-Science

Wissenschaftliche Methodik

Stand 2026-05-06 · grafana influxdb citizen-science rhein pegel hetzner forecasting arx

← zurück zum Hub

Alle Skripte unter /opt/rhein/poller/. Ergebnisse landen im InfluxDB-Bucket rhein_derived.

Phase 2.1 — NHN-Höhen + Wasserspiegelgefälle

Theorie

Wasserstand wird in cm über Pegelnullpunkt (PNP) gemessen. Absolute Höhe in m über NHN:

$$H_{\text{NHN}}(t) = \text{PNP} + \frac{W(t)}{100}$$

Wasserspiegelgefälle zwischen zwei Stationen (cm/km):

$$I_{ij}(t) = \frac{H_{\text{NHN},i}(t) - H_{\text{NHN},j}(t)}{\Delta x_{ij}} \cdot 100$$

mit i = stromaufwärts, j = stromabwärts.

Implementation

phase2_nhn_v2.py — jahresweise Verarbeitung (Influx-schonend), bei Mainz PNP-Validity ab 2019-11-01 beachtet (vor diesem Datum wird NHN nicht berechnet, weil PNP-Wert unbekannt).

Drei Abschnitte: - WORMS → NIERSTEIN (Δx = 37,236 km) - NIERSTEIN → MAINZ (Δx = 17,664 km) - WORMS → MAINZ (Δx = 54,9 km, Gesamtabschnitt)

Ergebnisse

Längsgefälle Tagesmittel 2024-06-02 bis -08:

Abschnitt Gefälle (cm/km)
WORMS → NIERSTEIN 9,5–11,6
NIERSTEIN → MAINZ 11,4–12,5
WORMS → MAINZ 10,1–11,9

Plausibel für Mittelrhein (typisch 8–15 cm/km).

Volumen: 844 607 NHN-Punkte + 764 359 Gefälle-Punkte in rhein_derived für 2017-07-18 bis heute.


Phase 2.2 — Globale Cross-Korrelation (CCF)

Theorie

Wellen-Celerität c zwischen zwei Stationen wird aus dem Lag τ* des CCF-Maximums abgeleitet:

$$\rho_{xy}(\tau) = \frac{\sum_t (x(t) - \bar{x})(y(t+\tau) - \bar{y})}{\sqrt{\sum_t (x-\bar{x})^2 \sum_t (y-\bar{y})^2}}$$

$$c = \frac{\Delta x}{\tau^*}$$

CCF wird auf der 1. Differenz dW/dt berechnet, um langsame Trends zu eliminieren.

Ergebnisse 2020–2026 (5 Segments)

Segment Δx (km) τ* (h) c (m/s) r_max
WORMS → NIERSTEIN 37,2 3,75 2,76 0,11
NIERSTEIN → MAINZ 17,7 1,00 4,91 0,09
WORMS → MAINZ 54,9 7,25 2,10 0,09
SPEYER → WORMS 42,8 7,75 1,53 0,11
SPEYER → MAINZ 97,7 17,00 1,60 0,07

Bewertung


Phase 2.3 — Autokorrelation + Welch-Spektrum

Theorie

ACF misst System-Gedächtnis: wie lange dauert es, bis der Wasserstand „seine Geschichte vergisst"? Quantifiziert über die e-fold-Abklingzeit (ACF unter 1/e ≈ 0,368).

Welch-Periodogramm zerlegt die Zeitreihe in Frequenzbeiträge — interessant ist der 1/24h-Peak als möglicher Indikator für Tagesperiodik (Schweizer Schwellbetrieb der Laufwasserkraftwerke?).

Ergebnisse (Jahr 2024 als Referenz)

Station r(24 h) r(72 h) e-fold (h) SNR @ 1/24 h
WORMS 0,973 0,860 > 168 1,56
NIERSTEIN 0,977 0,870 > 168 3,18
MAINZ 0,977 0,866 > 168 1,60
SPEYER 0,970 0,871 > 168 2,24
MANNHEIM 0,971 0,856 > 168 1,24
MANNHEIM_NECKAR 0,969 0,843 > 168 2,84
RAUNHEIM 0,936 0,704 > 168 2,25

Bewertung


Phase 2.4 — Event-basierte CCF

Motivation

Globale CCF mittelt über sehr unterschiedliche Regimes. Wirft man stattdessen ein Fenster (5 Tage vor + 10 Tage nach dem Peak) um identifizierte HW-Ereignisse, isoliert man das Wellensignal.

HW-Identifikation: Worms-W > 450 cm, Mindestabstand zwischen Events 14 Tage. Im Zeitraum 2016–2026 wurden ~14 Events gefunden.

Ergebnisse — Highlights

Event Peak (cm) WORMS→NIERSTEIN c (m/s) r_max WORMS→MAINZ c (m/s) r_max
2018-01-07 „HW Januar 2018" 621 3,45 0,44 4,07 0,47
2020-02-05 (Sturmtief) 523 1,53 0,62 2,65 0,54
2024-06-04 (Sommer-HW) 695 1,18 0,52 0,91 0,54
2019-05-23 467 1,33 0,55 2,65 0,48
2018-01-25 (Welle 2) 637 0,86 0,36 1,91 0,33

Bewertung


Phase 3.1 — Muskingum-Routing

Theorie

Klassisches lineares Routing-Modell:

$$Q_{\text{out}}(t+\Delta t) = C_0 \cdot Q_{\text{in}}(t+\Delta t) + C_1 \cdot Q_{\text{in}}(t) + C_2 \cdot Q_{\text{out}}(t)$$

mit $$C_0 = \frac{\Delta t - 2 K x}{2 K (1-x) + \Delta t}, \quad C_1 = \frac{\Delta t + 2 K x}{2 K (1-x) + \Delta t}, \quad C_2 = \frac{2 K (1-x) - \Delta t}{2 K (1-x) + \Delta t}$$

v2: Dual-Input mit Q_lat

Erste Naive-Variante (nur Worms→Mainz, Nelder-Mead) konvergierte nicht und unterprädizierte den Peak systematisch (Main fehlte als Input). v2 macht es richtig:

$$Q_{\text{Mainz,pred}}(t) = \mathcal{M}1(Q}}; K_1, x_1) + \mathcal{M2(Q$$}}; K_2, x_2) + Q_{\text{lat}

5 Parameter ($K_1, x_1, K_2, x_2, Q_{\text{lat}}$) werden via Differential Evolution auf einem HW-Event kalibriert. Globale Parameter sind der Median über mehrere Train-Events.

Ergebnisse

Globale Parameter (Median über 3 Train-Events): - $K_1 = 14{,}26$ h (Worms → Mainz Storage-Time) - $x_1 = 0{,}00$ (Reservoir-Limit, kein Translation-Anteil) - $K_2 = 0{,}40$ h (Raunheim → Mainz, kurze Strecke) - $x_2 = 0{,}012$ - $Q_{\text{lat}} = -20$ m³/s (kleiner Mess-Bias)

Train-NSE:

Event NSE RMSE Peak obs / pred
HW Jan 2018 0,994 62 4990 / 5065 m³/s
HW Feb 2020 0,998 36 3940 / 3918
HW Juni 2024 0,973 130 4960 / 5205

Test-NSE (mit globalen Parametern):

Event NSE RMSE Peak obs / pred
HW Jan 2018 W2 0,983 69 4680 / 4852
HW Mai 2019 0,987 77 3390 / 3285
HW Dez 2023 0,988 51 4430 / 4537

Alle Test-NSE > 0,97 — das ist ein vorzeigbares Ergebnis. Peak-Fehler typisch < 3 %.

Caveats


Phase 3.2 — ARX-Baseline-Vorhersage für H_Mainz

Modell

$$H_{\text{Mainz}}(t) = a_1 H_{\text{Mainz}}(t-1) + a_2 H_{\text{Mainz}}(t-2) + b_1 H_{\text{Worms}}(t-7) + b_2 H_{\text{Nierstein}}(t-1) + b_3 H_{\text{Raunheim}}(t-1) + \varepsilon(t)$$

Koeffizienten (gefittet)

Parameter Wert
AR1 0,2211
AR2 0,3653
WORMS_lag7 0,1451
NIERSTEIN_lag1 1,2925 ← dominanter Prediktor
RAUNHEIM_lag1 -0,2925
σ² 0,4096

Ergebnisse

One-Step-Ahead-Vorhersage auf Testperiode 2024: - NSE = 0,949 - RMSE = 16,5 cm (Mainz-H schwankt typisch 100–300 cm → Relativfehler ~5 %)

Bekannter Bug

Die Vorlauf-Zeit-Differenzierung (1h, 4h, 8h, 12h) ist im aktuellen Skript nicht korrekt implementiert — alle Vorlauf-Zeiten geben identisches Ergebnis. Echte Multi-Vorlauf-Zeit-Vorhersage (Direct-Method, je ein Modell pro Vorlauf-Zeit) ist ausstehend (Phase 3.5).


Vergleich der Modelle

Modell Größe Skill (Test) Vorlauf-Zeit
Muskingum v2 Q_Mainz NSE > 0,97 implizit ~K-Stunden
ARX (SARIMAX) H_Mainz NSE = 0,95 One-Step (1h)

Beide sind komplementär: - Muskingum modelliert Q (Volumenstrom) und ist physikalisch interpretierbar. - ARX modelliert H (Wasserstand) und liefert eine direkt operationelle Vorhersage in cm.

Für eine echte Live-Vorhersage Mainz mit 4-12 h Vorlauf-Zeit müsste das ARX-Modell auf Direct-Method umgestellt werden.


Phase 6 — Wellen-Propagation Worms→Nierstein (40 Segmente)

Idee

Statt 40 Pegel an 40 Punkten installieren: ein einziger Worms-Pegel + Wellen-Celerität + Geometrie. Für Segment $s$ bei km-Distanz $x_s$ vom Worms-Pegel:

$$W_s(t) = W_{\text{Worms}}\left(t - \frac{x_s \cdot 1000}{c}\right) \quad\text{mit}\quad c = 2{,}5\ \text{m/s}$$

Die Welle ist dadurch sichtbar als zeitversetzter Worms-Wert entlang der 38 km Strecke. Bei Hochwasser-Anstieg sieht man eine farbige Welle wandern.

Geometrie

Wahl der Wellen-Celerität

$c = 2{,}5$ m/s aus zwei unabhängigen Quellen bestätigt: - Phase 2 Event-CCF Median-Wert über saubere HW-Events 2018-2024 - Lighthill-Whitham $c \approx \frac{5}{3} v$ mit mittlerer Strömungsgeschwindigkeit ~1,5 m/s

Konstantes c ist eine bewusste Vereinfachung — bei sehr hohem oder sehr niedrigem Wasserstand variiert c, aber der Fehler in der km-Position ist im Mittel < 5 % über die 4 h Laufzeit.

Pipeline (Live, alle 15 min)

Worms-W (rhein_raw)
    ↓
propagate.py (lag = km · 1000 / c)
    ↓
rhein_derived.rhein_segment  (Influx)
    +
/srv/web/maps/rhein_segments_live.geojson  (per-Feature stroke-Farbe, SimpleStyle-Spec)

Phase 6b — Worms-Vorhersage (Direct-Method-ARX, 4 Vorlauf-Zeiten)

Architektur

Statt eines rekursiven One-Step-Modells (das den Vorlauf-Zeit-Bug aus Phase 3.2 erzeugt) vier separate Ridge-Regression-Modelle, je eines pro Vorlauf-Zeit:

$$\hat W_{\text{Worms}}(t + h) = \sum_i \beta_i^{(h)} x_i(t) \quad\text{für}\quad h \in {1, 4, 8, 12}\ \text{h}$$

Features (26 pro Modell)

Alle Features bei $t$ bekannt → Direct-Method (kein Vorhersage-Cascading-Fehler).

Training

Ergebnisse Testperiode 2024-2025

Lead NSE RMSE Skill vs. Persistenz
+1 h 1,0000 0,4 cm 62 %
+4 h 0,9999 1,4 cm 67 %
+8 h 0,9994 3,0 cm 68 %
+12 h 0,9978 4,5 cm 65 %

NSE-Werte > 0,997 sind nicht überraschend — Worms-W ist hochautokorreliert (e-fold > 7 d, $r(24h) \approx 0{,}97$). Aussagekräftiger ist der Skill gegen Persistenz: 62-68 % der Persistenz-Restfehler-Varianz wird durch das Modell erklärt.

Pipeline (Live, stündlich)

arx_worms.py (einmalig)  →  /app/data/worms_arx_models.pkl (5,4 KB, 4 Modelle)
                                       ↓
                          forecast_cron.py (cron 5 * * * *)
                                       ↓
       rhein_forecast.worms_arx_forecast       rhein_forecast.rhein_segment_forecast
       (4 Lead-Punkte/Stunde)                   (40 Segmente × 12 h)

Vorhersage-Segment-Werte werden mit derselben km-zu-Zeit-Lag-Formel ($x \cdot 1000 / c$) auf die 40 Segmente propagiert → die ARX-Welle wandert sichtbar in die Zukunft.


Phase 6.5 — Leaflet-Iframe für Per-Segment-Färbung

Problem

Grafana 13 Geomap-Panel rendert GeoJSON-LineStrings ausschließlich mit einer panelweiten Style-Farbe; per-Feature stroke-Properties (SimpleStyle-Spec) werden ignoriert. Bei 40 Segmenten mit unterschiedlicher Wasserstand-Farbe ergibt sich nur eine einfarbige Linie.

Lösung

Externes Leaflet-Frontend welle.html (Leaflet 1.9.4 via CDN), per <iframe> ins Dashboard eingebettet. Same-Origin (beide hinter Caddy auf rhein-pegel.duckdns.org) → keine X-Frame-Options-Issues.

propagate.py schreibt zusätzlich zur Influx auch eine styled GeoJSON-Datei nach /srv/web/maps/rhein_segments_live.geojson mit per-Feature:

{ "stroke": "#8B0000", "stroke-width": 6, "stroke-opacity": 0.9, "w_cm": 86.0 }

Leaflet liest die Properties direkt und färbt jedes Segment individuell.

Grafana-Konfiguration

GF_PANELS_DISABLE_SANITIZE_HTML=true ist Pflicht — sonst entfernt Grafana das <iframe> aus dem Text-Panel-Content.

Live-URL


Vergleich der Vorhersage-Modelle

Modell Größe Vorlauf-Zeit Skill (Test)
Muskingum v2 Q_Mainz implizit ~K-Stunden NSE > 0,97
ARX SARIMAX (Phase 3.2) H_Mainz One-Step (1h), buggy für >1h NSE = 0,95
Direct-Method-ARX (Phase 6b) W_Worms 1/4/8/12 h, korrekt NSE 0,998-1,000, Skill 62-68 %

Die in Phase 3.2 dokumentierte Vorlauf-Zeit-Bug-Limitierung ist mit Phase 6b für Worms gelöst. Eine analoge Direct-Method-Variante für Mainz ist offen und wäre ein sauberer Phase-3.5-Schritt.


Phase 6c — Erweiterung auf 11 Pegel + 24 h Vorhersage + HW-Warner

Motivation

Phase 6/6b war auf den Streckenabschnitt Worms→Nierstein begrenzt (40 Segmente, 12 h Vorhersage). Für eine echte HW-Vorwarnung am Bootshaus reicht das nicht — die Vorwarnzeit muss länger sein als die Reaktionszeit der Vereinsorganisation. Ziel: 24 h Vorhersage mit nutzbarem Skill, plus automatische Pushover-Benachrichtigung.

4 zusätzliche Oberlauf-Pegel

Pegel km Lag → Worms (c=2,5 m/s)
Iffezheim 336,20 ~12 h
Plittersdorf 340,20 ~11 h
Maxau 362,33 ~9 h
Philippsburg 389,33 ~6 h

Backfill via Pegelonline-Archiv-API (siehe Phase 0): ~292 k Punkte/Station × Parameter, total ~2 Mio. neue Punkte (2018-2026). Live-Polling alle 15 min.

Wichtige Beobachtung: Philippsburg-Pegelonline-Live hat ~12 h Latenz (Q wird nur einmal täglich gerechnet). Deshalb wurde Philippsburg aus den ARX-v2-Features ausgeschlossen, um den Vorhersage-Anker frisch zu halten.

Direct-Method-ARX v2

$$\hat W_{\text{Worms}}(t + h) = \sum_i \beta_i^{(h)} x_i(t) \quad\text{für}\quad h \in {1, 4, 8, 12, 16, 20, 24}\ \text{h}$$

102 Features pro Modell: - IFFEZHEIM lags 0..28 h (29) - PLITTERSDORF lags 0,2,4,...,24 h (13) - MAXAU lags 0..20 h (21) - SPEYER lags 0..14 h (15) - MANNHEIM lags 0..6 h (7) - WORMS-AR lags 0..3 h (4) - Saisonalität sin/cos (24 h, Jahr): 4 - 4 weitere ungenutzte Slots

Train 2018-2024 (61 355 h), Test 2024-2026 (12 000 h).

Ergebnisse v2 (Testperiode 2024-2026)

Lead NSE RMSE Skill vs. Persistenz
+1 h 1,0000 0,42 cm 60 %
+4 h 0,9998 1,21 cm 69 %
+8 h 0,9994 2,40 cm 68 %
+12 h 0,9986 3,58 cm 68 %
+16 h 0,9975 4,82 cm 67 %
+20 h 0,9959 6,18 cm 65 %
+24 h 0,9936 7,77 cm 63 %

24 h-Vorhersage ist nutzbar: RMSE 7,77 cm, MAPE_HW 2,9 %. Im Hochwasser-Bereich (Worms > 400 cm) ist das eine Vorhersagepräzision von ±12 cm — genau genug, um eine Schwellwert-Überschreitung 24 h voraus anzukündigen.

Karte Phase 6c (Maxau → Mainz + Altrhein)

Statt zeitversetztem Worms-W (Phase 6) jetzt räumliche Interpolation zwischen den 7 amtlichen Pegeln. Für Hauptrhein-Segment km_x finde umgebenden Pegel km_u < km_x < km_d:

$$W_x(t) = (1 - \alpha) \cdot W_u(t) + \alpha \cdot W_d(t), \quad \alpha = \frac{km_x - km_u}{km_d - km_u}$$

Für Altrhein-Segment α (0 = Stockstadt-Mündung, 1 = Erfelden-Mündung):

$$W_{\text{alt}}(t, \alpha) = (1 - \alpha) \cdot W_{\text{Stockstadt}}(t) + \alpha \cdot W_{\text{Erfelden}}(t)$$

wobei $W_{\text{Stockstadt}}$ und $W_{\text{Erfelden}}$ selbst aus Pegel-Interpolation auf km 468,4 bzw. 473,9 gewonnen werden. Damit ist der Altrhein hydraulisch konsistent mit dem Hauptrhein modelliert (offen an beiden Enden, quasi-statische Wasserstand-Anpassung).

136 Hauptrhein-Segmente (~1 km/Segment, Maxau km 362 → Mainz km 498) + 18 Altrhein-Segmente = 154 Features in rhein_segments_v2_live.geojson.

⚠ PNP-Einschränkung

Die Farbskala der Karte (RC-Neptun-Worms-Schwellwerte 100/150/200/430/500/640 cm) gilt streng nur am Worms-Pegel. Die anderen Pegel haben unterschiedliche Pegelnullpunkte (PNP) — Maxau bei 405 cm ist Mittelwasser, nicht "Wege sperren wie bei Worms 405 cm". Die Färbung im Maxau-Bereich ist eine grobe Indikation.

Eine Phase 6d mit lokalen Skalen (MNW/MHW pro Pegel via Pegelonline-charvalues, siehe charvalues.py) ist ein offenes TODO.

Pushover-HW-Warner

hw_alert.py läuft alle 15 min via Cron. Liest aktuellen Worms-W + ARX-v2-Vorhersage (1..24 h). Trigger:

Schwelle Bedeutung Pushover-Priority
430 cm Fasanenweg sperrt 0 (normal)
500 cm Stockstadt-Zugang sperrt 1 (high)
640 cm NSG komplett gesperrt 2 (emergency)

Hysterese: 6 h Cooldown pro Schwelle. State persistiert in /app/data/hw_alert_state.json.

Vorwarnzeit: Da der Trigger schon beim ersten ARX-Vorhersage > Schwelle feuert, ergibt sich eine Vorwarnzeit von 1-24 h, je nach wie weit die Welle in Maxau bereits sichtbar ist.

Pipeline-Übersicht (Phase 6c, 2026-05-05)

Pegelonline (11 Stationen)
    ↓ poll alle 15 min
rhein_raw  (Influx)
    ↓
    ├─ propagate_v2.py (cron */15)  →  rhein_segment_v2 + rhein_segments_v2_live.geojson
    ├─ forecast_cron_v2.py (cron 5 *)  →  worms_arx_v2_forecast (rhein_forecast)
    └─ hw_alert.py (cron */15)  →  Pushover (wenn Schwelle aktiv/Forecast)

Phase 6d — Lokale MNW/MHW-Skala für die Karten-Färbung

Problem mit Phase 6c

Die Phase-6c-Karte hat Worms-Bootshaus-Schwellwerte (100/150/200/430/500/640 cm) auf alle Hauptrhein-Segmente angewendet. Da die Pegel unterschiedliche Pegelnullpunkte (PNP) haben, war die Färbung farblich misleadingend:

Pegel MNW [cm] MW [cm] MHW [cm]
Iffezheim 104 240 518
Maxau 353 496 785
Speyer 214 361 699
Mannheim 132 293 644
Worms 46 195 529
Nierstein 112 259 554
Mainz 159 288 547

Z.B. 405 cm @ Maxau ist Mittelwasser, nicht "fast Hochwasser" wie bei Worms 405 cm. Mit Worms-Schwellen wäre Maxau-Bereich grün (200-430 = "Mittelwasser") gefärbt — irreführend, weil "Mittelwasser bei Worms" und "Mittelwasser bei Maxau" hydraulisch verschiedene Lagen sind.

Lösung: Ratio-basierte Färbung pro Segment

Pro Segment km_x werden MNW und MHW räumlich-linear zwischen den umgebenden Pegeln interpoliert. Dann:

$$\text{ratio}(km_x, t) = \frac{W(km_x, t) - \text{MNW}\text{lokal}(km_x)}{\text{MHW}\text{lokal}(km_x) - \text{MNW}_\text{lokal}(km_x)}$$

Diskrete Farbskala (8 Stufen) auf Basis von ratio:

Ratio Farbe Bedeutung
< −0,2 dunkelblau extrem niedrig (NW unter MNW)
−0,2..0,2 blau knapp niedrig
0,2..0,5 hellblau Niedrigwasser
0,5..0,8 grün Mittelwasser
0,8..1,0 gelb Annäherung MHW
1,0..1,3 orange leichtes Hochwasser
1,3..1,8 rot Hochwasser
> 1,8 dunkelrot extreme HW

Damit sind 405 cm @ Maxau und 87 cm @ Worms beide korrekt als blau (Niedrigwasser) eingefärbt — visuell konsistent.

Altrhein bleibt bei Worms-Bootshaus-Skala

Für die Altrhein-Segmente ist die RC-Neptun-Befahrbarkeit relevant, nicht die hydrologische Lage. Daher bleibt dort die Worms-Schwellen-Skala (100/150/200/430/500/640) — durchgehend in 8 unterscheidbaren Farben:

Worms-W Stufe Farbe
< 100 cm Treideln lila
100-150 cm knapp hell-lila
150-200 cm befahrbar cyan
200-430 cm Mittelwasser ideal grün
430-500 cm Wege sperren gelb
500-550 cm HW unterer orange
550-640 cm HW oberer rot
> 640 cm komplette Sperrung dunkelrot

(Die alte Skala hatte sowohl Treideln als auch Sperrung in dunkelrot — nicht unterscheidbar.)

Bias-Korrektur in der Pushover-Message

Aus dem Rückblickende Validierung HW Juni 2024 wurde der Modell-Bias pro Vorlauf-Zeit bestimmt. Der Bias ist negativ (Modell unterschätzt im HW-Bereich systematisch):

Lead Bias [cm] RMSE [cm]
+1 h −0,1 0,6
+4 h −0,2 2,2
+8 h −1,2 5,8
+12 h −2,8 10,4
+16 h −4,8 15,8
+20 h −7,1 21,5
+24 h −9,7 27,3

Die Pushover-Message zeigt jetzt den bias-korrigierten Wert ± RMSE als 1-σ-Konfidenzbereich, plus den Roh-Pred-Wert zur Transparenz.


Phase 6f — Muskingum-Sub-Routing für die Karte

Motivation

Phase 6c interpolierte räumlich-linear zwischen den Pegeln zur gleichen Zeit. Das ignoriert die Wellenausbreitung — eine HW-Welle erscheint als räumlich gemittelter Gradient, nicht als wandernde physikalische Welle.

Lösung: Muskingum-Routing pro Pegel-Reach

Klassisches Muskingum (linear, dt = 1 h):

$$Q_\text{out}(t) = C_0 \cdot Q_\text{in}(t) + C_1 \cdot Q_\text{in}(t-\Delta t) + C_2 \cdot Q_\text{out}(t-\Delta t)$$

mit den Routing-Koeffizienten

$$C_0 = \frac{-Kx + 0{,}5\Delta t}{K - Kx + 0{,}5\Delta t}, \quad C_1 = \frac{Kx + 0{,}5\Delta t}{K - Kx + 0{,}5\Delta t}, \quad C_2 = \frac{K - Kx - 0{,}5\Delta t}{K - Kx + 0{,}5\Delta t}$$

K = Storage-Konstante [h], x = Weighting [0..0,5]. Stabilitätsbedingung: 2Kx ≤ Δt ≤ 2K(1-x).

MW-Anomalie-Trick (PNP-Korrektur)

Direktes Routing der Wasserstand-Werte schlug fehl (NSE −2,4 für Iffezheim→Plittersdorf), weil die Pegelnullpunkte unterschiedlich sind. Lösung: Pegel-Anomalie routen:

$$W'_u(t) = W_u(t) - \text{MW}_u, \quad W'_d^\text{pred} = \text{Muskingum}(W'_u, K, x)$$

$$W_d^\text{pred}(t) = W'_d^\text{pred}(t) + \text{MW}_d$$

Damit wird der Mittel-Versatz aus dem Routing-Modell herausgenommen und nur noch die Wellen-Dynamik trainiert.

Kalibrierung 8 Reaches (Train 2018-2024)

Für jeden Reach (Pegel-Paar entlang Rhein) wurden K und x via Differential Evolution auf SSE der MW-Anomalie kalibriert.

Reach Δkm K [h] x NSE_W RMSE [cm] c_implied [m/s]
Iffezheim → Plittersdorf 4,0 1,27 0,000 0,994 6,7 0,88
Plittersdorf → Maxau 22,1 6,68 0,075 0,992 8,5 0,92
Maxau → Philippsburg 27,0 9,40 0,053 0,990 10,2 0,80
Philippsburg → Speyer 11,3 3,45 0,144 0,996 7,1 0,91
Speyer → Mannheim 24,1 2,90 0,000 0,983 14,7 2,31
Mannheim → Worms 18,6 3,04 0,000 0,994 8,0 1,70
Worms → Nierstein 37,2 8,65 0,000 0,992 9,0 1,20
Nierstein → Mainz 17,7 1,57 0,000 0,965 16,3 3,13

Beobachtung: Implizite Wellengeschwindigkeit (c = Δx/K) variiert stark — 0,8 m/s im Süden (gestaut durch Iffezheim-Wehr), 2-3 m/s im Mittel- und Untermain.

Sub-Routing pro Karten-Segment

Pro Hauptrhein-Segment km_x in Reach (km_u → km_d): - α = (km_x − km_u) / (km_d − km_u) - K_seg = max(0,5, α · K_full) - W_seg(t) = Muskingum(W_u-Reihe, K_seg, x) + (MW_u + α · (MW_d − MW_u))

Damit wandert eine HW-Welle physikalisch korrekt mit reach-spezifischer Geschwindigkeit durch die Karte. Die räumlich-zeitliche Verteilung ist konsistent mit den 8 trainierten Reaches.


Validierung Phase 6b/c — Rückblickende Validierung HW Juni 2024

Der Testperiode (Test-Set 2024-2026) enthält das schwere Sommer-Hochwasser vom 02.-15. Juni 2024 mit Peak 695 cm am 04.06. Damit lässt sich das ARX-v2-Modell retrospektiv validieren — hätte der HW-Warner damals rechtzeitig getriggered?

Verlaufs-Plot

Rückblickende Validierung HW Juni 2024 — Verlauf

Schwarze Linie = beobachteter Worms-Pegel. Bunte Linien (Viridis von dunkelviolett +1h zu gelb +24h) = Vorhersage-Werte zum jeweiligen Target-Zeitpunkt. Gestrichelte Linien = Schwellwerte 430/500/640 cm.

Beobachtung: Lead-1h und Lead-4h kleben praktisch auf der Beobachtung. Lead-24h hinkt sichtbar zurück und unterschätzt den Peak (665 cm prognostiziert vs. 695 cm beobachtet).

Skill pro Vorlauf-Zeit

Rückblickende Validierung HW Juni 2024 — RMSE und Bias pro Lead

RMSE wächst von 0,6 cm @ +1h auf 27,3 cm @ +24h. Modell-Bias (Pred − Obs) ist durchgehend negativ — der Mittel-Pull der Ridge-Regression dämpft die Spitze.

Schwellwert-Crossing — HW-Warner-Simulation

Wenn der HW-Warner damals gelaufen wäre (alle 7 Vorlauf-Zeiten parallel checkt):

Schwelle Obs erstmals erreicht Modell triggert (Vorab-Auslösung) Vorwarnzeit
430 cm (Fasanenweg) 01.06. 15:00 01.06. 06:00 (Lead +24h, pred 434) +9 h
500 cm (Stockstadt) 02.06. 02:00 01.06. 14:00 (Lead +24h, pred 509) +12 h
640 cm (NSG) 03.06. 05:00 02.06. 12:00 (Lead +24h, pred 643) +17 h

Alle drei Schwellen wären rechtzeitig getriggered worden — null False Alarms über alle 7 × 3 = 21 Lead-Trigger-Kombinationen. Der HW-Warner hätte am 01.06. um 06:00 Uhr UTC die erste Pushover-Notification (Vorwarnung Fasanenweg) gesendet, mit 9 Stunden Vorlauf.

Statistik im HW-Bereich (Worms-Obs > 400 cm, n = 278-301)

Lead NSE RMSE MAE Bias
+1 h 1,0000 0,59 cm 0,46 cm +0,1
+4 h 0,9994 2,18 cm 1,56 cm −0,2
+8 h 0,9954 5,81 cm 3,83 cm −1,2
+12 h 0,9852 10,4 cm 6,57 cm −2,8
+16 h 0,9660 15,8 cm 9,68 cm −4,8
+20 h 0,9373 21,5 cm 12,8 cm −7,1
+24 h 0,8986 27,3 cm 16,2 cm −9,7

NSE bleibt > 0,9 bis Lead +20h. Bei +24h fällt sie auf 0,90 — das Modell ist dann nicht mehr signifikant besser als Persistenz für Niedrigwasser-Bereich, aber im HW-Bereich noch nutzbar (Skill ≈ 63 % gegen Persistenz).


Phase 6g — Multi-Event-Rückblickende Validierung (alle 11 HW-Events 2018-2026)

Methodik

Aus den Phase-2-Event-CCF-Daten (rhein_derived.ccf_event) wurden 11 saubere Hochwasser-Events identifiziert:

Event-ID Datum (Peak) Peak-W [cm]
20180107 07.01.2018 622
20180125 25.01.2018 637
20190317 17.03.2019 451
20190523 23.05.2019 467
20200205 05.02.2020 524
20210204 04.02.2021 613
20210718 18.07.2021 604
20231119 19.11.2023 543
20231215 15.12.2023 610
20240604 04.06.2024 695
20250110 10.01.2025 457

Pro Event: ARX-v2 wurde stündlich für 17 Tage simuliert (−7..+10 Tage um Peak), Vorhersage für alle 7 Vorlauf-Zeiten bei jeder Stunde berechnet, Ergebnisse gegen Beobachtung verglichen.

Ergebnis: HW-Warner-Trefferquote

Vorwarnzeit pro Event und Schwelle

Schwelle Events erreicht Vorab-Auslösung Post-Fire Miss Hit-Rate Mean-Vorwarnzeit
430 cm (Fasanenweg) 11 10 1 0 91 % +15.8 h
500 cm (Stockstadt) 8 8 0 0 100 % +20.5 h
640 cm (NSG) 1 1 0 0 100 % +17.0 h

19 von 20 Schwellen-Triggern Vorab-Auslösung (95 % gesamt). Null Misses. Der 1 Post-Fire-Fall wurde noch innerhalb 1 h des Beobachtungs-Eintretens getriggered — also nur knapp zu spät, nie ganz verpasst.

Skill pro Vorlauf-Zeit (gemittelt über 11 Events)

RMSE und Bias pro Vorlauf-Zeit, Multi-Event

Lead NSE_HW RMSE_HW Bias_HW
+1 h 0.9997 0.5 cm +0.0
+4 h 0.9958 1.8 cm +0.1
+8 h 0.9799 4.0 cm +0.0
+12 h 0.9405 6.6 cm −0.2
+16 h 0.8582 9.7 cm −0.7
+20 h 0.7633 13.0 cm −1.4
+24 h 0.6137 16.8 cm −2.4

Wichtige Beobachtung: Der Mean-Bias bei +24 h ist nur −2.4 cm gemittelt über 11 Events — viel kleiner als die −9.7 cm des einzelnen 2024-Events (das ein Extremereignis war). Das war Anlass zur Phase-6h-Anpassung der HW-Alarm-Konfidenzbänder.


Phase 6h-Conformal — Empirische Quantil-Konfidenzbänder

Problem mit Phase 6d Bias-Korrektur

Phase 6d nutzte Bias und RMSE aus dem einzelnen 2024-HW-Event und annahm normalverteilte Residuen. Das war: - Zu konservativ in der Korrektur (−9.7 cm Bias bei Lead 24h, gemessen nur an einem Event) - Annahme einer Normalverteilung der Vorhersagefehler — was bei HW-Events nicht stimmt (rechts-skewed: das Modell unterschätzt extreme Peaks öfter, aber selten überschätzt)

Conformal-Prediction-Ansatz

Statt Annahmen über die Verteilung: direkte empirische Quantile der Train-Residuen auf dem HW-Subset (obs > 400 cm, n = 2 438 Stunden 2018-2024).

Pro Vorlauf-Zeit (h) sind die Quantile (in cm, residual = obs − pred):

Lead q05 q50 q95 Asymmetrie
+1 h −0.78 −0.04 +0.67 symmetrisch
+4 h −2.68 −0.18 +2.49 leicht asymmetrisch
+8 h −5.16 −0.36 +5.41 symmetrisch
+12 h −7.94 −0.53 +9.60 rechts-skewed
+16 h −10.15 −0.77 +14.00 stark rechts-skewed
+20 h −11.91 −0.98 +21.06 sehr asymmetrisch
+24 h −13.54 −1.15 +29.86 extrem rechts-skewed

Bei Lead +24 h ist q95 = +30 cm (also der Peak könnte 30 cm höher sein als das mittlere Modell vorhersagt) während q05 = −13 cm. Diese Asymmetrie spiegelt wider, dass Extremereignisse das Modell nach oben überraschen, selten nach unten.

Pushover-Message: 90%-PI statt RMSE-Annahme

Die Pushover-Notification zeigt jetzt:

Worms-Forecast +24h: 105 cm (90%-Bereich 91–135 cm).
Schwelle 430 cm im Worst-Case-Fall erreicht voraussichtlich 07.05. 11:00 MESZ.

Trigger-Logik nutzt q95-Grenze (oberer 90%-PI) — konservativer Vorab-Auslösung bei steigendem Trend, aber kein False Alarm bei stabilem Niedrigwasser.


Phase 6e — Time-Slider-Animation

Welle-Animation auf der Karte (welle.html, Slider unten rechts): - Bereich −12 h (historisch) bis +24 h (ARX-Vorhersage) - Toggle LIVE / ANIM - Auto-Play (350 ms/Tick) - Worms-Wert + JETZT-Marker + Schwellwert-Status pro Tick

Backend animation_state.py erzeugt alle 15 min einen JSON-Snapshot (37 Stundenscheiben × 154 Segmente, ~250 KB) unter /maps/welle_animation_state.json. Bei jedem Stunden-Tick wird über alle Hauptrhein-Pegel das Muskingum-Sub-Routing rückwärts in der Vergangenheit + vorwärts mittels ARX-v2-Vorhersage (Worms) und Persistenz-Annahme (alle anderen Pegel) gerechnet.


Phase-7-Roadmap (offene wissenschaftliche Verbesserungen)

Phase 7.1 — DWD-Niederschlag-Vorhersage als ARX-Feature

Idee: Niederschlagsmengen über das Schwarzwald-Einzugsgebiet als zusätzliche Features ins ARX, um Vorlauf-Zeit auf 48-72 h zu erweitern.

Datenquelle: Brightsky API (DWD-Wrapper, JSON-API). Parameter precipitation und precipitation_probability_6h für Stationen Karlsruhe, Freudenstadt, Triberg.

Aufwand: ~1 Tag (Backfill 2018-2024 für 6 Wetter-Stationen, ARX-Re-Training, Skill-Vergleich).

Erwarteter Skill-Gewinn: Lead 48 h NSE > 0.8 (statt 0.6 bei 24 h), Lead 72 h NSE > 0.7. Kritisch für Vorwarnung über mehrere Tage.

Phase 7.2 — Saint-Venant-Routing (statt Muskingum)

Idee: 1D-Hydrodynamik-Modell mit Querschnitten + Sohlgefälle für physikalisch genaue Wellenausbreitung.

Gleichungen (vereinfacht, kinematische Welle):

$$\frac{\partial A}{\partial t} + \frac{\partial Q}{\partial x} = 0 \quad\text{(Massenerhaltung)}$$

$$S_f = S_0 \quad\text{(Impuls, kinematisch)}$$

mit $A$ = Querschnittsfläche, $Q$ = Abfluss, $S_f$ = Reibungs-Slope, $S_0$ = Sohlgefälle.

Datenbedarf: Querschnittsdaten der Wasserstraßen- und Schifffahrtsverwaltung (WSV) — aufwändig zu beschaffen, evtl. nur als Anfrage.

Aufwand: mehrere Tage, Forschungsniveau. Diplomarbeits-tauglich.

Vorteil: echte Physik (Kontinuitäts- + Impulsgleichung) statt linearem Routing-Modell. Bei Extrem-HW genauere Spitzen-Vorhersage.

Phase 7.3 — BfG-WaVo-Vergleichsbenchmark

Status: keine öffentliche API gefunden. Manuelles Web-Scraping der BfG-Wasserstandsvorhersagezentrale wäre möglich aber instabil.

Alternative: EFAS (European Flood Awareness System) hat akademische API — Interface zur Validierung wäre ein eigenes Forschungsprojekt.

Aufwand: ~2 Tage Recherche + Scraping.

Phase 7.4 — Echte Quantile-Regression statt Conformal

Conformal-Prediction (Phase 6h) nutzt globale Train-Residuen-Quantile. Echte heteroskedastische Quantile-Regression (ein Modell pro Quantil, sklearn QuantileRegressor) gäbe state-abhängige PIs — bei steigender Welle ggf. anders breit als bei stabiler Lage. Initial-Test mit Subsampling war zu langsam (~7 Min/Lead), Optimierung nötig.

Aufwand: ~1 Tag mit GBM (Gradient Boosting Quantile-Loss, schneller als LP-basiert).


Phase 7.1 — DWD-Niederschlag-Feature (ARX-v4)

Datenquelle: Brightsky-API (DWD-Wrapper)

3 Wetter-Stationen im Schwarzwald-/Rhein-Einzugsgebiet:

Station Lat / Lon Höhe / Charakter
Karlsruhe 49.04 / 8.40 zentrales Oberrhein
Freudenstadt 48.46 / 8.41 Schwarzwald-Höhe (842 m)
Triberg 48.13 / 8.23 südlicher Schwarzwald

Backfill 2018-01-01 .. 2026-05-06 mittels brightsky_backfill.py: 425 k Niederschlag-Punkte geschrieben in rhein_raw.weather. Live-Poller brightsky_poller.py (Cron alle 60 min) holt zusätzlich DWD-ICON-Vorhersagen (0-72 h) nach rhein_forecast.weather_forecast.

Feature-Engineering

Pro Station × 3 Cumul-Fenster = 9 zusätzliche Features:

$$\text{PRECIP_KARLSRUHE_24h} = \sum_{i=t-24}^{t} P_\text{KARLSRUHE}(i)$$

(analog für Freudenstadt, Triberg und Fenster 24/48/72 h)

Damit wächst der Feature-Vektor von 93 auf 102 Spalten. Die Niederschlag-Features kodieren die "geladene" Hydrologie des Einzugsgebiets — relevant für Vorlauf-Zeiten > 24 h, weil dort die direkte Pegel-Wellenausbreitung (max ~12 h von Iffezheim nach Worms) nicht mehr ausreicht.

Skill-Vergleich v3 (ohne Niederschlag) vs. v4 (mit Niederschlag)

Lead v3 RMSE v4 RMSE Verbesserung v4 NSE v4 Skill vs. Persistenz
+1 h 0.42 cm 0.42 cm 1.0000 60 %
+4 h 1.21 1.18 −2 % 0.9999 70 %
+8 h 2.40 2.31 −4 % 0.9994 70 %
+12 h 3.58 3.40 −5 % 0.9988 69 %
+16 h 4.82 4.54 −6 % 0.9978 69 %
+20 h 6.18 5.79 −6 % 0.9964 68 %
+24 h 7.77 7.25 −7 % 0.9944 65 %
+36 h 13.45 NEU 0.9807 55 %
+48 h 21.27 NEU 0.9516 42 %
+72 h 36.28 NEU 0.8592 25 %

Zwei Wirkungen: 1. Marginale Verbesserung bei kurzen Leads (~5-7 % RMSE-Reduktion bei +24 h). Bei strukturellen HW-Events sind die Pegel-Lags die dominante Information. 2. Neue Vorlauf-Zeiten +36/+48/+72 h wurden freigeschaltet. NSE > 0.95 bis +48 h ist nutzbar; +72 h NSE 0.86 mit Skill 25 % gegen Persistenz reicht für strategische HW-Vorbereitung (Vereinsmaterial sichern, Wege-Sperrungen kommunizieren).

Operationelle Pipeline

Brightsky-API (DWD-Wrapper)
    ├─ brightsky_poller.py (cron 30 *)  → rhein_raw.weather (Obs)
    │                                    + rhein_forecast.weather_forecast (DWD-ICON Forecasts)
    │
ARX-v4 (Pegel-Lags + Niederschlag-Cumuls)
    └─ forecast_cron_v4.py (cron 10 *)  → rhein_forecast.worms_arx_v4_forecast
                                          (Lead 1/4/8/12/16/20/24/36/48/72 h)

Phase 7.1b — DWD-ICON-Niederschlag-Vorhersage als Feature (offen)

Aktuell nutzt v4 nur historische Niederschlag-Beobachtungen (Cumul-Fenster). Die nächste Verbesserung wäre, die DWD-ICON-Niederschlag-Vorhersagen (0-72 h) als zusätzliche Features einzubringen. Das ist konzeptionell anspruchsvoller, da das Modell trainiert werden müsste mit "wie sah der ICON-Vorhersage vor X Stunden aus" — historische ICON-Archive sind verfügbar (DWD CDC), aber Aufwand erheblich.

Erwarteter zusätzlicher Skill-Gewinn: bei Lead +48..72 h könnte NSE von 0.86 auf > 0.92 steigen.


Phase 7.1b — DWD-ICON-Niederschlag-Vorhersage als ARX-Feature (v5)

Idee

Phase 7.1 (v4) nutzte nur historische Niederschlag-Cumul-Werte. Phase 7.1b (v5) erweitert um zukunfts-gerichtete Cumul-Fenster (0..+24 h, 0..+48 h, 0..+72 h pro Wetter-Station = 9 zusätzliche Future-Features).

Methodische Herausforderung: Training mit Perfect-Foresight

Im Training-Set 2018-2024 stehen keine historischen DWD-ICON-Vorhersage-Archive zur Verfügung. Brightsky speichert nur die aktuellen Vorhersagen. Daher Training mit Perfect-Foresight:

$$\text{PRECIP_KARLSRUHE_FUT_24h}(t) = \sum_{i=t+1}^{t+24} P_\text{KARLSRUHE}^\text{obs}(i)$$

Das ist physikalisch nicht korrekt für ein Live-Modell — die echte Niederschlagsmenge der nächsten 24 h ist erst 24 h später bekannt. Im Live-System (forecast_cron_v5.py) werden diese Features stattdessen aus dem DWD-ICON-Vorhersage (gespeichert in rhein_forecast.weather_forecast durch Brightsky-Poller) gefüllt.

Konsequenz: der Test-Skill auf Testperiode 2024-2026 ist eine OBERE SCHRANKE. Im Live-Betrieb wird der Skill etwas niedriger sein, da ICON-D2-Niederschlag-Vorhersagen einen RMSE von typisch 1-2 mm/24 h haben. Eine echte Phase 7.1c würde mit DWD-CDC-ICON-Archiven trainieren — aufwändig (GRIB2-Files, separate Pipeline).

Skill-Vergleich v4 vs. v5 (Testperiode 2024-2026)

Lead v4 RMSE v5 RMSE RMSE-Reduktion v4 Skill v5 Skill Skill-Sprung
+1 h 0.42 0.42 60 % 60 %
+4 h 1.18 1.18 70 % 70 %
+8 h 2.31 2.30 −0 % 70 % 70 %
+12 h 3.40 3.35 −1 % 69 % 70 % + 1
+16 h 4.54 4.40 −3 % 69 % 70 % + 1
+20 h 5.79 5.46 −6 % 68 % 69 % + 1
+24 h 7.25 6.60 −9 % 65 % 68 % + 3
+36 h 13.45 11.10 −17 % 55 % 63 % + 8
+48 h 21.27 16.15 −24 % 42 % 56 % + 14
+72 h 36.28 24.26 −33 % 25 % 50 % + 25

Riesen-Sprung bei langen Leads: +72 h Skill verdoppelt (25 → 50 %), RMSE um ein Drittel reduziert. Das macht 3-Tage-Vorhersagen erstmals operationell nutzbar.

Live-Vorhersage (jetzt)

Stand 2026-05-06 16:30 UTC mit ICON-Niederschlag-Vorhersage:

KARLSRUHE     Future-Precip 24h=11.6 mm
FREUDENSTADT  Future-Precip 24h=7.1 mm
TRIBERG       Future-Precip 24h=7.0 mm
Lead v4 (ohne Vorhersage) v5 (mit ICON) Differenz
+24 h 107.7 cm 112.8 cm +5.1 cm
+48 h 114.0 cm 126.8 cm +12.8 cm
+72 h 117.1 cm 127.6 cm +10.5 cm

V5 prognostiziert höhere Pegel weil das Modell die kommende Niederschlag-Aktivität "antizipiert".

Pipeline

brightsky_poller.py (cron 30 *)
  ├─ rhein_raw.weather (DWD-Beobachtung)
  └─ rhein_forecast.weather_forecast (DWD-ICON-Forecast 0-72h)

arx_worms_v5.py (einmalig, gepickelt)
  Train 2018-2024 mit Perfect-Foresight-Niederschlag

forecast_cron_v5.py (cron 20 *)
  Past-Niederschlag aus rhein_raw.weather (Cumul -24/-48/-72 h)
  Future-Niederschlag aus rhein_forecast.weather_forecast (Cumul +24/+48/+72 h)
  → rhein_forecast.worms_arx_v5_forecast (Lead 1..72 h)

Phase 7.1c — TIGGE-Reforecast als echte Vorhersage-Features (v6)

Idee

Phase 7.1b (v5) trainierte mit Perfect-Foresight: die echten zukünftigen Niederschlag-Beobachtungen ersetzten den (zu der Zeit nicht archivierten) ICON-Vorhersage. Das ist physikalisch nicht korrekt — der resultierende Test-Skill ist eine obere Schranke, weil das Modell während des Trainings „weiß", was später wirklich passiert.

Phase 7.1c schließt diese methodische Lücke: Training mit echten historischen Vorhersage-Archiven, downloaded aus dem TIGGE-Datensatz auf dem ECMWF Data Store (ECDS).

Datenquelle: TIGGE auf ECDS

Backfill-Pipeline

tigge_pilot.py / tigge_backfill.py (einmaliger Lauf)
  ├─ cdsapi-Request pro Monat 2018-01..2024-12
  ├─ GRIB2 → cfgrib → xarray
  ├─ Spatial-Extraktion: nächster Gitterpunkt pro Station
  └─ rhein.weather_forecast_archive (measurement tigge_forecast,
                                     tags: station, origin, lead_h,
                                     time = init_time)

84 Monate × 60 Inits × 13 Lead-Steps × 3 Stationen = ~196 000 Datenpunkte, ~30 MB. Backfill 2026-05-06 21:00–23:16 UTC, alle 84 Monate erfolgreich.

Lookup-Logik im Training

Pro Trainings-Stunde t findet tigge_to_fut_features(...):

  1. den jüngsten Init-Run mit init_time ≤ t (max 12 h alt → entspricht der Live-Latenz von ICON)
  2. Δh = t − init_time, dann lineare Interpolation der Cumul-Werte zwischen den verfügbaren Lead-Stützstellen
  3. Future-Feature PRECIP_<STATION>_FUT_<W>h := tp(min(72, Δ+W)) − tp(Δ)

Die Feature-Namen sind identisch zu v5 → direkter Skill-Vergleich.

Methodische Caveats (verbleibend)

Caveat Stand v5 (Phase 7.1b) Stand v6 (Phase 7.1c)
Perfect-Foresight im Training ✗ vorhanden aufgehoben
Modell-Version konstant über Trainingsperiode n/a (Beobachtungen) ⚠ TIGGE-IFS-Version drifted seit 2018 (operationelle ECMWF-Releases)
Train-Modell ↔ Live-Modell identisch ✓ (beide Brightsky/ICON) ⚠ Train: TIGGE-ECMWF-IFS / Live: Brightsky-DWD-ICON

Die verbleibenden Caveats sind milder: TIGGE-IFS-Drift wirkt nur über mehrere Jahre, ist aber methodisch deutlich näher am realen Live-Modell als die Perfect-Foresight-Substitution. Saubere konstante Reforecast-Modelle (EFAS-Reforecast auf EWDS) sind für Phase 7.1d vorgesehen, aktuell aber gefroren (Stand 2024-11-11).

Skill-Vergleich v5 (Perfect-Foresight) vs. v6 (echte Vorhersagen) — Testperiode 2024-2026

Lead v5 RMSE v6 RMSE Differenz v5 Skill v6 Skill Skill-Verlust
+1 h 0,42 0,40 −0,02 60 % 63 % +3 (sic!)
+4 h 1,18 1,25 +0,07 70 % 69 % −1
+8 h 2,30 2,51 +0,21 70 % 69 % −1
+12 h 3,35 3,74 +0,39 70 % 68 % −2
+16 h 4,40 4,99 +0,59 70 % 68 % −2
+20 h 5,46 6,28 +0,82 69 % 67 % −2
+24 h 6,60 7,71 +1,11 68 % 65 % −3
+36 h 11,10 12,93 +1,83 63 % 59 % −4
+48 h 16,15 18,59 +2,44 56 % 52 % −4
+72 h 24,26 27,85 +3,59 50 % 45 % −5

Bewertung der Ergebnisse:

Live-Pipeline (Phase 7.1c)

brightsky_poller.py (unverändert, cron 30 *)
  └─ rhein_forecast.weather_forecast (DWD-ICON-Forecast 0-72h, Live)

arx_worms_v6.py (einmaliger Lauf, 2026-05-06)
  Train 2018-2024 mit TIGGE-Reforecast-Features
  → /app/data/worms_arx_v6_models.pkl (42 kB, 10 Lead-Modelle)

forecast_cron_v6.py (cron 25 *, parallel zu v5 cron 20 *)
  Past-Niederschlag aus rhein_raw.weather (gleicher Code wie v5)
  Future-Niederschlag aus rhein_forecast.weather_forecast (Brightsky-DWD-ICON live)
  → rhein_forecast.worms_arx_v6_forecast (Lead 1..72 h)

Cron-Slot 25 statt 20, damit v5 und v6 parallel laufen — Vergleich der Live-Vorhersagen ist im Dashboard möglich.

Status (2026-05-06)

Verwandte Dashboards