use ndarray::Array1;
use num_complex::Complex64;
use std::f64::consts::PI;
pub fn compute_phase(response: &Array1<Complex64>) -> Array1<f64> {
response.mapv(|c| c.arg().to_degrees())
}
pub fn unwrap_phase_degrees(phase: &Array1<f64>) -> Array1<f64> {
let mut unwrapped = Array1::zeros(phase.len());
if phase.is_empty() {
return unwrapped;
}
unwrapped[0] = phase[0];
let mut offset = 0.0;
for i in 1..phase.len() {
let diff = phase[i] - phase[i - 1];
let wraps = (diff / 360.0).round();
offset -= wraps * 360.0;
unwrapped[i] = phase[i] + offset;
}
unwrapped
}
pub fn compute_group_delay(freqs: &Array1<f64>, phase: &Array1<f64>) -> Array1<f64> {
let mut gd = Array1::zeros(phase.len());
for i in 1..phase.len() {
let d_freq = freqs[i] - freqs[i - 1];
if d_freq > 0.0 {
let d_phase = (phase[i] - phase[i - 1]).to_radians();
gd[i] = -d_phase / (2.0 * PI * d_freq) * 1000.0; }
}
gd[0] = gd[1];
gd
}
pub fn phase_deviation(
measured_phase: &Array1<f64>,
target_phase: &Array1<f64>,
freqs: &Array1<f64>,
) -> f64 {
assert_eq!(measured_phase.len(), target_phase.len());
assert_eq!(measured_phase.len(), freqs.len());
let unwrapped_measured = unwrap_phase_degrees(measured_phase);
let unwrapped_target = unwrap_phase_degrees(target_phase);
let diff = &unwrapped_measured - &unwrapped_target;
let n = diff.len() as f64;
let sum_sq: f64 = diff.iter().map(|d| d * d).sum();
(sum_sq / n).sqrt()
}
pub fn magnitude_phase_loss(magnitude_error: f64, phase_error: f64, phase_weight: f64) -> f64 {
magnitude_error + phase_weight * phase_error
}
pub fn reconstruct_minimum_phase(magnitude_db: &Array1<f64>) -> Array1<f64> {
magnitude_db.mapv(|_| 0.0) }
pub fn impulse_response_duration(freqs: &Array1<f64>, phase: &Array1<f64>) -> f64 {
let gd = compute_group_delay(freqs, phase);
let mean_gd: f64 = gd.iter().sum::<f64>() / gd.len() as f64;
let gd_variance: f64 = gd.iter().map(|g| (g - mean_gd).powi(2)).sum::<f64>() / gd.len() as f64;
gd_variance.sqrt()
}