Sparse non-negative Weibull deconvolution of offshore wind-speed distributions — FISTA and trust-region (TRAIn) solvers, in MATLAB and Python.
A single two-parameter Weibull law is the default description of wind-speed statistics, but offshore and coastal records routinely superpose several meteorological regimes that one law cannot represent. This repository represents the observed wind-speed density as a continuous non-negative superposition of Weibull atoms over a compact shape–scale domain and recovers the mixing measure by regularized inversion of the associated compact operator. Two complementary solvers are provided:
- FISTA — a convex, positive ℓ¹-regularized fast iterative shrinkage–thresholding algorithm that returns compact regime maps.
- TRAIn — a trust-region Gauss–Newton scheme in the squared-amplitude
parametrization
h = η², whose single regularization parameter is selected automatically per record by an L-curve criterion.
The code reproduces every table and figure of the companion paper. The MATLAB and Python implementations are independent and cross-validate each other to numerical tolerance.
At the bimodal northern Gulf of California site, forcing a single Weibull law onto the record underestimates the annual energy of a 15 MW reference turbine by 2.5 GWh yr⁻¹ (−6.6 %). The deconvolved mixture recovers the correct energy, identifies the number and location of the wind regimes through a convex programme (no pre-fixed component count), and yields a parameter map that is closed under linear flow acceleration — so one fitted map is reusable, without re-estimation, for the design of diffuser-augmented turbines and other wind-conditioning structures.
Two hourly MERRA-2 wind-speed records at 50 m, 2014–2023 (87,648 observations each), off Baja California:
| Site | Location | Character |
|---|---|---|
| N30 | 30.000° N, 114.375° W — northern Gulf of California | bimodal (seasonally alternating regimes) |
| N29 | 29.000° N, 115.625° W — Pacific side, off Punta Eugenia | near-unimodal (steady California Current winds) |
The two quality-controlled CSV slices are in MATLAB/data/ and
are shared by both implementations. Source: NASA GMAO MERRA-2 M2T1NXSLV
collection, redistributed here under the
NASA GES DISC open-data policy.
weibull-wind-deconvolution/
├── MATLAB/ Reference MATLAB implementation
│ ├── WeibullMixtureApp.m core class (dictionary, FISTA, TRAIn, export, GUI)
│ ├── run_weibull_deconvolution.m batch driver for both sites
│ ├── run_reproducible_analysis.m full paper-results rebuild
│ ├── analizar_distribuciones_viento.m empirical + classical Weibull fit
│ ├── data/ the two MERRA-2 CSV slices
│ ├── results/ reference numerical outputs (CSV)
│ └── tests/ MATLAB unit tests
├── PYTHON/ Independent Python port (package weibull_deconv)
│ ├── weibull_deconv/ config, data, dictionary, fista, train,
│ │ autotermfac, mle, mixture2, windfarm, …
│ ├── run_deconvolution.py batch driver (mirror of the MATLAB one)
│ ├── run_auto_termfac_results.py FISTA + auto-termFac TRAIn, full results
│ ├── run_case_study.py turbine energy yield + flow-purification study
│ ├── requirements.txt
│ └── tests/ parity + unit tests
└── docs/overview.png
Note on paths. The folder names
MATLABandPYTHONare case-sensitive: the Python scripts read the shared data from../MATLAB/data. Keep the names as-is on case-sensitive file systems.
cd PYTHON
pip install -r requirements.txt # numpy, scipy, matplotlib (Python ≥ 3.10)
python run_auto_termfac_results.py # FISTA + auto-termFac TRAIn on both sites
python run_case_study.py # 15 MW turbine energy yield + purification
python -m pytest tests/ -q # or: python tests/test_against_matlab.pyProgrammatic use:
from datetime import datetime, timezone
from weibull_deconv import default_config, fit, load_wind_file
data = load_wind_file(
"../MATLAB/data/Wind_MERRA2_N30_000_W114_375_2014_2023.csv",
start_date=datetime(2014, 1, 1, tzinfo=timezone.utc),
end_date=datetime(2023, 12, 31, tzinfo=timezone.utc))
cfg = default_config("article") # TRAIn termFac selected automatically
cfg["alpha_rel"] = 0.03 # FISTA ℓ¹ strength for N30
result = fit(data.speed, cfg)
print(result["solvers"]["FISTA"]["components"][0]) # dominant (κ, λ) cell
print(result["solvers"]["TRAIn"]["term_fac_selected"])cd MATLAB
salida = run_weibull_deconvolution; % FISTA + TRAIn on N30 and N29
app = WeibullMixtureApp; % interactive GUI (optional)
results = runtests('tests'); assertSuccess(results)| FISTA | TRAIn | |
|---|---|---|
| Objective | convex, positive ℓ¹-regularized | non-convex, unpenalized NNLS in h = η² |
| Regularization | explicit ℓ¹ (α), chronologically tuned |
trust-region reference-target factor termFac, auto-selected in [1, 2] by an L-curve |
| Dictionary | 1,353 L²-normalized Weibull atoms | 4,452-atom enlarged grid |
| Reported role | compact, interpretable regime map | high-fidelity positive reconstruction |
The deconvolution is deliberately reported with predictive fit, sparsity and physical identifiability as separate claims. A year-block bootstrap (200 replicates) confirms the dominant regime cell is stable under decadal sampling variability; the high dictionary coherence means individual atoms are not uniquely identifiable and are reported as resolution cells.
Both implementations regenerate all numerical outputs from the packaged data.
The Python test suite validates the port against the MATLAB reference outputs
in MATLAB/results/batch_deconvolution/BOTH/ (classical MLE, FISTA metrics,
effective support and dominant cells agree to tolerance; TRAIn converges to the
same reference-target neighborhood). The automatic termFac selector agrees
between the two languages to within 0.006.
If you use this code or data, please cite the companion paper (see
CITATION.cff):
Robalo-Cabrera, I.; López-Lao, E.; Alcayde, A.; Zapata-Sierra, A.; Arrabal-Campos, F. M.*; Manzano-Agugliaro, F.* Sparse Non-negative Weibull Deconvolution of Offshore Wind-Speed Distributions: A Hilbert–Banach formulation with FISTA and trust-region inversion. University of Almería. (* corresponding authors)
Code: MIT. Data: NASA GES DISC open-data policy (see above).
