use std::f32::consts::PI;
#[derive(PartialEq, Debug)]
pub struct Filter {
coeff: Vec<f32>,
}
impl Filter {
pub fn new(coeff: Vec<f32>) -> Self {
Filter { coeff }
}
pub fn len(&self) -> usize {
self.coeff.len()
}
pub fn filter_windowed(&self, signal: &Vec<f32>) -> Vec<f32> {
signal
.windows(self.coeff.len())
.map(|window| window.iter().zip(&self.coeff).map(|(x, y)| x * y).sum())
.collect()
}
pub fn create_moving_average(size: usize) -> Self {
let coefficients = vec![1.0 / size as f32; size];
Self {
coeff: coefficients,
}
}
pub fn create_srrc(n_half: usize, b: f32, m: usize) -> Self {
let mut srrc = Vec::with_capacity(n_half * 2 * m + 1);
let offset = n_half * m;
let factor = 4.0 * b / f32::sqrt(m as f32);
for i in 0..(n_half * m) {
let t = i as f32 - offset as f32;
let cos_calc = f32::cos((1.0 + b) * PI * t / (m as f32));
let sin_calc = f32::sin((1.0 - b) * PI * t / (m as f32)) / (4.0 * b * t / (m as f32));
let latter_f = PI * (1.0 - 16.0 * (b * t / (m as f32)).powi(2));
let mut val: f32 = factor * (cos_calc + sin_calc) / latter_f;
if val.is_nan() {
val = b / f32::sqrt(2.0 * m as f32)
* ((1.0 + 2.0 / PI) * f32::sin(PI / (4.0 * b))
+ (1.0 - 2.0 / PI) * f32::cos(PI / (4.0 * b)));
}
srrc.push(val as f32);
}
srrc.push(1.0 / f32::sqrt(m as f32) * ((1.0 - b) + 4.0 * b / PI));
for i in 0..offset {
srrc.push(srrc[offset - i - 1]);
}
Filter { coeff: srrc }
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_srrc_len() {
let srrc = Filter::create_srrc(4, 0.5, 2);
assert_eq!(srrc.len(), 17);
}
#[test]
fn test_srrc_symmetry() {
let srrc = Filter::create_srrc(4, 0.5, 2);
let len = srrc.len();
for i in 0..len / 2 - 1 {
assert_eq!(srrc.coeff[i], srrc.coeff[len - i - 1]);
}
}
#[test]
fn test_srrc_values() {
let srrc = Filter::create_srrc(4, 0.5, 1);
let srrc_mat = vec![-0.010105, 0.0030315, 0.042441, -0.1061, 1.1366];
let err = 0.0001;
for i in 0..srrc_mat.len() {
let err_sqrd = (srrc.coeff[i] - srrc_mat[i]).abs();
assert!(err_sqrd < err)
}
}
#[test]
fn test_filter() {
let filter = Filter::new(vec![1., 0., 1.]);
let sig = vec![1., 2., 3., 4., 5., 6., 7.];
let expected_result = vec![4., 6., 8., 10., 12.];
assert_eq!(expected_result, filter.filter_windowed(&sig));
}
#[test]
fn create_moving_average() {
let vec = vec![0.2, 0.2, 0.2, 0.2, 0.2];
let filter_ma_5 = Filter::new(vec);
assert_eq!(filter_ma_5, Filter::create_moving_average(5));
let vec = vec![0.25, 0.25, 0.25, 0.25];
let filter_ma_4 = Filter::new(vec);
assert_eq!(filter_ma_4, Filter::create_moving_average(4));
}
}