use std::collections::VecDeque;
use super::types::ThermalSample;
use super::{DEFAULT_THROTTLE_THRESHOLD_C, MIN_SAMPLES_FOR_ANALYSIS};
#[derive(Debug)]
pub struct ThermalAnalyzer {
samples: VecDeque<ThermalSample>,
max_samples: usize,
throttle_threshold_c: f64,
default_cooling_rate: f64,
}
impl ThermalAnalyzer {
pub fn new(max_samples: usize) -> Self {
Self {
samples: VecDeque::with_capacity(max_samples),
max_samples,
throttle_threshold_c: DEFAULT_THROTTLE_THRESHOLD_C,
default_cooling_rate: 0.5,
}
}
pub fn with_threshold(mut self, threshold_c: f64) -> Self {
self.throttle_threshold_c = threshold_c;
self
}
pub fn with_cooling_rate(mut self, rate: f64) -> Self {
self.default_cooling_rate = rate;
self
}
pub fn add_sample(&mut self, sample: ThermalSample) {
if self.samples.len() >= self.max_samples {
self.samples.pop_front();
}
self.samples.push_back(sample);
}
pub fn add(&mut self, temperature_c: f64, timestamp_sec: f64) {
self.add_sample(ThermalSample::new(temperature_c, timestamp_sec));
}
pub fn add_with_latency(&mut self, temperature_c: f64, timestamp_sec: f64, latency_us: f64) {
self.add_sample(ThermalSample::with_latency(
temperature_c,
timestamp_sec,
latency_us,
));
}
pub fn sample_count(&self) -> usize {
self.samples.len()
}
pub fn has_sufficient_samples(&self) -> bool {
self.samples.len() >= MIN_SAMPLES_FOR_ANALYSIS
}
pub fn current_temperature(&self) -> Option<f64> {
self.samples.back().map(|s| s.temperature_c)
}
pub fn average_temperature(&self) -> Option<f64> {
if self.samples.is_empty() {
return None;
}
let sum: f64 = self.samples.iter().map(|s| s.temperature_c).sum();
Some(sum / self.samples.len() as f64)
}
pub fn temperature_range(&self) -> Option<(f64, f64)> {
if self.samples.is_empty() {
return None;
}
let min = self
.samples
.iter()
.map(|s| s.temperature_c)
.fold(f64::INFINITY, f64::min);
let max = self
.samples
.iter()
.map(|s| s.temperature_c)
.fold(f64::NEG_INFINITY, f64::max);
Some((min, max))
}
pub(crate) fn time_temp_pairs(&self) -> Vec<(f64, f64)> {
self.samples
.iter()
.map(|s| (s.timestamp_sec, s.temperature_c))
.collect()
}
pub(crate) fn throttle_threshold_c(&self) -> f64 {
self.throttle_threshold_c
}
pub(crate) fn default_cooling_rate(&self) -> f64 {
self.default_cooling_rate
}
pub fn clear(&mut self) {
self.samples.clear();
}
pub fn samples(&self) -> &VecDeque<ThermalSample> {
&self.samples
}
}
impl Default for ThermalAnalyzer {
fn default() -> Self {
Self::new(100)
}
}