microspectrogram 0.1.0

A simple `no_std` library for computing spectrograms.
Documentation
use core::f32::consts::PI;
#[allow(unused_imports)]
use num_traits::real::Real;

use crate::utils::linspace;

#[derive(Clone, Copy)]
pub enum Window {
    Hann,
}

pub fn get_window<const N: usize>(win: Window, sym: bool) -> [f32; N]
where
    [(); N + 1]: Sized,
{
    use Window::*;
    match win {
        Hann => {
            let alpha = 0.5;
            let a = [alpha, 1. - alpha];
            let mut w = [0.0; N];
            (0..a.len()).for_each(|i| {
                if sym {
                    let fac = linspace::<N>(-PI, PI);
                    w.iter_mut().zip(fac).for_each(|(iw, f)| {
                        *iw += a[i] * (i as f32 * f).cos();
                    });
                } else {
                    let fac = linspace::<{ N + 1 }>(-PI, PI);
                    w.iter_mut().zip(fac).for_each(|(iw, f)| {
                        *iw += a[i] * (i as f32 * f).cos();
                    });
                };
            });
            w
        }
    }
}

#[cfg(test)]
mod test {
    use core::ops;

    use num_traits::ToPrimitive;

    use super::*;

    fn all_close<T, const N: usize>(a: &[T; N], b: &[T; N]) -> bool
    where
        T: ops::Sub<Output = T> + ToPrimitive + Copy,
    {
        const EPSILON: f32 = 1e-5;
        for i in 0..N {
            if (a[i] - b[i]).to_f32().unwrap() > EPSILON {
                return false;
            }
        }
        true
    }

    #[test]
    #[allow(clippy::excessive_precision)]
    fn test_window_hann() {
        assert!(all_close(
            &get_window(Window::Hann, true),
            &[0., 0.75, 0.75, 0.]
        ));
        assert!(all_close(
            &get_window(Window::Hann, false),
            &[0., 0.5, 1., 0.5]
        ));
    }
}