modewise_emd/
lib.rs

1//! Empirical mode decomposition, per channel (EMD) and multivariate (MEMD), on one sifting
2//! engine. Sources and choices are in docs/emd.md.
3
4mod boundary;
5mod decomposers;
6mod directions;
7mod ensemble;
8mod extrema;
9mod layout;
10mod sift;
11mod spline;
12
13pub use decomposers::{Emd, Memd};
14pub use ensemble::{Ceemdan, Eemd};
15pub use sift::Stop;
16
17#[doc(hidden)]
18pub mod testing {
19    //! Internals exposed for accuracy tests against scipy and PyEMD.
20
21    /// Knot positions and sample indices of the lower and upper envelopes, or `None`.
22    pub type Mirrored = ((Vec<f64>, Vec<usize>), (Vec<f64>, Vec<usize>));
23
24    pub fn mirror(indmin: &[usize], indmax: &[usize], x: &[f64]) -> Option<Mirrored> {
25        let (lo, hi) = crate::boundary::mirror(indmin, indmax, x).ok()?;
26        Some(((lo.positions, lo.samples), (hi.positions, hi.samples)))
27    }
28
29    /// EEMD and CEEMDAN of one channel with given noise realisations: (IMFs, residual).
30    pub fn eemd(
31        x: &[f64],
32        noises: &[Vec<f64>],
33        stop: crate::Stop,
34        max_imfs: usize,
35    ) -> (Vec<Vec<f64>>, Vec<f64>) {
36        let noises: Vec<_> = noises
37            .iter()
38            .map(|w| ndarray::Array1::from(w.clone()))
39            .collect();
40        let (imfs, r) =
41            crate::ensemble::eemd_channel(ndarray::ArrayView1::from(x), &noises, stop, max_imfs);
42        (imfs.into_iter().map(|m| m.to_vec()).collect(), r.to_vec())
43    }
44
45    pub fn ceemdan(
46        x: &[f64],
47        noises: &[Vec<f64>],
48        stop: crate::Stop,
49        epsilon: f64,
50        max_imfs: Option<usize>,
51    ) -> (Vec<Vec<f64>>, Vec<f64>) {
52        let noises: Vec<_> = noises
53            .iter()
54            .map(|w| ndarray::Array1::from(w.clone()))
55            .collect();
56        let (imfs, r) = crate::ensemble::ceemdan_channel(
57            ndarray::ArrayView1::from(x),
58            &noises,
59            stop,
60            epsilon,
61            max_imfs,
62        );
63        (imfs.into_iter().map(|m| m.to_vec()).collect(), r.to_vec())
64    }
65
66    pub fn centroid_hz(rows: ndarray::ArrayView2<f64>, fs_hz: f64) -> f64 {
67        modewise_fourier::centroid_hz(rows, fs_hz)
68    }
69
70    pub fn spline(
71        knots: &[f64],
72        values: ndarray::ArrayView2<f64>,
73        n: usize,
74    ) -> ndarray::Array2<f64> {
75        crate::spline::interpolate(knots, values, n)
76    }
77}