dasp_rs/features/
manipulation.rs1use ndarray::{Array1, Array2, Axis};
2
3pub fn delta(
21    data: &Array2<f32>,
22    width: Option<usize>,
23    order: Option<usize>,
24    axis: Option<isize>,
25) -> Array2<f32> {
26    let width = width.unwrap_or(9);
27    let order = order.unwrap_or(1);
28    let axis = axis.unwrap_or(-1);
29    let mut result = data.to_owned();
30    for _ in 0..order {
31        let mut delta = Array2::zeros(result.dim());
32        let half_width = width / 2;
33        let weights: Vec<f32> = (1..=half_width).map(|i| i as f32).collect();
34        let norm = weights.iter().map(|x| x.powi(2)).sum::<f32>();
35        for i in 0..result.shape()[axis.unsigned_abs()] {
36            let slice = result.index_axis(Axis(axis.unsigned_abs()), i);
37            for j in 0..slice.len() {
38                let mut sum = 0.0;
39                for w in 0..weights.len() {
40                    let left = (j as isize - w as isize - 1).max(0) as usize;
41                    let right = (j + w + 1).min(slice.len() - 1);
42                    sum += weights[w] * (slice[right] - slice[left]);
43                }
44                delta[[if axis < 0 { j } else { i }, if axis < 0 { i } else { j }]] = sum / norm;
45            }
46        }
47        result = delta;
48    }
49    result
50}
51
52pub fn stack_memory(
69    data: &Array2<f32>,
70    n_steps: Option<usize>,
71    delay: Option<usize>,
72) -> Array2<f32> {
73    let n_steps = n_steps.unwrap_or(2);
74    let delay = delay.unwrap_or(1);
75    let n_frames = data.shape()[1];
76    let n_features = data.shape()[0];
77    let mut stacked = Array2::zeros((n_features * n_steps, n_frames));
78    for step in 0..n_steps {
79        let offset = step * delay;
80        for t in 0..n_frames {
81            let src_t = (t as isize - offset as isize).max(0) as usize;
82            for f in 0..n_features {
83                stacked[[f + step * n_features, t]] = data[[f, src_t]];
84            }
85        }
86    }
87    stacked
88}
89
90pub fn temporal_kurtosis(
112    y: Option<&[f32]>,
113    S: Option<&Array2<f32>>,
114    frame_length: Option<usize>,
115    hop_length: Option<usize>,
116) -> Array1<f32> {
117    let frame_len = frame_length.unwrap_or(2048);
118    let hop = hop_length.unwrap_or(frame_len / 4);
119    match (y, S) {
120        (Some(y), None) => {
121            let n_frames = (y.len() - frame_len) / hop + 1;
122            let mut kurtosis = Array1::zeros(n_frames);
123            for i in 0..n_frames {
124                let start = i * hop;
125                let frame = &y[start..(start + frame_len).min(y.len())];
126                let mean = frame.iter().sum::<f32>() / frame.len() as f32;
127                let m2 = frame.iter().map(|&x| (x - mean).powi(2)).sum::<f32>() / frame.len() as f32;
128                let m4 = frame.iter().map(|&x| (x - mean).powi(4)).sum::<f32>() / frame.len() as f32;
129                kurtosis[i] = if m2 > 1e-10 { m4 / m2.powi(2) - 3.0 } else { 0.0 };
130            }
131            kurtosis
132        }
133        (None, Some(S)) => S.axis_iter(Axis(1)).map(|frame| {
134            let mean = frame.mean().unwrap_or(0.0);
135            let m2 = frame.mapv(|x| (x - mean).powi(2)).mean().unwrap_or(0.0);
136            let m4 = frame.mapv(|x| (x - mean).powi(4)).mean().unwrap_or(0.0);
137            if m2 > 1e-10 { m4 / m2.powi(2) - 3.0 } else { 0.0 }
138        }).collect(),
139        _ => panic!("Must provide either y or S"),
140    }
141}
142
143pub fn zero_crossing_rate(
161    y: &[f32],
162    frame_length: Option<usize>,
163    hop_length: Option<usize>,
164) -> Array1<f32> {
165    let frame_len = frame_length.unwrap_or(2048);
166    let hop = hop_length.unwrap_or(frame_len / 4);
167    let n_frames = (y.len() - frame_len) / hop + 1;
168    let mut zcr = Array1::zeros(n_frames);
169    for i in 0..n_frames {
170        let start = i * hop;
171        let slice = &y[start..(start + frame_len).min(y.len())];
172        let count = slice.windows(2).filter(|w| w[0] * w[1] < 0.0).count();
173        zcr[i] = count as f32 / frame_len as f32;
174    }
175    zcr
176}