use ndarray::{Array3, ArrayBase, ArrayViewMut3, AsArray, Axis, Ix3, ViewRepr, Zip};
use rayon::prelude::*;
use crate::phasor::plot;
use crate::traits::numeric::AsNumeric;
pub fn calibrate_coords(g: f64, s: f64, modulation: f64, phase: f64) -> (f64, f64) {
let g_trans = modulation * phase.cos();
let s_trans = modulation * phase.sin();
let g_cal = g * g_trans - s * s_trans;
let s_cal = g * s_trans + s * g_trans;
(g_cal, s_cal)
}
pub fn calibrate_gs_image<'a, T, A>(
data: A,
modulation: f64,
phase: f64,
axis: Option<usize>,
) -> Array3<f64>
where
A: AsArray<'a, T, Ix3>,
T: 'a + AsNumeric,
{
let view: ArrayBase<ViewRepr<&'a T>, Ix3> = data.into();
let a = axis.unwrap_or(2);
let shape = view.dim();
let mut c_data = Array3::<f64>::zeros(shape);
let g_trans = modulation * phase.cos();
let s_trans = modulation * phase.sin();
let src_lanes = view.lanes(Axis(a));
let dst_lanes = c_data.lanes_mut(Axis(a));
Zip::from(src_lanes)
.and(dst_lanes)
.par_for_each(|s_ln, mut d_ln| {
d_ln[0] = s_ln[0].to_f64() * g_trans - s_ln[1].to_f64() * s_trans;
d_ln[1] = s_ln[0].to_f64() * s_trans + s_ln[1].to_f64() * g_trans;
});
c_data
}
pub fn calibrate_gs_image_mut(
mut data: ArrayViewMut3<f64>,
modulation: f64,
phase: f64,
axis: Option<usize>,
) {
let axis = axis.unwrap_or(2);
let g_trans = modulation * phase.cos();
let s_trans = modulation * phase.sin();
let lanes = data.lanes_mut(Axis(axis));
lanes.into_iter().par_bridge().for_each(|mut ln| {
let g_cal = ln[0] * g_trans - ln[1] * s_trans;
let s_cal = ln[0] * s_trans + ln[1] * g_trans;
ln[0] = g_cal;
ln[1] = s_cal;
});
}
pub fn modulation_and_phase(g: f64, s: f64, tau: f64, omega: f64) -> (f64, f64) {
let cal_point = plot::monoexponential_coords(tau, omega);
let cal_mod = plot::gs_modulation(cal_point.0, cal_point.1);
let cal_phs = plot::gs_phase(cal_point.0, cal_point.1);
let data_mod = plot::gs_modulation(g, s);
let data_phs = plot::gs_phase(g, s);
let d_mod = cal_mod / data_mod;
let d_phs = cal_phs - data_phs;
(d_mod, d_phs)
}