#[allow(unused_imports)]
use super::functions::*;
#[allow(unused_imports)]
use super::functions_2::*;
use std::f64::consts::PI;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[allow(dead_code)]
pub enum WeightingFilter {
A,
B,
C,
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct PorousAbsorber {
pub flow_resistivity: f64,
pub thickness: f64,
}
impl PorousAbsorber {
pub fn new(flow_resistivity: f64, thickness: f64) -> Self {
Self {
flow_resistivity,
thickness,
}
}
fn x_param(&self, freq: f64) -> f64 {
1.204 * freq / self.flow_resistivity
}
pub fn impedance_real(&self, freq: f64) -> f64 {
let x = self.x_param(freq);
1.0 + 9.08 * x.powf(-0.75)
}
pub fn impedance_imag(&self, freq: f64) -> f64 {
let x = self.x_param(freq);
-11.9 * x.powf(-0.73)
}
pub fn propagation_real(&self, freq: f64) -> f64 {
let x = self.x_param(freq);
let omega = 2.0 * PI * freq;
let c_air = 343.0;
(omega / c_air) * (1.0 + 10.8 * x.powf(-0.70))
}
pub fn propagation_imag(&self, freq: f64) -> f64 {
let x = self.x_param(freq);
let omega = 2.0 * PI * freq;
let c_air = 343.0;
(omega / c_air) * (10.3 * x.powf(-0.59))
}
pub fn absorption_coefficient(&self, freq: f64) -> f64 {
let z_r = self.impedance_real(freq);
let z_i = self.impedance_imag(freq);
let ki = self.propagation_imag(freq);
let kd = ki * self.thickness;
let coth_kd = if kd > 50.0 { 1.0 } else { 1.0 / kd.tanh() };
let zs_r = z_r * coth_kd;
let zs_i = z_i * coth_kd;
let num_re = zs_r - 1.0;
let denom_re = zs_r + 1.0;
let r_sq = (num_re * num_re + zs_i * zs_i) / (denom_re * denom_re + zs_i * zs_i);
(1.0 - r_sq).clamp(0.0, 1.0)
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct LocallyResonantUnit {
pub mass: f64,
pub stiffness: f64,
pub cell_volume: f64,
pub rho_matrix: f64,
}
impl LocallyResonantUnit {
pub fn new(mass: f64, stiffness: f64, cell_volume: f64, rho_matrix: f64) -> Self {
Self {
mass,
stiffness,
cell_volume,
rho_matrix,
}
}
pub fn resonance_frequency(&self) -> f64 {
(1.0 / (2.0 * PI)) * (self.stiffness / self.mass).sqrt()
}
pub fn effective_density(&self, freq: f64) -> f64 {
let omega_0 = 2.0 * PI * self.resonance_frequency();
let omega = 2.0 * PI * freq;
let omega_0_sq = omega_0 * omega_0;
let omega_sq = omega * omega;
let denom = omega_0_sq - omega_sq;
if denom.abs() < 1e-30 {
return f64::INFINITY;
}
let rho_incl = self.mass / self.cell_volume;
self.rho_matrix + rho_incl * omega_0_sq / denom
}
pub fn is_negative_mass(&self, freq: f64) -> bool {
let rho_eff = self.effective_density(freq);
rho_eff < 0.0
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct WaterAbsorption {
pub temperature_c: f64,
pub salinity_ppt: f64,
pub depth_m: f64,
}
impl WaterAbsorption {
#[allow(dead_code)]
pub fn new(temperature_c: f64, salinity_ppt: f64, depth_m: f64) -> Self {
Self {
temperature_c,
salinity_ppt,
depth_m,
}
}
#[allow(dead_code)]
pub fn freshwater() -> Self {
Self::new(20.0, 0.0, 0.0)
}
#[allow(dead_code)]
pub fn seawater() -> Self {
Self::new(15.0, 35.0, 0.0)
}
#[allow(dead_code)]
pub fn absorption_db_per_km(&self, freq_khz: f64) -> f64 {
let t = self.temperature_c;
let s = self.salinity_ppt;
let d = self.depth_m / 1000.0;
let f = freq_khz;
let f2 = f * f;
let f1 = 0.78 * (s / 35.0).sqrt() * (t / 26.0).exp();
let a1 = 0.106 * f1 * f2 / (f1 * f1 + f2) * (-d / 6.0).exp();
let f2_rel = 42.0 * (t / 17.0).exp();
let a2 = 0.52 * (s / 35.0) * (1.0 + t / 40.0) * f2_rel * f2 / (f2_rel * f2_rel + f2)
* (-d / 6.0).exp();
let a3 = 4.9e-4 * f2 * (-t / 27.0 + d / 17.0).exp();
a1 + a2 + a3
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct AcousticMaterial {
pub density: f64,
pub bulk_modulus: f64,
pub shear_modulus: f64,
pub loss_factor: f64,
}
impl AcousticMaterial {
#[allow(dead_code)]
pub fn new(density: f64, bulk_modulus: f64, shear_modulus: f64, loss_factor: f64) -> Self {
Self {
density,
bulk_modulus,
shear_modulus,
loss_factor,
}
}
#[allow(dead_code)]
pub fn water() -> Self {
Self {
density: 998.2,
bulk_modulus: 2.18e9,
shear_modulus: 0.0,
loss_factor: 0.0,
}
}
#[allow(dead_code)]
pub fn steel() -> Self {
Self {
density: 7850.0,
bulk_modulus: 166.67e9,
shear_modulus: 80.0e9,
loss_factor: 0.001,
}
}
#[allow(dead_code)]
pub fn air() -> Self {
Self {
density: 1.204,
bulk_modulus: 141.9e3,
shear_modulus: 0.0,
loss_factor: 0.0,
}
}
#[allow(dead_code)]
pub fn concrete() -> Self {
Self {
density: 2300.0,
bulk_modulus: 13.33e9,
shear_modulus: 10.0e9,
loss_factor: 0.02,
}
}
#[allow(dead_code)]
pub fn longitudinal_velocity(&self) -> f64 {
let m_modulus = self.bulk_modulus + 4.0 * self.shear_modulus / 3.0;
(m_modulus / self.density).sqrt()
}
#[allow(dead_code)]
pub fn shear_velocity(&self) -> f64 {
if self.shear_modulus == 0.0 {
0.0
} else {
(self.shear_modulus / self.density).sqrt()
}
}
#[allow(dead_code)]
pub fn acoustic_impedance(&self) -> f64 {
self.density * self.longitudinal_velocity()
}
#[allow(dead_code)]
pub fn compute_insertion_loss(
&self,
frequency: f64,
thickness: f64,
fresnel_number: f64,
) -> f64 {
let m_s = self.density * thickness;
let rho_air = 1.204_f64;
let c_air = 343.0_f64;
let tl_mass = 20.0 * (1.0 + PI * frequency * m_s / (rho_air * c_air)).log10();
let il_diffraction = if fresnel_number > 0.0 {
10.0 * (1.0 + 20.0 * fresnel_number).log10()
} else {
0.0
};
tl_mass + il_diffraction
}
#[allow(dead_code)]
pub fn compute_noise_reduction_coefficient(&self, thickness: f64) -> f64 {
let bands = [250.0_f64, 500.0, 1000.0, 2000.0];
let rho_air = 1.204_f64;
let c_air = 343.0_f64;
let m_s = self.density * thickness;
let sum: f64 = bands
.iter()
.map(|&f| {
let omega = 2.0 * PI * f;
let alpha = self.loss_factor * m_s * omega / (rho_air * c_air);
alpha.clamp(0.0, 1.0)
})
.sum();
let nrc_raw = sum / bands.len() as f64;
let nrc_rounded = (nrc_raw / 0.05).round() * 0.05;
nrc_rounded.clamp(0.0, 1.0)
}
#[allow(dead_code)]
pub fn compute_transmission_loss_mass_law(&self, frequency: f64, thickness: f64) -> f64 {
let m_s = self.density * thickness;
let rho_air = 1.204_f64;
let c_air = 343.0_f64;
let arg = PI * m_s * frequency / (rho_air * c_air);
20.0 * arg.log10()
}
}
#[allow(dead_code)]
impl AcousticMaterial {
pub fn rubber() -> Self {
Self {
density: 1200.0,
bulk_modulus: 2.0e9,
shear_modulus: 0.5e6,
loss_factor: 0.1,
}
}
pub fn aluminium() -> Self {
Self {
density: 2780.0,
bulk_modulus: 73.1e9,
shear_modulus: 27.0e9,
loss_factor: 0.0002,
}
}
pub fn glass() -> Self {
Self {
density: 2230.0,
bulk_modulus: 46.0e9,
shear_modulus: 26.0e9,
loss_factor: 0.0005,
}
}
#[allow(dead_code)]
pub fn sound_speed(&self) -> f64 {
self.longitudinal_velocity()
}
#[allow(dead_code)]
pub fn relative_impedance(&self) -> f64 {
self.acoustic_impedance() / 413.0
}
}
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub struct UltrasonicNDE {
pub velocity: f64,
pub frequency: f64,
pub pulse_amplitude: f64,
pub attenuation_db_m: f64,
}
impl UltrasonicNDE {
#[allow(dead_code)]
pub fn new(velocity: f64, frequency: f64, pulse_amplitude: f64, attenuation_db_m: f64) -> Self {
Self {
velocity,
frequency,
pulse_amplitude,
attenuation_db_m,
}
}
#[allow(dead_code)]
pub fn time_of_flight(&self, depth_m: f64) -> f64 {
2.0 * depth_m / self.velocity
}
#[allow(dead_code)]
pub fn echo_amplitude(&self, depth_m: f64, reflection_coeff: f64) -> f64 {
if depth_m <= 0.0 {
return self.pulse_amplitude * reflection_coeff.abs();
}
let d = 2.0 * depth_m;
let geo = 1.0 / (1.0 + d);
let alpha_np = self.attenuation_db_m / 8.686;
let att = (-alpha_np * d).exp();
self.pulse_amplitude * reflection_coeff.abs() * geo * att
}
#[allow(dead_code)]
pub fn wavelength(&self) -> f64 {
self.velocity / self.frequency
}
#[allow(dead_code)]
pub fn near_field_distance(&self, transducer_radius: f64) -> f64 {
transducer_radius * transducer_radius / self.wavelength()
}
#[allow(dead_code)]
pub fn lateral_resolution(&self, depth_m: f64, transducer_radius: f64) -> f64 {
1.22 * self.wavelength() * depth_m / (2.0 * transducer_radius)
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct PhononicCrystal1D {
pub z_a: f64,
pub z_b: f64,
pub c_a: f64,
pub c_b: f64,
pub d_a: f64,
pub d_b: f64,
}
impl PhononicCrystal1D {
pub fn new(z_a: f64, z_b: f64, c_a: f64, c_b: f64, d_a: f64, d_b: f64) -> Self {
Self {
z_a,
z_b,
c_a,
c_b,
d_a,
d_b,
}
}
pub fn lattice_constant(&self) -> f64 {
self.d_a + self.d_b
}
pub fn bragg_frequency(&self) -> f64 {
let c_eff = (self.c_a * self.d_a + self.c_b * self.d_b) / self.lattice_constant();
c_eff / (2.0 * self.lattice_constant())
}
pub fn relative_gap_width(&self) -> f64 {
let r = (self.z_b - self.z_a).abs() / (self.z_a + self.z_b);
(2.0 / PI) * r.asin()
}
pub fn gap_width_hz(&self) -> f64 {
self.relative_gap_width() * self.bragg_frequency()
}
pub fn is_in_gap(&self, freq: f64) -> bool {
let f0 = self.bragg_frequency();
let half_gap = 0.5 * self.gap_width_hz();
(freq - f0).abs() < half_gap
}
}