Acoustic impedance, live¶
A medium's characteristic acoustic impedance, Z = ρc, its density times the speed of sound in it, in Pa s/m (the rayl). Where a sound wave meets a second medium, the share of its pressure reflected is (Z₂ − Z₁) / (Z₂ + Z₁). Below, a bar with steel's density is swept in stiffness from none to 240 GPa, 1.5 GPa a step, twenty steps a second, and at each the library's speed of sound (lusine.properties.speed_of_sound) and impedance (lusine.properties.acoustic_impedance) give its impedance on your GPU as you read. Beside it the same program computes the closed form a bar's impedance reduces to, ρ √(E / ρ) = √(E ρ), and the impedances of the library's steel and copper, of water and of air.
This page runs the program on your GPU through WebGPU, so it needs a browser with WebGPU (a recent Chrome, Edge, Safari or Firefox). Without it the program does not run and nothing is drawn below.
What it shows¶
- The strip above the controls is green while every check holds, and turns red for good once one fails.
- The bar: the chart draws the bar's impedance from the two kernels, in MPa s/m, against its stiffness in GPa, a point a step over one whole sweep, and the closed form √(E ρ) beside it: the two lie one over the other. Below it, the stiffness and the impedance there.
- The media: the impedances of the library's steel and copper, each from its own stiffness and density, and of water (998 kg/m³ at 1481 m/s) and air (1.21 kg/m³ at 343 m/s), as Kinsler, Frey, Coppens and Sanders tabulate them (Fundamentals of Acoustics, 4th ed., appendix A10); and the share of a wave's pressure reflected where air meets water, 0.9994, why sound barely crosses a water surface, and where water meets steel, 0.928.
- The checks, each held at every step: √(E ρ), the bar's impedance within 0.0001% of the closed form; the tables' values, steel at 39.62 MPa s/m, copper at 34.13 MPa s/m and water at 1.478 MPa s/m, each within 0.01 MPa s/m; reflections, the two shares within 0.0001 and 0.001 of 0.99945 and 0.928; proportional, twice the density or twice the speed giving exactly twice the impedance.
Every number here is computed by the program on the GPU; the page only reads the values back and draws them. The materials, the media and the sweep are the program's settings, which the host may write; this page offers no control to change them yet.
The program¶
The sweep, the law's answers and the checks, the panels the page draws, and the one procedure, main, run each step: the sweep moves on, the kernels are asked for the bar and the media, and the checks are taken.
// The acoustic impedance's live page: a bar of steel's density swept through stiffnesses, its impedance from the
// library's speed of sound and impedance beside the closed form sqrt(E rho), and the share of a sound wave reflected
// where air meets water and water meets steel, with the page's checks computed here on the GPU and shown by the panels
// the program declares.
namespace acoustic_impedance;
lusine.version version = { { number = 1 } };
// The reader's settings: the library's steel and copper, each a phase with a stiffness and a density; water and air
// as Kinsler et al. tabulate them (their appendix A10); and the sweep: how far each step moves the bar's stiffness,
// from none.
host struct {
relation<lusine.materials.mechanical_phases> steel
= lusine.materials.mechanical_phases[lusine.materials.substances["steel"], "solid"];
relation<lusine.materials.mechanical_phases> copper
= lusine.materials.mechanical_phases[lusine.materials.substances["copper"], "solid"];
float<kg/m3> water_density = 998.0 kg/m3; float<m/s> water_speed = 1481.0 m/s;
float<kg/m3> air_density = 1.21 kg/m3; float<m/s> air_speed = 343.0 m/s;
float<Pa> stride = 1500000000.0 Pa;
} settings;
// The sweep: the step it is at, from 0 to 159 and round again, and the bar's stiffness there, also as a number of
// gigapascals for the chart's axis.
struct { integer step = -1; float<Pa> stiffness; float gigapascals; } sweep;
// The bar's impedance from the library's two kernels, beside the closed form sqrt(E rho); the impedances of the
// library's steel and copper, of water and of air; and the shares of a wave's pressure reflected where air meets water
// and where water meets steel, (Z2 - Z1) / (Z2 + Z1); and the bar's two as numbers of MPa s/m, for the chart.
struct {
float bar_chart; float closed_chart; float<Pa*s/m> bar; float<Pa*s/m> closed_form;
float<Pa*s/m> steel; float<Pa*s/m> copper; float<Pa*s/m> water;
float<Pa*s/m> air; float air_to_water; float water_to_steel;
} law;
// The checks: the bar's impedance within 0.0001% of sqrt(E rho) at every stiffness; the library's steel and copper at
// 39.62 and 34.13 MPa s/m and Kinsler's water at 1.478 MPa s/m, each within 0.01 MPa s/m; the reflections, 0.9994 of
// the pressure where air meets water and 0.928 where water meets steel; and the impedance doubled, exactly, by twice
// the density or twice the speed.
struct { bool bar = true; bool tabulated = true; bool reflects = true; bool proportional = true; } checks;
// A strip of lamps the page draws, lit green while every check holds and red once one fails.
struct lamp { vector<float, 4> colour; };
lattice<lamp, 2> lamps(spacing = 1 m, boundary = wall);
vector<float, 4> lamp_colour(bool holds)
{
return holds ? vector<float, 4>(0.15, 0.6, 0.3, 1.0) : vector<float, 4>(0.75, 0.15, 0.15, 1.0);
}
float<Pa> stiffness(relation<lusine.materials.mechanical_phases> phase) { return phase.stiffness; }
float<kg/m3> density(relation<lusine.materials.mechanical_phases> phase) { return phase.density; }
// A phase's impedance, from its own stiffness and density through the library's speed of sound.
float<Pa*s/m> phase_impedance(relation<lusine.materials.mechanical_phases> phase)
{
return lusine.properties.acoustic_impedance(density = density(phase),
speed = lusine.properties.speed_of_sound(stiffness = stiffness(phase),
density = density(phase)));
}
float reflected(float<Pa*s/m> from, float<Pa*s/m> into) { return (into - from) / (into + from); }
// Twice the density, or twice the speed, gives exactly twice the impedance (a doubling is exact in binary32).
bool doubles(float<kg/m3> density, float<m/s> speed)
{
let once = lusine.properties.acoustic_impedance(density, speed);
return lusine.properties.acoustic_impedance(density = 2.0 * density, speed) == 2.0 * once
&& lusine.properties.acoustic_impedance(density, speed = 2.0 * speed) == 2.0 * once;
}
bool near(float<Pa*s/m> got, float<Pa*s/m> want) { return abs(got - want) <= 10000.0 Pa*s/m; }
output table<lusine.widget> panels = {
lusine.series { { panel = "the bar", chart = "impedance", quantity = law.bar_chart, steps = 160,
against = sweep.gigapascals, label = "the kernels, MPa s/m" } },
lusine.series { { panel = "the bar", chart = "impedance", quantity = law.closed_chart, steps = 160,
against = sweep.gigapascals, label = "sqrt(E rho), MPa s/m" } },
lusine.value { { panel = "the bar", quantity = sweep.stiffness, label = "stiffness" } },
lusine.value { { panel = "the bar", quantity = law.bar, label = "impedance" } },
lusine.value { { panel = "the media", quantity = law.steel, label = "steel" } },
lusine.value { { panel = "the media", quantity = law.copper, label = "copper" } },
lusine.value { { panel = "the media", quantity = law.water, label = "water" } },
lusine.value { { panel = "the media", quantity = law.air, label = "air" } },
lusine.value { { panel = "the media", quantity = law.air_to_water, label = "air into water reflects" } },
lusine.value { { panel = "the media", quantity = law.water_to_steel, label = "water into steel reflects" } },
lusine.value { { panel = "the checks", quantity = checks.bar, label = "sqrt(E rho)" } },
lusine.value { { panel = "the checks", quantity = checks.tabulated, label = "the tables' values" } },
lusine.value { { panel = "the checks", quantity = checks.reflects, label = "reflections" } },
lusine.value { { panel = "the checks", quantity = checks.proportional, label = "proportional" } },
};
void main()
{
sweep.step = sweep.step >= 159 ? 0 : sweep.step + 1;
sweep.stiffness = float(sweep.step) * settings.stride;
law.bar = lusine.properties.acoustic_impedance(density = density(phase = settings.steel),
speed = lusine.properties.speed_of_sound(
sweep.stiffness, density = density(phase = settings.steel)));
law.closed_form = sqrt(sweep.stiffness * density(phase = settings.steel));
sweep.gigapascals = sweep.stiffness / 1000000000.0 Pa;
law.bar_chart = law.bar / 1000000.0 Pa*s/m;
law.closed_chart = law.closed_form / 1000000.0 Pa*s/m;
law.steel = phase_impedance(phase = settings.steel);
law.copper = phase_impedance(phase = settings.copper);
law.water = lusine.properties.acoustic_impedance(density = settings.water_density,
speed = settings.water_speed);
law.air = lusine.properties.acoustic_impedance(density = settings.air_density, speed = settings.air_speed);
law.air_to_water = reflected(from = law.air, into = law.water);
law.water_to_steel = reflected(from = law.water, into = law.steel);
checks.bar = checks.bar && abs(law.bar - law.closed_form) <= 0.000001 * law.closed_form;
checks.tabulated = checks.tabulated && near(got = law.steel, want = 39623000.0 Pa*s/m)
&& near(got = law.copper, want = 34130000.0 Pa*s/m)
&& near(got = law.water, want = 1478000.0 Pa*s/m);
checks.reflects = checks.reflects && law.air_to_water > 0.9994 && law.air_to_water < 0.9995
&& law.water_to_steel > 0.927 && law.water_to_steel < 0.929;
checks.proportional = checks.proportional && doubles(density = settings.water_density, speed = settings.water_speed);
lamps.colour = lamp_colour(holds = checks.bar && checks.tabulated && checks.reflects && checks.proportional);
}
The law's other proof (every bar in the library, and proportionality over media at random) is on its proof page.