use dspk_ops::peaks::{select_by_distance, DistanceRule, Polarity};
use super::threshold::SpikePolarity;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SpikeSpacing {
pub refractory_samples: usize,
pub rule: DistanceRule,
}
impl SpikeSpacing {
pub fn new(refractory_samples: usize) -> Self {
Self { refractory_samples, rule: DistanceRule::LocallyExclusive }
}
pub fn from_ms(refractory_ms: f64, sample_rate_hz: f64, rule: DistanceRule) -> Self {
Self { refractory_samples: ((sample_rate_hz * refractory_ms * 1e-3).round() as usize).max(1), rule }
}
pub fn distance(&self) -> usize {
self.refractory_samples + 1
}
pub fn select<P>(&self, mut candidates: Vec<(usize, f32, P)>) -> Vec<(usize, f32, P)> {
candidates.sort_by_key(|c| c.0);
let samples: Vec<usize> = candidates.iter().map(|c| c.0).collect();
let scores: Vec<f32> = candidates.iter().map(|c| c.1).collect();
let keep = select_by_distance(&samples, &scores, self.distance(), self.rule);
candidates.into_iter().zip(keep).filter_map(|(c, k)| k.then_some(c)).collect()
}
}
impl From<SpikePolarity> for Polarity {
fn from(p: SpikePolarity) -> Self {
match p {
SpikePolarity::Negative => Polarity::Negative,
SpikePolarity::Positive => Polarity::Positive,
SpikePolarity::Both => Polarity::Both,
}
}
}