use core::f32::consts::PI;
#[derive(Clone, Copy)]
pub enum WindowFunctionType {
Hann,
Welch,
}
pub fn apply_window_function(window_function: WindowFunctionType, buffer: &mut [f32]) {
match window_function {
WindowFunctionType::Hann => hann_window(buffer),
WindowFunctionType::Welch => welch_window(buffer),
}
}
fn hann_window(buffer: &mut [f32]) {
let a = 0.5 * (PI / 2. - 1.5);
let b = 0.5 * (2.5 - PI);
let c = 0.5 * PI / 2.;
let d = 0.5;
let len = buffer.len();
let dx = 4. / ((len - 1) as f32);
let len_is_even = len % 2 == 0;
let left_half_end_len = if len_is_even { len / 2 } else { len / 2 + 1 };
let mut x = -1.0;
for value in buffer.iter_mut().take(left_half_end_len) {
let x3 = x * x * x;
let x5 = x3 * x * x;
let window_value = a * x5 + b * x3 + c * x + d;
*value *= window_value;
x += dx;
}
x = if len_is_even {
1.0 - 0.5 * dx
} else {
1.0 - dx
};
for value in buffer.iter_mut().skip(left_half_end_len) {
let x3 = x * x * x;
let x5 = x3 * x * x;
let window_value = a * x5 + b * x3 + c * x + d;
*value *= window_value;
x -= dx;
}
}
fn welch_window(buffer: &mut [f32]) {
if buffer.len() < 2 {
for value in buffer.iter_mut() {
*value = 0.0;
}
return;
}
let len = buffer.len();
let dx = 2. / ((len - 1) as f32);
for (i, value) in buffer.iter_mut().enumerate() {
let x = -1.0 + dx * (i as f32);
let window_value = 1. - x * x;
*value *= window_value;
}
}
#[cfg(test)]
mod tests {
use crate::common::window_function::{hann_window, welch_window};
use alloc::vec;
use core::f32::consts::PI;
#[test]
fn test_hann_window() {
let hann_exact = |n: usize, size: usize| -> f32 {
if n == 0 {
return 0.0;
}
let sin = (PI * (n as f32) / ((size - 1) as f32)).sin();
sin * sin
};
let eps = 0.0003;
for window_size in [1, 2, 128, 4096, 100000] {
let mut window = vec![1.0; window_size];
hann_window(&mut window);
for (i, value_approx) in window.iter().enumerate() {
let exact_value = hann_exact(i, window.len());
let error = (exact_value - value_approx).abs();
assert!(error < eps);
}
}
}
#[test]
fn test_welch_window() {
let welch_exact = |n: usize, size: usize| -> f32 {
if size < 2 {
return 0.0;
}
let x = -1.0 + 2.0 * (n as f32) / ((size - 1) as f32);
1.0 - x * x
};
let eps = 1e-6;
for window_size in [1, 2, 128, 4096, 100000] {
let mut window = vec![1.0; window_size];
welch_window(&mut window);
for (i, value_approx) in window.iter().enumerate() {
let exact_value = welch_exact(i, window.len());
let error = (exact_value - value_approx).abs();
assert!(error < eps);
}
}
}
}