use crate::Sample;
use windowfunctions::{window, Symmetry, WindowFunction as ImportedWindowFunction};
#[derive(Debug, Clone, Copy)]
pub enum WindowFunction {
Blackman,
Blackman2,
BlackmanHarris,
BlackmanHarris2,
Hann,
Hann2,
}
pub fn blackman_harris<T>(npoints: usize) -> Vec<T>
where
T: Sample,
{
trace!("Making a BlackmanHarris windows with {} points", npoints);
window::<f64>(
npoints,
ImportedWindowFunction::BlackmanHarris,
Symmetry::Periodic,
)
.map(|v| T::coerce(v))
.collect()
}
pub fn blackman<T>(npoints: usize) -> Vec<T>
where
T: Sample,
{
trace!("Making a Blackman windows with {} points", npoints);
window::<f64>(
npoints,
ImportedWindowFunction::Blackman,
Symmetry::Periodic,
)
.map(|v| T::coerce(v))
.collect()
}
pub fn hann<T>(npoints: usize) -> Vec<T>
where
T: Sample,
{
trace!("Making a Hann windows with {} points", npoints);
window::<f64>(npoints, ImportedWindowFunction::Hann, Symmetry::Periodic)
.map(|v| T::coerce(v))
.collect()
}
pub fn make_window<T>(npoints: usize, windowfunc: WindowFunction) -> Vec<T>
where
T: Sample,
{
let mut window = match windowfunc {
WindowFunction::BlackmanHarris | WindowFunction::BlackmanHarris2 => {
blackman_harris::<T>(npoints)
}
WindowFunction::Blackman | WindowFunction::Blackman2 => blackman::<T>(npoints),
WindowFunction::Hann | WindowFunction::Hann2 => hann::<T>(npoints),
};
match windowfunc {
WindowFunction::Blackman2 | WindowFunction::BlackmanHarris2 | WindowFunction::Hann2 => {
window.iter_mut().for_each(|y| *y = *y * *y);
}
_ => {}
};
window
}
pub fn calculate_cutoff<T>(npoints: usize, windowfunc: WindowFunction) -> T
where
T: Sample,
{
let (k1, k2, k3) = match windowfunc {
WindowFunction::BlackmanHarris => (
T::coerce(8.041443677716476),
T::coerce(55.9506779343387),
T::coerce(898.0287985384213),
),
WindowFunction::BlackmanHarris2 => (
T::coerce(13.745202940783823),
T::coerce(121.73532586374934),
T::coerce(5964.163279612051),
),
WindowFunction::Blackman => (
T::coerce(6.159598046201173),
T::coerce(18.926415097606878),
T::coerce(653.4247430458968),
),
WindowFunction::Blackman2 => (
T::coerce(9.506235102129398),
T::coerce(79.13120634953742),
T::coerce(1502.2316160588925),
),
WindowFunction::Hann => (
T::coerce(3.3481080887677166),
T::coerce(10.106519434875038),
T::coerce(78.96345249024414),
),
WindowFunction::Hann2 => (
T::coerce(5.38751148378734),
T::coerce(29.69451915489501),
T::coerce(184.82117462266237),
),
};
let one = T::one();
let npoints_t = T::coerce(npoints);
one / (k1 / npoints_t
+ k2 / (npoints_t * npoints_t)
+ k3 / (npoints_t * npoints_t * npoints_t)
+ one)
}
#[cfg(test)]
mod tests {
extern crate approx;
use crate::windows::calculate_cutoff;
use crate::windows::make_window;
use crate::windows::WindowFunction;
use approx::assert_abs_diff_eq;
use test_log::test;
#[test]
fn test_blackman2() {
let wnd = make_window::<f64>(16, WindowFunction::Blackman);
let wnd2 = make_window::<f64>(16, WindowFunction::Blackman2);
assert_abs_diff_eq!(wnd[1] * wnd[1], wnd2[1], epsilon = 0.000001);
assert_abs_diff_eq!(wnd[4] * wnd[4], wnd2[4], epsilon = 0.000001);
assert_abs_diff_eq!(wnd[7] * wnd[7], wnd2[7], epsilon = 0.000001);
assert!(wnd2[1] > 0.000001);
assert!(wnd2[4] > 0.000001);
assert!(wnd2[7] > 0.000001);
}
#[test]
fn test_cutoff() {
let cutoff = calculate_cutoff::<f64>(128, WindowFunction::Blackman);
assert_abs_diff_eq!(cutoff, 0.953, epsilon = 0.001);
let cutoff = calculate_cutoff::<f64>(256, WindowFunction::Blackman);
assert_abs_diff_eq!(cutoff, 0.976, epsilon = 0.001);
let cutoff = calculate_cutoff::<f64>(128, WindowFunction::Blackman2);
assert_abs_diff_eq!(cutoff, 0.926, epsilon = 0.001);
let cutoff = calculate_cutoff::<f64>(256, WindowFunction::Blackman2);
assert_abs_diff_eq!(cutoff, 0.963, epsilon = 0.001);
let cutoff = calculate_cutoff::<f64>(128, WindowFunction::BlackmanHarris);
assert_abs_diff_eq!(cutoff, 0.937, epsilon = 0.001);
let cutoff = calculate_cutoff::<f64>(256, WindowFunction::BlackmanHarris);
assert_abs_diff_eq!(cutoff, 0.969, epsilon = 0.001);
let cutoff = calculate_cutoff::<f64>(128, WindowFunction::BlackmanHarris2);
assert_abs_diff_eq!(cutoff, 0.894, epsilon = 0.001);
let cutoff = calculate_cutoff::<f64>(256, WindowFunction::BlackmanHarris2);
assert_abs_diff_eq!(cutoff, 0.947, epsilon = 0.001);
let cutoff = calculate_cutoff::<f64>(128, WindowFunction::Hann);
assert_abs_diff_eq!(cutoff, 0.974, epsilon = 0.001);
let cutoff = calculate_cutoff::<f64>(256, WindowFunction::Hann);
assert_abs_diff_eq!(cutoff, 0.987, epsilon = 0.001);
let cutoff = calculate_cutoff::<f64>(128, WindowFunction::Hann2);
assert_abs_diff_eq!(cutoff, 0.958, epsilon = 0.001);
let cutoff = calculate_cutoff::<f64>(256, WindowFunction::Hann2);
assert_abs_diff_eq!(cutoff, 0.979, epsilon = 0.001);
}
}