pub mod directivity;
use crate::{
defined::{float, Complex, PI, T4010A1_AMPLITUDE},
geometry::{Transducer, Vector3},
};
use directivity::Directivity;
pub fn propagate<D: Directivity>(
tr: &Transducer,
attenuation: float,
sound_speed: float,
target_pos: &Vector3,
) -> Complex {
let diff = target_pos - tr.position();
let dist = diff.norm();
Complex::from_polar(
T4010A1_AMPLITUDE / (4. * PI) / dist
* D::directivity_from_tr(tr, &diff)
* (-dist * attenuation).exp(),
-tr.wavenumber(sound_speed) * dist,
)
}
#[cfg(test)]
mod tests {
use super::*;
use rand::Rng;
use crate::geometry::UnitQuaternion;
use directivity::tests::TestDirectivity;
macro_rules! assert_complex_approx_eq {
($a:expr, $b:expr) => {
assert_approx_eq::assert_approx_eq!($a.re, $b.re);
assert_approx_eq::assert_approx_eq!($a.im, $b.im);
};
}
#[test]
fn propagate() {
let mut rng = rand::thread_rng();
let tr = crate::geometry::Transducer::new(0, Vector3::zeros(), UnitQuaternion::identity());
let atten = rng.gen_range(0.0..1e-6);
let c = rng.gen_range(300e3..400e3);
let target = Vector3::new(
rng.gen_range(-100.0..100.0),
rng.gen_range(-100.0..100.0),
rng.gen_range(-100.0..100.0),
);
let expect = {
let dist = target.norm();
let r = T4010A1_AMPLITUDE
* TestDirectivity::directivity_from_tr(&tr, &target)
* (-dist * atten).exp()
/ (4. * PI * dist);
let phase = -tr.wavenumber(c) * dist;
Complex::new(r * phase.cos(), r * phase.sin())
};
assert_complex_approx_eq!(
expect,
super::propagate::<TestDirectivity>(&tr, atten, c, &target)
);
}
}