use std::ops::{Deref, DerefMut};
use super::FilterBase;
use crate::Result;
use crate::algorithms::Nlms;
use crate::filters::ProcessingMode;
use crate::types::{Float, WindowSize};
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct NlmsOptions<F: Float> {
pub mu: F,
pub eps: F,
pub window_size: usize,
}
impl<F: Float> Default for NlmsOptions<F> {
fn default() -> Self {
#[allow(
clippy::unwrap_used,
clippy::missing_panics_doc,
reason = "Trivial conversions"
)]
Self {
mu: F::from(0.01).unwrap(),
eps: F::from(1e-8).unwrap(),
window_size: 16,
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct NlmsFilter<F: Float> {
inner: FilterBase<F, Nlms<F>>,
}
impl<F: Float> NlmsFilter<F> {
#[allow(clippy::needless_pass_by_value, reason = "All fields are moved")]
pub fn new(options: NlmsOptions<F>, mode: ProcessingMode) -> Result<Self> {
let window_size = WindowSize::new(options.window_size)?;
let block_size = mode.block_size()?;
let nlms = Nlms::new(options.mu, options.eps, window_size)?;
let filter = FilterBase::new(nlms, block_size);
Ok(Self { inner: filter })
}
}
impl<F: Float> Deref for NlmsFilter<F> {
type Target = FilterBase<F, Nlms<F>>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<F: Float> DerefMut for NlmsFilter<F> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::indexing_slicing, reason = "Tests")]
mod tests {
use crate::types::BlockSize;
use super::*;
#[test]
fn new_works() {
let mu = 0.1;
let eps = 1e-8;
let window_size = 16;
let filter = NlmsFilter::new(
NlmsOptions {
mu,
eps,
window_size,
},
ProcessingMode::Sample,
)
.unwrap();
let window_size = WindowSize::new(window_size).unwrap();
let expected_inner = FilterBase::new(
Nlms::new(mu, eps, window_size).unwrap(),
BlockSize::new(1).unwrap(),
);
assert_eq!(filter.inner, expected_inner);
assert_eq!(filter.window_size(), *window_size);
}
#[test]
fn load_weights_works() {
let mu = 0.1;
let eps = 1e-8;
let weights = vec![1.0, 2.0, 3.0];
let window_size = WindowSize::new(weights.len()).unwrap();
let filter = {
let mut filter = NlmsFilter::new(
NlmsOptions {
mu,
eps,
window_size: *window_size,
},
ProcessingMode::Sample,
)
.unwrap();
filter.load_weights(weights.clone()).unwrap();
filter
};
let expected_inner = {
let mut expected_inner = FilterBase::new(
Nlms::new(mu, eps, window_size).unwrap(),
BlockSize::new(1).unwrap(),
);
expected_inner.load_weights(weights.clone()).unwrap();
expected_inner
};
assert_eq!(filter.inner, expected_inner);
assert_eq!(filter.window_size(), weights.len());
}
}