FerroWave · reference

Multi-resolution analysis

Reference for the multi-resolution decomposition and reconstruction API in ferro-wave.

Multi-resolution analysis (MRA) decomposes a signal into a coarse approximation and a stack of detail bands at successively finer scales. ferro-wave exposes both the analysis and synthesis sides of the MRA so a caller can decompose, filter or zero out specific bands, and reconstruct.

The decomposition

For a signal xRNx \in \mathbb{R}^N with N=2JN = 2^J, the level-JJ DWT produces

x=aJ+j=1Jdjx = a_J + \sum_{j=1}^{J} d_j

where aJa_J is the approximation at the coarsest scale and each djd_j is the detail band capturing variation at scale 2j2^j. The bands are orthogonal under the chosen wavelet's inner product, so

x2=aJ2+j=1Jdj2\|x\|^2 = \|a_J\|^2 + \sum_{j=1}^{J} \|d_j\|^2

This energy conservation is the assertion Mra::assert_energy_preserved checks in debug builds.

API surface

pub fn decompose(
    signal: &[f64],
    wavelet: Wavelet,
    levels: usize,
) -> Result<Mra, WaveError>;

impl Mra {
    pub fn approximation(&self) -> &[f64];
    pub fn details(&self) -> &[Band];
    pub fn reconstruct(&self) -> Vec<f64>;
    pub fn reconstruct_into(&self, out: &mut [f64]);
}

Inputs

  • signal — a slice whose length is a power of two. Pad with the padding module's reflect or symmetric padders if your data is not.
  • wavelet — any variant of the Wavelet enum.
  • levels — the number of decomposition levels JJ. Must satisfy 2JN2^J \le N.

Output

An Mra value owning the approximation and detail buffers. The struct is Send + Sync and contains no interior mutability — it is safe to share across threads for parallel band processing.

Selective reconstruction

Zero out a band before reconstruction to denoise or to isolate a frequency component:

let mut mra = decompose(&signal, Wavelet::Sym6, 6)?;
mra.zero_detail(1);            // strip the highest-frequency detail
let denoised = mra.reconstruct();

Reconstruction is exact (within f64f64 rounding) when no bands are modified — this is what makes the MRA a basis change rather than a lossy transform.

Errors

  • WaveError::InvalidLength — signal length is not a power of two.
  • WaveError::LevelTooDeeplevels exceeds log2N\log_2 N.
  • WaveError::EmptySignal — signal slice is empty.

The decomposition never panics on valid inputs and never allocates after the initial Mra buffer setup.