pub fn walsh_signature(coeffs: &[f64], order: usize) -> Vec<f64> {
coeffs.iter().take(order).copied().collect()
}
pub fn spectral_energy(coeffs: &[f64]) -> f64 {
coeffs.iter().map(|c| c * c).sum()
}
pub fn spectral_entropy(coeffs: &[f64]) -> f64 {
let energy = spectral_energy(coeffs);
if energy == 0.0 {
return 0.0;
}
let mut h = 0.0;
for c in coeffs {
let p = (c * c) / energy;
if p > 0.0 {
h -= p * p.log2();
}
}
h
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn signature_takes_low_order() {
assert_eq!(walsh_signature(&[1.0, 2.0, 3.0, 4.0], 2), vec![1.0, 2.0]);
assert_eq!(walsh_signature(&[1.0], 5), vec![1.0]);
}
#[test]
fn energy_is_sum_of_squares() {
assert_eq!(spectral_energy(&[3.0, 4.0]), 25.0);
}
#[test]
fn entropy_extremes() {
assert_eq!(spectral_entropy(&[5.0, 0.0, 0.0, 0.0]), 0.0);
let flat = spectral_entropy(&[1.0, 1.0, 1.0, 1.0]);
assert!((flat - 2.0).abs() < 1e-12);
assert_eq!(spectral_entropy(&[0.0, 0.0]), 0.0);
}
}