use crate::processing_utils::AnalysisPipeline;
use num::Float;
#[cfg(feature = "std")]
use std::collections::VecDeque;
#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(not(feature = "std"))]
use alloc::{boxed::Box, collections::vec_deque::VecDeque};
pub struct TimeQueue<T> {
data: VecDeque<T>,
time: T,
current_time: T,
pipeline: Box<dyn AnalysisPipeline<T>>,
}
impl<
T: Float
+ core::iter::Sum<T>
+ Copy
+ 'static
+ core::fmt::Debug
+ num::Signed
+ core::ops::AddAssign
+ core::marker::Send
+ core::marker::Sync
+ core::ops::SubAssign
+ Into<f64>
+ num::FromPrimitive,
> TimeQueue<T>
where
Box<dyn AnalysisPipeline<T>>: Default,
{
pub fn new(time: usize) -> Self {
Self {
data: VecDeque::with_capacity(4 * time), time: T::from(time).unwrap(),
current_time: T::from(0).unwrap(),
pipeline: Default::default(),
}
}
pub fn set_pipeline(&mut self, pipeline: Box<dyn AnalysisPipeline<T>>) {
self.pipeline = pipeline;
}
pub fn push(&mut self, rr_interval: T) {
self.current_time += rr_interval;
self.data.push_back(rr_interval);
if self.current_time >= self.time {
if let Some(deleted) = self.data.pop_front() {
self.current_time -= deleted;
}
}
}
pub fn get(&self) -> &[T] {
self.data.as_slices().0
}
pub fn get_hrv(&self) -> crate::HrvMetrics<T> {
self.pipeline.process(self.get().to_vec())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
frequency_domain::FrequencyMetrics, geometric_domain::GeometricMetrics,
non_linear::NonLinearMetrics, processing_utils::RRIntervals, time_domain::TimeMetrics,
utils::test_data::RR_INTERVALS,
};
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
#[test]
fn test_queue() {
let mut data = RR_INTERVALS.to_vec();
data.extend_from_within(..);
let mut queue = TimeQueue::new(298_500usize);
let mut win_0: crate::HrvMetrics<f64> = Default::default();
for (i, j) in data.iter().enumerate() {
queue.push(*j);
if i == data.len() / 2 - 1 {
win_0 = queue.get_hrv();
}
}
let win_1 = queue.get_hrv();
assert_eq!(win_0, win_1);
}
#[test]
fn test_queue_custom_pipeline() {
let mut data = RR_INTERVALS.to_vec();
data.extend_from_within(..);
let mut queue = TimeQueue::new(298_500usize);
struct Pipeline();
impl AnalysisPipeline<f64> for Pipeline {
fn process(&self, data: Vec<f64>) -> crate::HrvMetrics<f64> {
let rr_intervals = RRIntervals::new(data);
let time = TimeMetrics::compute(rr_intervals.as_slice());
let frequency = FrequencyMetrics::compute(rr_intervals.as_slice(), 4.);
let geometric = GeometricMetrics::compute(rr_intervals.as_slice());
let non_linear = NonLinearMetrics::compute_default(rr_intervals.as_slice());
crate::HrvMetrics {
time,
frequency,
geometric,
non_linear,
}
}
}
queue.set_pipeline(Box::new(Pipeline()));
let mut win_0: crate::HrvMetrics<f64> = Default::default();
for (i, j) in data.iter().enumerate() {
queue.push(*j);
if i == data.len() / 2 - 1 {
win_0 = queue.get_hrv();
}
}
let win_1 = queue.get_hrv();
assert_eq!(win_0, win_1);
}
}