Skip to main content

sim_lib_interference_core/
medium.rs

1//! The homogeneous scalar medium and its complex wavenumber.
2
3use std::f64::consts::TAU;
4
5use crate::{Hertz, MetresPerSecond, NepersPerMetre};
6
7/// The complex wavenumber `k_tilde = omega / c + i * alpha`.
8///
9/// For the crate's `exp(i * k_tilde * r)` propagation convention, the real
10/// part advances phase and the non-negative imaginary part produces
11/// `exp(-alpha * r)` attenuation.
12#[derive(Clone, Copy, Debug, PartialEq)]
13pub struct WaveNumber {
14    real_radians_per_metre: f64,
15    imaginary_nepers_per_metre: f64,
16}
17
18impl WaveNumber {
19    /// Returns the real, phase-advancing component in radians per metre.
20    pub fn real_radians_per_metre(self) -> f64 {
21        self.real_radians_per_metre
22    }
23
24    /// Returns the imaginary, attenuating component in nepers per metre.
25    pub fn imaginary_nepers_per_metre(self) -> f64 {
26        self.imaginary_nepers_per_metre
27    }
28}
29
30/// A three-dimensional, homogeneous, isotropic scalar propagation medium.
31#[derive(Clone, Copy, Debug, PartialEq)]
32pub struct ScalarMedium {
33    speed: MetresPerSecond,
34    attenuation: NepersPerMetre,
35}
36
37impl ScalarMedium {
38    /// Constructs a medium from checked speed and attenuation quantities.
39    pub fn new(speed: MetresPerSecond, attenuation: NepersPerMetre) -> Self {
40        Self { speed, attenuation }
41    }
42
43    /// Returns the propagation speed.
44    pub fn speed(self) -> MetresPerSecond {
45        self.speed
46    }
47
48    /// Returns the attenuation coefficient.
49    pub fn attenuation(self) -> NepersPerMetre {
50        self.attenuation
51    }
52
53    /// Derives the complex wavenumber at `frequency`.
54    pub fn wavenumber(self, frequency: Hertz) -> WaveNumber {
55        WaveNumber {
56            real_radians_per_metre: TAU * frequency.get() / self.speed.get(),
57            imaginary_nepers_per_metre: self.attenuation.get(),
58        }
59    }
60}