use ringbuffer::{AllocRingBuffer, RingBuffer};
pub struct BufferStats {
pub buffer_size: usize,
pub window_size: usize,
pub total_avg: f64,
pub total_variance: f64,
pub total_stdev: f64,
pub moving_avg: AllocRingBuffer<f64>,
pub moving_variance: AllocRingBuffer<f64>,
pub moving_max: AllocRingBuffer<f64>,
}
impl BufferStats {
pub fn new(buffer_len: usize, window_len: usize) -> BufferStats {
BufferStats {
buffer_size: buffer_len,
window_size: window_len,
total_avg: 0.,
total_variance: 0.,
total_stdev: 0.,
moving_avg: AllocRingBuffer::new(buffer_len),
moving_variance: AllocRingBuffer::new(buffer_len), moving_max: AllocRingBuffer::new(buffer_len),
}
}
pub fn init_moving_avg(&mut self, data: &[f64]) {
let mut init_moving_avg_value = 0.;
for idx in 0..self.window_size - 1 {
init_moving_avg_value += data[idx];
}
init_moving_avg_value /= self.window_size as f64;
for idx in 0..self.buffer_size {
if idx < self.window_size {
self.moving_avg.push(init_moving_avg_value);
} else {
self.update_moving_avg(&data);
}
}
}
pub fn init_moving_variance(&mut self, data: &[f64]) {
let mut variance = 0.;
for idx in 0..self.buffer_size {
if idx < self.window_size {
let diff = self.moving_avg[idx] - data[idx];
variance += diff * diff;
self.moving_variance
.push(variance / self.window_size as f64);
} else {
self.update_moving_variance(&data);
}
}
}
pub fn init_moving_max(&mut self, data: &[f64]) {
let mut window_max = 0.;
for idx in 0..self.buffer_size {
if idx < self.window_size {
if data[idx] > window_max {
window_max = data[idx];
}
self.moving_max.push(window_max);
} else {
self.update_moving_variance(&data)
}
}
}
pub fn update_moving_avg(&mut self, data: &[f64]) {
let oldest_data = data[0];
let newest_data = data[data.len() - 1];
let newest_avg = self.moving_avg.back().unwrap();
self.moving_avg
.push(newest_avg + (newest_data - oldest_data) / self.window_size as f64)
}
pub fn update_moving_variance(&mut self, data: &[f64]) {
let oldest_data = data[0];
let newest_data = data[data.len() - 1];
let oldest_avg = self
.moving_avg
.get_signed(-(self.window_size as isize))
.unwrap();
let newest_avg = self.moving_avg.back().unwrap();
let oldest_diff = (oldest_data - oldest_avg).powi(2);
let newest_diff = (newest_data - newest_avg).powi(2);
let newest_variance = self.moving_variance.back().unwrap();
self.moving_variance
.push(newest_variance + (newest_diff - oldest_diff) / self.window_size as f64)
}
pub fn update_moving_max(&mut self, data: &[f64]) {
let newest_data = data[data.len() - 1];
let curr_window_max = self.moving_max.back().unwrap();
if newest_data > *curr_window_max {
self.moving_max.push(newest_data);
} else {
self.moving_max.push(*curr_window_max);
}
}
}