Acoustic impedance: density times the speed of sound¶
A medium's characteristic acoustic impedance, Z = rho c, from its density and the speed of sound in it (lusine.properties.speed_of_sound for a bar), in Pa s/m (the rayl).
Where two media meet, a wave's pressure amplitude is reflected by (Z2 - Z1) / (Z2 + Z1). Source: Kinsler, Frey, Coppens & Sanders, Fundamentals of Acoustics, 4th ed., 5.10 and 6.2. Checked against a reference in numpy, which has its own tests.
- Source
- Kinsler, Frey, Coppens & Sanders, Fundamentals of Acoustics, 4th ed., 5.10 and 6.2.
- Proof
- reference, invariant.
acoustic_impedance.trait
namespace lusine.properties;
float<Pa*s/m> acoustic_impedance(float<kg/m3> density, float<m/s> speed)
{
return density * speed;
}
A medium's characteristic impedance Z = ρc, in Pa s/m (the rayl). Where two media meet, a pressure wave is reflected by (Z₂ − Z₁)/(Z₂ + Z₁). The library stores no impedance: this kernel derives it. Its speed of sound comes from lusine.properties.speed_of_sound.
import os, sys
root = os.getcwd()
while not os.path.isfile(os.path.join(root, 'docsite.json')):
root = os.path.dirname(root)
sys.path.insert(0, os.path.join(root, 'tools'))
import numpy as np
import matplotlib.pyplot as plt
from lusine import trait_run
from lusine.library_sources import parse_rows
EPS = float(np.finfo(np.float32).eps) # Trait's float is binary32
The kernel¶
The law as the library states it.
print(trait_run.source('properties/acoustic_impedance.trait'))
// lusine.properties.acoustic_impedance: a medium's characteristic acoustic impedance, Z = rho c, from its density and
// the speed of sound in it (lusine.properties.speed_of_sound for a bar), in Pa s/m (the rayl). Where two media meet, a
// wave's pressure amplitude is reflected by (Z2 - Z1) / (Z2 + Z1).
// Source: Kinsler, Frey, Coppens & Sanders, Fundamentals of Acoustics, 4th ed., 5.10 and 6.2.
// Checked against a reference in numpy, which has its own tests.
namespace lusine.properties;
float<Pa*s/m> acoustic_impedance(float<kg/m3> density, float<m/s> speed)
{
return density * speed;
}
The program¶
Each section runs the kernel over a lattice of items, one a case.
print(trait_run.law_program('properties/acoustic_impedance.trait', 'acoustic_impedance'))
namespace probe;
lusine.version version = { { number = 1 } };
struct item {
host float<kg/m3> density;
host float<m/s> speed;
float<Pa*s/m> result_0;
};
lattice<item, 1> items(spacing = 1 m, boundary = wall);
void main() { items.result_0 = lusine.properties.acoustic_impedance(items.density, items.speed); }
Reference: steel and copper bars, from the table's own E and ρ¶
The bar speed comes from speed_of_sound run on the table's E and ρ, and the impedance from this kernel on ρ and that speed; ρ√(E/ρ) is √(Eρ), which each is held to, to binary32's rounding: steel's 39.6 MPa s/m, copper's 34.1 MPa s/m.
mech = trait_run.source('materials/generated/mechanical.trait')
phases = [r for r in parse_rows(mech, 'mechanical_phases') if 'stiffness' in r and 'density' in r]
stiff = {r['material']: r['stiffness'] for r in phases}
dense = {r['material']: r['density'] for r in phases}
bars = ['steel', 'copper', 'iron', 'tungsten']
E = np.array([stiff[m] for m in bars])
rho = np.array([dense[m] for m in bars])
c = trait_run.law('properties/speed_of_sound.trait', 'speed_of_sound', stiffness=E, density=rho)
z = trait_run.law('properties/acoustic_impedance.trait', 'acoustic_impedance', density=rho, speed=c)
want = np.sqrt(E * rho)
assert np.all(np.abs(z / want - 1) <= 4 * EPS), np.abs(z / want - 1).max()
assert abs(z[0] - 3.962e7) < 1e4 and abs(z[1] - 3.413e7) < 1e4, z
for m, v in zip(bars, z):
print(f'{m:9s} Z = {v / 1e6:6.2f} MPa s/m')
steel Z = 39.62 MPa s/m copper Z = 34.13 MPa s/m iron Z = 40.75 MPa s/m tungsten Z = 89.06 MPa s/m
Invariant: a wave meeting another medium¶
Water (998 kg/m³ at 1481 m/s, Kinsler et al.'s appendix A10) against air (1.21 kg/m³ at 343 m/s): the pressure amplitude reflected, (Z₂ − Z₁)/(Z₂ + Z₁), is 0.9994, why sound barely crosses a water surface; against a steel bar, 0.928. The impedance is proportional to each of ρ and c: doubling either doubles it, bit for bit.
z = trait_run.law('properties/acoustic_impedance.trait', 'acoustic_impedance', density=[1.21, 998.0, 7850.0], speed=[343.0, 1481.0, 5047.54443359375])
air, water, steel = (float(v) for v in z)
r_air = (water - air) / (water + air)
r_steel = (steel - water) / (steel + water)
assert 0.9994 < r_air < 0.9995 and 0.927 < r_steel < 0.929, (r_air, r_steel)
print(f'water from air reflects {r_air:.4f}; steel from water {r_steel:.4f}')
rng = np.random.default_rng(321)
rho = np.float32(10 ** rng.uniform(0, 4.5, 32)).astype(float)
cs = np.float32(10 ** rng.uniform(2, 4, 32)).astype(float)
z1 = trait_run.law('properties/acoustic_impedance.trait', 'acoustic_impedance', density=rho, speed=cs)
z2 = trait_run.law('properties/acoustic_impedance.trait', 'acoustic_impedance', density=2 * rho, speed=cs)
z3 = trait_run.law('properties/acoustic_impedance.trait', 'acoustic_impedance', density=rho, speed=2 * cs)
assert np.array_equal(z2, 2 * z1) and np.array_equal(z3, 2 * z1)
assert np.all(np.abs(z1 / (rho * cs) - 1) <= EPS)
water from air reflects 0.9994; steel from water 0.9281