#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AgeGroup {
Child,
Teen,
YoungAdult,
MiddleAged,
Senior,
Unknown,
}
#[must_use]
pub fn estimate_age(f0: f32, formants: &[f32], jitter: f32, shimmer: f32) -> AgeGroup {
if f0 > 250.0 && formants.first().is_some_and(|&f1| f1 > 700.0) {
return AgeGroup::Child;
}
if jitter > 0.02 && shimmer > 0.08 {
return AgeGroup::Senior;
}
if jitter > 0.01 && jitter <= 0.02 {
return AgeGroup::MiddleAged;
}
if jitter < 0.01 && shimmer < 0.05 {
if !(100.0..=180.0).contains(&f0) {
return AgeGroup::Teen;
}
return AgeGroup::YoungAdult;
}
AgeGroup::Unknown
}
#[must_use]
pub fn estimate_age_with_confidence(
f0: f32,
formants: &[f32],
jitter: f32,
shimmer: f32,
) -> (AgeGroup, f32) {
let age_group = estimate_age(f0, formants, jitter, shimmer);
let confidence = match age_group {
AgeGroup::Child => {
if f0 > 300.0 {
0.9
} else {
0.6
}
}
AgeGroup::Senior => {
if jitter > 0.03 && shimmer > 0.1 {
0.8
} else {
0.6
}
}
AgeGroup::YoungAdult => {
if jitter < 0.008 && shimmer < 0.04 {
0.7
} else {
0.5
}
}
AgeGroup::MiddleAged => 0.6,
AgeGroup::Teen => 0.5,
AgeGroup::Unknown => 0.0,
};
(age_group, confidence)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_age_estimation() {
let child = estimate_age(300.0, &[750.0, 2000.0], 0.005, 0.03);
assert_eq!(child, AgeGroup::Child);
let young = estimate_age(150.0, &[500.0, 1500.0], 0.005, 0.03);
assert_eq!(young, AgeGroup::YoungAdult);
let senior = estimate_age(140.0, &[500.0, 1500.0], 0.025, 0.10);
assert_eq!(senior, AgeGroup::Senior);
}
#[test]
fn test_age_with_confidence() {
let (age, conf) = estimate_age_with_confidence(320.0, &[750.0, 2000.0], 0.005, 0.03);
assert_eq!(age, AgeGroup::Child);
assert!(conf > 0.7);
}
}