use ndarray::Array1;
pub fn calculate_tonal_balance(
freqs: &Array1<f64>,
values: &Array1<f64>,
f_min: f64,
f_max: f64,
) -> Option<(f64, f64)> {
let mut x_vals = Vec::new();
let mut y_vals = Vec::new();
for (i, &f) in freqs.iter().enumerate() {
if f >= f_min && f <= f_max {
x_vals.push(f.log2());
y_vals.push(values[i]);
}
}
if x_vals.len() < 2 {
return None;
}
let n = x_vals.len() as f64;
let sum_x: f64 = x_vals.iter().sum();
let sum_y: f64 = y_vals.iter().sum();
let sum_xy: f64 = x_vals.iter().zip(y_vals.iter()).map(|(x, y)| x * y).sum();
let sum_x2: f64 = x_vals.iter().map(|x| x * x).sum();
let denom = n * sum_x2 - sum_x * sum_x;
if denom.abs() < 1e-12 {
return None;
}
let slope = (n * sum_xy - sum_x * sum_y) / denom;
let intercept = (sum_y * sum_x2 - sum_x * sum_xy) / denom;
let slope_octave = slope;
let intercept_1khz = intercept + slope * 1000f64.log2();
Some((slope_octave, intercept_1khz))
}
pub fn generate_regression_line(slope: f64, intercept: f64, freqs: &Array1<f64>) -> Array1<f64> {
freqs.mapv(|f| intercept + slope * (f / 1000.0).log2())
}
pub fn create_regression_trace(
freqs: &Array1<f64>,
values: &Array1<f64>,
name: &str,
color: &str,
x_axis: Option<&str>,
y_axis: Option<&str>,
) -> plotly::Scatter<f64, f64> {
let mut trace = plotly::Scatter::new(freqs.to_vec(), values.to_vec())
.mode(plotly::common::Mode::Lines)
.name(name)
.line(
plotly::common::Line::new()
.color(color.to_string())
.width(3.0),
);
if let Some(axis) = x_axis {
trace = trace.x_axis(axis);
}
if let Some(axis) = y_axis {
trace = trace.y_axis(axis);
}
*trace
}