///|
/// Calculate the Standard Deviation of NN intervals (SDNN).
pub fn calculate_sdnn(intervals : Array[Double]) -> Double {
let n = intervals.length()
if n <= 1 {
return 0.0
}
let mut sum = 0.0
for i in 0.. Double {
let n = intervals.length()
if n <= 1 {
return 0.0
}
let mut sum_sq_diff = 0.0
for i in 0..<(n - 1) {
let diff = intervals[i + 1] - intervals[i]
sum_sq_diff += diff * diff
}
let mean_sq_diff = sum_sq_diff / (n - 1).to_double()
mean_sq_diff.sqrt()
}
///|
/// Calculate the percentage of successive RR intervals differing by more than threshold_ms.
pub fn calculate_pnn(
intervals : Array[Double],
threshold_ms : Double,
) -> Double {
let n = intervals.length()
if n <= 1 {
return 0.0
}
let mut count = 0
for i in 0..<(n - 1) {
let diff = intervals[i + 1] - intervals[i]
let abs_diff = if diff < 0.0 { -diff } else { diff }
if abs_diff > threshold_ms {
count += 1
}
}
count.to_double() / (n - 1).to_double() * 100.0
}
///|
/// Calculate all time-domain HRV metrics for cleaned intervals.
pub fn calculate_metrics(
intervals : Array[Double],
config : HrvConfig,
quality : QualityReport,
) -> HrvMetrics {
let n = intervals.length()
if n == 0 {
return {
mean_rr: 0.0,
mean_hr: 0.0,
sdnn: 0.0,
rmssd: 0.0,
pnn50: 0.0,
pnn_custom: 0.0,
quality,
}
}
let mut sum = 0.0
for i in 0.. 0.0 { 60000.0 / mean_rr } else { 0.0 }
let sdnn = calculate_sdnn(intervals)
let rmssd = calculate_rmssd(intervals)
let pnn50 = calculate_pnn(intervals, 50.0)
let pnn_custom = calculate_pnn(intervals, config.pnn_threshold)
{ mean_rr, mean_hr, sdnn, rmssd, pnn50, pnn_custom, quality }
}