use autd::{
consts::{DataArray, NUM_TRANS_IN_UNIT},
geometry::Geometry,
prelude::Vector3,
Float, PI,
};
use super::macros::*;
use crate::{macros::VectorXf, Optimizer};
const EPS: Float = 1e-6;
const K_MAX: usize = 10_000;
pub struct GradientDescent {
pub eps: Float,
pub k_max: usize,
}
impl GradientDescent {
pub fn new() -> Self {
Self::default()
}
}
impl Default for GradientDescent {
fn default() -> Self {
Self {
eps: EPS,
k_max: K_MAX,
}
}
}
impl Optimizer for GradientDescent {
#[allow(non_snake_case, clippy::many_single_char_names)]
fn optimize(
&self,
geometry: &Geometry,
foci: &[Vector3],
amps: &[Float],
atten: Float,
data: &mut [DataArray],
) {
let m = foci.len();
let n = geometry.num_devices() * NUM_TRANS_IN_UNIT;
let n_param = n + m;
let x0 = VectorXf::zeros(n_param);
let BhB = make_BhB(geometry, atten, amps, foci, m);
let mut x = x0;
for _ in 0..self.k_max {
let T = make_T(&x, n, m);
let Jtf = calc_Jtf(&BhB, &T);
if Jtf.max() <= self.eps {
break;
}
x = &x - &(0.1 * Jtf);
}
let duty = 0xFF00;
for (d, xe) in data.iter_mut().flatten().zip(x.iter()) {
let phase = (xe % (2.0 * PI)) / (2.0 * PI);
let phase = (255.0 * (1.0 - phase)) as u16;
*d = duty | phase;
}
}
}