You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add wavelet-transform support alongside the STFT toolkit, without compromising the focus or identity of ruststft. This is purely additive: no changes to the existing STFT code are required.
Background
Wavelets are a different time-frequency tool from the STFT (fixed window) - they give multi-resolution analysis (variable window per scale). Two distinct transforms, with two distinct engines:
Fast implementation is frequency-domain: ifft(fft(signal) * conj(psi_hat(scale * omega))) per scale.
Reuses our FFT backend, but Morlet is complex-valued, so it needs a full complex FFT (not realfft's real-to-complex). rustfft is already a transitive dependency via realfft; promote it to a direct dependency for CWT, or mirror the realfft output into a full Hermitian spectrum.
New pieces: mother-wavelet definitions (analytic psi_hat in the frequency domain), a scale-set generator (log/linear, voices-per-octave), a Scalogram container, cone-of-influence, and admissibility normalization.
Reuses almost nothing from the STFT path - no FFT, it is filter-bank convolution plus decimation.
New pieces: filter-tap tables (db1..dbN, sym, coif, bior - sizeable const data for PyWavelets parity), boundary modes (symmetric/periodic/zero/reflect - a superset of our PadMode), level math, a jagged WaveletCoeffs container, the inverse filter bank (upsample + reconstruction filters), and perfect-reconstruction tests.
Optional extensions: wavelet packet transform (WPT), and undecimated/stationary transform (SWT/MODWT).
What carries over from ruststft
The Sample trait, the no_std + alloc patterns, feature-gating conventions, and CI/tooling.
The error type (rename StftError to a crate-wide error, or add variants in the new crate).
The "coefficient table + cached metadata" pattern (Window) maps cleanly to a WaveletFilter holding decomposition/reconstruction taps.
The FFT-convolution machinery, for the CWT only.
Proposed architecture (the key decision)
Prefer a workspace split over bolting wavelets onto the STFT crate's name:
Extract a small dsp-core crate: Sample, the shared error type, and FFT helpers.
Keep ruststft focused on STFT/ISTFT.
Add a new sibling crate (e.g. ruswt) for wavelets, depending on dsp-core.
This keeps independent versioning and a clean identity. The alternative - rebranding ruststft into a general time-frequency crate with stft + wavelet feature-modules - is awkward under the current name and would mean another breaking rename.
Dependency / backend deltas
CWT: a direct rustfft dependency (complex FFT). DWT: none (pure FIR).
Filter tables embedded as const arrays (keeps no_std support).
Parity targets: PyWavelets (pywt) for the DWT, ssqueezepy / scipy for the CWT (note scipy.signal.cwt is deprecated).
Task checklist
Workspace refactor: extract dsp-core (Sample, error, FFT helpers); make ruststft depend on it.
New wavelet crate scaffold (features, CI, no_std, forbid(unsafe_code)).
Goal
Add wavelet-transform support alongside the STFT toolkit, without compromising the focus or identity of
ruststft. This is purely additive: no changes to the existing STFT code are required.Background
Wavelets are a different time-frequency tool from the STFT (fixed window) - they give multi-resolution analysis (variable window per scale). Two distinct transforms, with two distinct engines:
CWT (continuous wavelet transform)
ifft(fft(signal) * conj(psi_hat(scale * omega)))per scale.rustfftis already a transitive dependency viarealfft; promote it to a direct dependency for CWT, or mirror the realfft output into a full Hermitian spectrum.psi_hatin the frequency domain), a scale-set generator (log/linear, voices-per-octave), aScalogramcontainer, cone-of-influence, and admissibility normalization.DWT (discrete wavelet transform, Mallat algorithm)
constdata for PyWavelets parity), boundary modes (symmetric/periodic/zero/reflect - a superset of ourPadMode), level math, a jaggedWaveletCoeffscontainer, the inverse filter bank (upsample + reconstruction filters), and perfect-reconstruction tests.What carries over from
ruststftSampletrait, theno_std+allocpatterns, feature-gating conventions, and CI/tooling.StftErrorto a crate-wide error, or add variants in the new crate).Window) maps cleanly to aWaveletFilterholding decomposition/reconstruction taps.Proposed architecture (the key decision)
Prefer a workspace split over bolting wavelets onto the STFT crate's name:
dsp-corecrate:Sample, the shared error type, and FFT helpers.ruststftfocused on STFT/ISTFT.ruswt) for wavelets, depending ondsp-core.This keeps independent versioning and a clean identity. The alternative - rebranding
ruststftinto a general time-frequency crate withstft+waveletfeature-modules - is awkward under the current name and would mean another breaking rename.Dependency / backend deltas
rustfftdependency (complex FFT). DWT: none (pure FIR).constarrays (keepsno_stdsupport).pywt) for the DWT,ssqueezepy/scipyfor the CWT (notescipy.signal.cwtis deprecated).Task checklist
dsp-core(Sample, error, FFT helpers); makeruststftdepend on it.no_std,forbid(unsafe_code)).Scalogram, cone-of-influence, normalization.WaveletCoeffs.Effort