Can a machine-learning model predict turbulent wind pressures on tall buildings 0.5 seconds ahead? We trained 10+ models on 340 wind-tunnel series and found the answer is nuanced - and spectrally critical.
Three progressive training rounds - single building -> 5 geometries -> 340 series.
20 building aspect ratios x multiple yaw angles x 2 terrain roughness profiles (alpha = 1/4 and 1/6). Each series: 32 768 samples at 1 000 Hz.
Identical 70/15/15 split, same seed, optimiser, batch size and hardware across all models. Differences are model differences only.
Point metrics (RMSE, R2) -> statistical significance (Diebold-Mariano) -> spectral fidelity (Welch PSD). Each layer changes the ranking.
MSE-trained models collapse to the conditional mean at h = 500. Predicted PSD is 60-75x smaller than the true signal PSD - the critical finding for wind engineering.
Progressively broader scope to test generalisation.
RMSE and R2 at step h = 500, aggregated over the full 146,880-window test set (denormalised windward Cp) - the same regime for every model. An earlier single-trajectory evaluation inflated the naive baseline (RMSE 0.118 / R2 0.97) and the deep-model "collapse" (R2 -6.18); those were measurement artifacts. Lower RMSE = better; R2 closer to 1 = better. Classical rows re-fit at window-stride 40; naive shown is the 680-trajectory value (the exact 146,880-window naive is 0.231, which the direct models also beat).
| Model | Paradigm | RMSE h=1 | RMSE h=500 | R2 h=500 | vs Naive (DM p) | Status |
|---|---|---|---|---|---|---|
| Naive persistence | - | 0.0314 | 0.218 | 0.77 | - | Baseline |
| Ridge | Autoreg | 0.0218 | 0.281 | 0.62 | p < 0.001 (naive wins) | Underperforms |
| Random Forest | Autoreg | 0.0264 | 0.212 | 0.78 | beats naive (DM +11.2) | Beats naive |
| XGBoost | Autoreg | 0.0236 | 0.217 | 0.77 | statistical tie with naive | Ties naive |
| LSTM | Autoreg | 0.0246 | 0.270 | 0.65 | beats naive on 44% of traj. | Competitive |
| GRU | Autoreg | 0.0245 | 0.273 | 0.64 | beats naive on 47% of traj. | Competitive |
| TCN | Autoreg | 0.0186 | 0.411 | 0.19 | p < 0.001 (naive wins) | Unstable |
| LSTM-direct (B.4) | Direct multi-step | 0.0404 | 0.179 | 0.84 | beats naive | Best R2 |
| PatchTST (C.6) | Direct multi-step | 0.0427 | 0.175 | 0.85 | beats naive | Best R2 |
All autoregressive / classical rows use the corrected 680-trajectory regime; direct models use the full 146,880-window test set. The exact tree-vs-naive margin is sensitive to training-set size. High R2 at h = 500 does not mean spectral fidelity. See Spectral Findings.
Four take-aways that change how practitioners should evaluate wind-pressure forecasters.
h = 1 is essentially solved. Every reasonable model (R3) reaches RMSE ~ 0.04 and R2 > 0.99. Single-step metrics are no longer a useful differentiator.
Over 680 trajectories, the tree-based models sit right at naive level at h = 500 - Random Forest (0.212) marginally beats naive (0.218), XGBoost (0.217) ties it; the margin moves with training-set size, i.e. the trees hit the predictability ceiling around persistence rather than clearing it. Autoregressive LSTM/GRU reach R2 ~ 0.64-0.65 (not the catastrophic R2 = -6.18 of the single-trajectory artifact); Ridge stays stable (0.281, no divergence). Only TCN genuinely destabilises (R2 = 0.19).
Replacing the output head with Linear(128 -> 500) + full-vector MSE loss recovers R2 = 0.84-0.85 at h = 500. Two radically different architectures (LSTM-direct and PatchTST) converge to the same ceiling - confirming it is not architectural.
The predicted PSD is 60-75x smaller than the true signal PSD at every frequency above 4 Hz. MSE-trained models output the conditional mean - the spectrum collapses. R2 = 0.85 is misleading for applications requiring spectral fidelity (fatigue, peak-factor, gust-effect factor). WPTSE-Net (synthesis, Huber loss) recovers 79 % of true spectral power.
Input: 100-sample (100 ms) windows of 4 face-averaged Cp channels. Target: windward Cp at horizons 1, 10, 50, 100, 500 ms.
| Family | Model | Parameters (R3) | Train time | Best val MSE |
|---|---|---|---|---|
| Classical | Ridge | 401 | 1 s | 0.00238 |
| Classical | XGBoost | 500 trees | 69 s | 0.00305 |
| Classical | Random Forest | 200 trees | 7 262 s | 0.00281 |
| Deep | Autoreg | LSTM | 827 649 | 46 min | 0.00294 |
| Deep | Autoreg | GRU | 628 993 | 38 min | 0.00290 |
| Deep | Autoreg | TCN | 459 073 | 2.4 h | 0.00166 |
| Deep | Direct | LSTM-direct | ~830 k | ~45 min | 0.1440 |
| Deep | Direct | PatchTST | 1 111 924 | 71 min | 0.1406 |
| Synthesis | WPTSE-Net | 122 528 | 32 min | - |
Hardware: NVIDIA RTX A4000 16 GB | CUDA 11.8 | PyTorch 2.7.1 | Adam lr=1e-3 | batch 256 | seed 42.