use egui::emath::OrderedFloat;
use std::{
collections::VecDeque,
fmt::{self, Debug, Formatter},
};
#[derive(Clone, Copy)]
struct BufferElement {
index: usize,
value: OrderedFloat<f32>,
}
impl Debug for BufferElement {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("BufferElement")
.field("index", &self.index)
.field("value", &self.value.0)
.finish()
}
}
impl Default for BufferElement {
fn default() -> Self {
BufferElement {
index: 0,
value: 0.0.into(),
}
}
}
#[derive(Clone, Debug)]
pub struct PeakDetector {
deque: VecDeque<BufferElement>,
buffer_size: usize,
next_index: usize,
}
impl PeakDetector {
pub fn new(buffer_size: usize) -> Self {
Self {
buffer_size,
deque: VecDeque::default(),
next_index: 0,
}
}
pub fn next(&mut self, value: f32) -> f32 {
let deque = &mut self.deque;
let buffer_size = self.buffer_size;
let next_index = self.next_index;
let value = OrderedFloat(value);
if deque.back().map(|it| it.index) == Some(next_index) {
deque.pop_back();
}
if deque.is_empty() {
deque.push_back(BufferElement {
index: next_index,
value,
});
} else if deque.back().unwrap().value <= value {
deque.clear();
deque.push_back(BufferElement {
index: next_index,
value,
});
} else {
while value >= deque.front().unwrap().value {
deque.pop_front();
}
deque.push_front(BufferElement {
index: next_index,
value,
});
}
self.next_index = (next_index + 1) % buffer_size;
deque.back().unwrap().value.into_inner()
}
#[allow(dead_code)]
pub fn current(&self) -> f32 {
self.deque
.back()
.unwrap_or(&BufferElement::default())
.value
.into_inner()
}
}
#[cfg(test)]
mod test {
use super::PeakDetector;
#[test]
fn tracks_max_ascending_list() {
let array = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5];
let mut detector = PeakDetector::new(10);
let detected_maxes = array.map(|it| detector.next(it));
assert_eq!(detected_maxes, array);
}
#[test]
fn tracks_max_descending_list() {
let array = [0.5, 0.4, 0.3, 0.2, 0.1];
let mut detector = PeakDetector::new(10);
let detected_maxes = array.map(|it| detector.next(it));
assert_eq!(detected_maxes, [0.5; 5])
}
#[test]
fn max_outside_of_buffer_is_removed() {
let array = [0.5, 0.4, 0.3, 0.2, 0.1];
let mut detector = PeakDetector::new(4);
for value in array {
detector.next(value);
}
let expected = 0.4;
assert_eq!(detector.current(), expected)
}
#[test]
fn detector_handles_array_larger_than_buffer() {
let array = [0.8, 0.1, 0.3, 0.2, 0.1, 0.6, 0.2];
let mut detector = PeakDetector::new(4);
for value in array {
detector.next(value);
}
let expected = 0.6;
assert_eq!(detector.current(), expected)
}
#[test]
fn new_max_is_detected() {
let array = [0.5, 0.0, 0.1, 0.0, 0.8];
let mut detector = PeakDetector::new(10);
for value in array {
detector.next(value);
}
let expected = 0.8;
assert_eq!(detector.current(), expected);
}
#[test]
fn empty_buffer_returns_0() {
let detector = PeakDetector::new(10);
assert_eq!(detector.current(), 0.0);
}
}