A fast, comprehensive wavelet transform library for the Odin programming language, inspired by PyWavelets.
- Haar - Simplest wavelet, fast computation
- Daubechies (db1-db10) - Widely used orthogonal wavelets
- Symlets (sym2-sym8) - Near-symmetric wavelets
- Coiflets (coif1-coif4) - Wavelets with vanishing moments
- 1D DWT/IDWT - Discrete Wavelet Transform for f32 and complex64
- 2D DWT/IDWT - 2D transform for image processing
- Multi-level decomposition -
wavedec/waverecfor full decomposition - SWT - Stationary (Undecimated) Wavelet Transform
- CWT - Continuous Wavelet Transform with Morlet and Mexican Hat wavelets
- Denoising - Wavelet-based signal denoising with hard/soft thresholding
- Thresholding - Hard, soft, and garrote thresholding
- Noise estimation - MAD-based noise level estimation
- Zero, Constant, Symmetric, Reflect, Periodic, Smooth, Antisymmetric
import wv "wavelets"
main :: proc() {
// Create a wavelet
wavelet, ok := wv.get_wavelet("db4")
if !ok do return
defer wv.destroy_wavelet(&wavelet)
// Your signal
signal := []f32{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0}
// Single-level DWT
coeffs := wv.dwt(signal, wavelet)
defer delete(coeffs.approx)
defer delete(coeffs.detail)
// Reconstruct
reconstructed := wv.idwt(coeffs, wavelet, len(signal))
defer delete(reconstructed)
}import wv "wavelets"
// Full decomposition
result := wv.wavedec(signal, wavelet, 4) // 4 levels
defer wv.destroy_wavedec_result(&result)
// result.coeffs[0] = approximation coefficients (cA)
// result.coeffs[1..] = detail coefficients (cD) from coarse to fine
// Reconstruction
reconstructed := wv.waverec(result, wavelet)
defer delete(reconstructed)import wv "wavelets"
// image is [][]f32
coeffs := wv.dwt2(image, wavelet)
defer wv.destroy_coeffs_2d(&coeffs)
// coeffs.approx = LL (approximation)
// coeffs.horiz = LH (horizontal detail)
// coeffs.vert = HL (vertical detail)
// coeffs.diag = HH (diagonal detail)
// Reconstruct
reconstructed := wv.idwt2(coeffs, wavelet, {rows, cols})import wv "wavelets"
// Works with complex64 (real: f32, imag: f32)
complex_signal := make([]wv.Complex64, n)
for i in 0..<n {
complex_signal[i] = complex(real_part, imag_part)
}
coeffs := wv.dwt_complex(complex_signal, wavelet)
reconstructed := wv.idwt_complex(coeffs, wavelet, len(complex_signal))import wv "wavelets"
// Automatic wavelet denoising
denoised := wv.denoise(noisy_signal, wavelet, 4, .Symmetric, .Soft)
defer delete(denoised)
// Manual thresholding
wv.threshold(coefficients, threshold_value, .Soft)import wv "wavelets"
// Generate scales
scales := wv.log_scales(1, 64, 32) // 32 scales from 1 to 64
defer delete(scales)
// Morlet CWT
result := wv.cwt_morlet(signal, scales)
defer wv.destroy_cwt_result(&result)
// result.coefficients[scale][time] contains complex coefficientsimport wv "wavelets"
// SWT (signal length must be power of 2)
result := wv.swt(signal, wavelet, 3) // 3 levels
defer wv.destroy_swt_result(&result)
// result.levels[i].approx and result.levels[i].detail
// All have same length as original signal# Build everything
make all
# Run tests
make run-test
# Run benchmarks
make run-bench
# Run comparison with PyWavelets
make run-comp
# Build with debug symbols
make debug
# Clean
make cleanget_wavelet(name) -> (Wavelet, bool)- Create wavelet by namedestroy_wavelet(wavelet)- Free wavelet resourceslist_wavelets() -> []string- List available wavelets
dwt(signal, wavelet, mode) -> Coeffs_1D- Single-level DWTidwt(coeffs, wavelet, length) -> []f32- Single-level IDWTwavedec(signal, wavelet, level, mode) -> Wavedec_Result- Multi-level decompositionwaverec(result, wavelet) -> []f32- Multi-level reconstructiondwt_max_level(data_len, filter_len) -> int- Maximum decomposition level
dwt2(image, wavelet, mode) -> Coeffs_2D- 2D DWTidwt2(coeffs, wavelet, shape) -> [][]f32- 2D IDWT
swt(signal, wavelet, level) -> SWT_Result- Stationary DWTiswt(result, wavelet) -> []f32- Inverse SWT
cwt_morlet(signal, scales, omega0) -> CWT_Result- Morlet CWTcwt_mexican_hat(signal, scales) -> [][]f32- Mexican Hat CWTlog_scales(min, max, num) -> []f32- Generate logarithmic scaleslinear_scales(min, max, num) -> []f32- Generate linear scales
denoise(signal, wavelet, level, mode, thresh_type) -> []f32- Wavelet denoisingthreshold(data, thresh, type)- Apply thresholdingestimate_noise_std(coeffs) -> f32- Estimate noise level
energy(signal) -> f32- Signal energyrms(signal) -> f32- Root mean squaresnr_db(original, noisy) -> f32- Signal-to-noise ratiopad_to_power2(signal) -> ([]f32, original_len)- Pad to power of 2
The library achieves perfect reconstruction (errors at floating-point precision limit ~1e-7) for all wavelet transforms.
Both libraries achieve identical reconstruction accuracy:
| Test | Odin Library | PyWavelets | Status |
|---|---|---|---|
| DWT/IDWT Reconstruction | 2.38e-07 to 5.96e-07 | 1.19e-07 to 4.77e-07 | ✓ Match |
| Multi-level (5 levels) | 5.96e-07 to 8.34e-07 | 5.36e-07 to 7.15e-07 | ✓ Match |
| 2D DWT/IDWT | 1.79e-07 to 4.17e-07 | ~3e-07 | ✓ Match |
| Complex DWT | 1.33e-07 to 2.40e-07 | ~2e-07 | ✓ Match |
| Energy Conservation | <2% deviation | <2% deviation | ✓ Match |
| Linearity | 4.77e-07 to 9.54e-07 | ~5e-07 | ✓ Match |
| Wavelet | Odin (MS/s) | PyWavelets (MS/s) | Ratio |
|---|---|---|---|
| Haar | 583 | 1304 | 2.2x |
| Db4 | 385 | 630 | 1.6x |
| Sym4 | 387 | 630 | 1.6x |
MS/s = Million Samples per second
With optimized build flags (-o:speed -disable-assert -no-bounds-check), the Odin library achieves 60-65% of PyWavelets performance. PyWavelets uses a highly optimized C backend with SIMD vectorization.
# Run comprehensive comparison test
make run-comp
# This runs:
# 1. Odin library validation (49 tests, 100% pass rate)
# 2. PyWavelets benchmark (requires Python + pywavelets)| Family | Names | Filter Lengths |
|---|---|---|
| Haar | haar, db1 | 2 |
| Daubechies | db2-db10 | 4-20 |
| Symlets | sym2-sym8 | 4-16 |
| Coiflets | coif1-coif4 | 6-24 |
MIT License