autd3_core/acoustics/
mod.rs1pub mod directivity;
3
4use std::f32::consts::PI;
5
6use crate::{
7 defined::T4010A1_AMPLITUDE,
8 geometry::{Complex, Point3, Transducer, UnitVector3},
9};
10
11use directivity::Directivity;
12
13#[inline]
15#[must_use]
16pub fn propagate<D: Directivity>(
17 tr: &Transducer,
18 wavenumber: f32,
19 dir: &UnitVector3,
20 target_pos: &Point3,
21) -> Complex {
22 const P0: f32 = T4010A1_AMPLITUDE / (4. * PI);
23 let diff = target_pos - tr.position();
24 let dist = diff.norm();
25 Complex::from_polar(
26 P0 / dist * D::directivity_from_dir(dir, &diff),
27 wavenumber * dist,
28 )
29}
30
31#[cfg(test)]
32mod tests {
33 use super::*;
34
35 use rand::Rng;
36
37 use crate::{
38 defined::mm,
39 geometry::{Device, UnitQuaternion, Vector3},
40 };
41 use directivity::tests::TestDirectivity;
42
43 macro_rules! assert_complex_approx_eq {
44 ($a:expr, $b:expr) => {
45 approx::assert_abs_diff_eq!($a.re, $b.re, epsilon = 1e-3 / mm);
46 approx::assert_abs_diff_eq!($a.im, $b.im, epsilon = 1e-3 / mm);
47 };
48 }
49
50 #[rstest::fixture]
51 fn tr() -> Transducer {
52 let mut rng = rand::rng();
53 Transducer::new(Point3::new(
54 rng.random_range(-100.0..100.0),
55 rng.random_range(-100.0..100.0),
56 rng.random_range(-100.0..100.0),
57 ))
58 }
59
60 #[rstest::fixture]
61 fn rot() -> UnitQuaternion {
62 let mut rng = rand::rng();
63 UnitQuaternion::from_axis_angle(
64 &Vector3::x_axis(),
65 rng.random_range::<f32, _>(-180.0..180.0).to_radians(),
66 ) * UnitQuaternion::from_axis_angle(
67 &Vector3::y_axis(),
68 rng.random_range::<f32, _>(-180.0..180.0).to_radians(),
69 ) * UnitQuaternion::from_axis_angle(
70 &Vector3::z_axis(),
71 rng.random_range::<f32, _>(-180.0..180.0).to_radians(),
72 )
73 }
74
75 #[rstest::fixture]
76 fn target() -> Point3 {
77 let mut rng = rand::rng();
78 Point3::new(
79 rng.random_range(-100.0..100.0),
80 rng.random_range(-100.0..100.0),
81 rng.random_range(-100.0..100.0),
82 )
83 }
84
85 #[rstest::fixture]
86 fn sound_speed() -> f32 {
87 let mut rng = rand::rng();
88 rng.random_range(300e3..400e3)
89 }
90
91 #[rstest::rstest]
92 #[test]
93 fn test_propagate(tr: Transducer, rot: UnitQuaternion, target: Point3, sound_speed: f32) {
94 let mut device = Device::new(rot, vec![tr.clone()]);
95 device.sound_speed = sound_speed;
96 let wavenumber = device.wavenumber();
97 assert_complex_approx_eq!(
98 {
99 let diff = target - tr.position();
100 let dist = diff.norm();
101 let r = T4010A1_AMPLITUDE / (4. * PI) / dist
102 * TestDirectivity::directivity_from_dir(device.axial_direction(), &diff);
103 let phase = wavenumber * dist;
104 Complex::new(r * phase.cos(), r * phase.sin())
105 },
106 super::propagate::<TestDirectivity>(&tr, wavenumber, device.axial_direction(), &target)
107 );
108 }
109}