use num_traits::Num;
use super::Ring;
fn insertion_sort<T: PartialOrd>(s: &mut [T]) {
for i in 1..s.len() {
let mut j = i;
while j > 0 && s[j - 1] > s[j] {
s.swap(j - 1, j);
j -= 1;
}
}
}
pub struct MedianFilter<T: PartialOrd + Copy + Num, const N: usize> {
vals: Ring<T, N>,
buf: [T; N],
imid: usize,
}
impl<T: PartialOrd + Copy + Num, const N: usize> MedianFilter<T, N> {
pub fn new(v: T) -> Self {
const {
assert!(N >= 3);
assert!(N % 2 == 1);
}
let imid = N / 2;
Self {
vals: Ring::new(v),
buf: [v; N],
imid,
}
}
pub fn update(&mut self, v: T) -> T {
self.vals.push(v);
self.buf.copy_from_slice(self.vals.buf());
insertion_sort(&mut self.buf);
self.buf[self.imid]
}
}
#[cfg(feature = "std")]
#[cfg(test)]
mod test {
#[test]
fn test_median() {
use super::MedianFilter;
let inp = [2_u32, 5, 6, 7, 8, 4, 9, 0, 1, 3];
let expected = [0, 2, 5, 6, 7, 7, 8, 4, 1, 1];
let mut f = MedianFilter::<u32, 3>::new(0);
for i in 0..inp.len() {
let v = f.update(inp[i]);
let e = expected[i];
assert!(v == e, "{i}: {v} != {e}");
}
let expected = [0, 0, 2, 5, 6, 6, 7, 7, 4, 3];
let mut f = MedianFilter::<u32, 5>::new(0);
for i in 0..inp.len() {
let v = f.update(inp[i]);
let e = expected[i];
assert!(v == e, "{i}: {v} != {e}");
}
}
}