1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use autd3_core::{
gain::{Gain, GainProps, IGain},
geometry::{Geometry, Transducer, UnitQuaternion, Vector3},
};
use autd3_traits::Gain;
#[derive(Gain)]
pub struct Bessel<T: Transducer> {
props: GainProps<T>,
amp: f64,
pos: Vector3,
dir: Vector3,
theta: f64,
}
impl<T: Transducer> Bessel<T> {
pub fn new(pos: Vector3, dir: Vector3, theta: f64) -> Self {
Self::with_duty(pos, dir, theta, 1.0)
}
pub fn with_duty(pos: Vector3, dir: Vector3, theta: f64, amp: f64) -> Self {
Self {
props: GainProps::new(),
amp,
pos,
dir,
theta,
}
}
}
impl<T: Transducer> IGain<T> for Bessel<T> {
fn calc(&mut self, geometry: &Geometry<T>) -> anyhow::Result<()> {
let dir = self.dir.normalize();
let v = Vector3::new(dir.y, -dir.x, 0.);
let theta_v = v.norm().asin();
let rot = if let Some(v) = v.try_normalize(1.0e-6) {
UnitQuaternion::from_scaled_axis(v * -theta_v)
} else {
UnitQuaternion::identity()
};
geometry.transducers().for_each(|tr| {
let r = tr.position() - self.pos;
let r = Vector3::new(r.x, r.y, r.z);
let r = rot * r;
let dist = self.theta.sin() * (r.x * r.x + r.y * r.y).sqrt() - self.theta.cos() * r.z;
let phase = tr.align_phase_at(dist, geometry.sound_speed());
self.props.drives[tr.id()].amp = self.amp;
self.props.drives[tr.id()].phase = phase;
});
Ok(())
}
}