The speed of sound in a bar, live¶
The speed of a longitudinal wave along a thin solid bar, c = √(E / ρ), from its Young's modulus E and its density ρ: the thin-rod speed, for a bar much thinner than the wavelength and free to swell sideways, slower than the bulk longitudinal speed. 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 law (lusine.properties.speed_of_sound) gives its speed on your GPU as you read, beside a bar four times as dense. The program holds what the law promises without restating it: ρc² is the modulus again, and the library's own steel and copper carry a wave at the bar speeds Kinsler, Frey, Coppens and Sanders tabulate (Fundamentals of Acoustics, 4th ed., appendix A10: steel 5050 m/s, copper 3810 m/s).
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 speed against its stiffness in GPa, a point a step over one whole sweep, and the speed in a bar four times as dense, which runs at exactly half of it all the way. Below it, the stiffness, the speed there and ρc², the stiffness again.
- The solids: the bar speeds of the library's steel (200 GPa, 7850 kg/m³) and copper (130 GPa, 8960 kg/m³), each from its own row, beside Kinsler's.
- The checks, each held at every step: ρc² is E, within 0.0001%; four times, four times as stiff carrying the wave exactly twice as fast and four times as dense exactly half as fast, bit for bit, since a power of four scales E / ρ without rounding and the square root is correctly rounded; Kinsler's bars, steel and copper each within 0.1% of the tabulated speed.
Every number here is computed by the program on the GPU; the page only reads the values back and draws them. The materials, the tabulated speeds 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 law is asked for the bar, the dense bar and the library's solids, and the checks are taken.
// The speed of sound's live page: a bar of steel's density swept through stiffnesses, the library's bar speed at each
// and at four times the density, held to rho c^2 = E and to Kinsler's tabulated bar speeds of steel and copper, with
// the page's checks computed here on the GPU and shown by the panels the program declares.
namespace speed_of_sound;
lusine.version version = { { number = 1 } };
// The reader's settings: the library's steel and copper, each a phase with a stiffness and a density; Kinsler et
// al.'s tabulated bar speeds of the two (their appendix A10); and 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<m/s> steel_tabulated = 5050.0 m/s; float<m/s> copper_tabulated = 3810.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 speed at steel's density and at four times it; rho c^2 at steel's density, which is the stiffness again;
// and the library's steel and copper, each from its own stiffness and density.
struct {
float<m/s> bar; float<m/s> dense; float<Pa> modulus; float<m/s> steel; float<m/s> copper;
} law;
// The checks: rho c^2 the stiffness within 0.0001% at every step; four times as stiff twice as fast, and four times
// as dense half as fast, exactly; and the library's steel and copper within 0.1% of Kinsler's bar speeds.
struct { bool modulus = true; bool fourfold = true; bool tabulated = 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; }
float<m/s> bar_speed(relation<lusine.materials.mechanical_phases> phase)
{
return lusine.properties.speed_of_sound(stiffness = stiffness(phase), density = density(phase));
}
// Four times as stiff carries the wave exactly twice as fast, four times as dense exactly half as fast: a power of four
// scales E / rho without rounding, and the square root is correctly rounded.
bool fourfold(float<Pa> stiffness, float<kg/m3> density)
{
let once = lusine.properties.speed_of_sound(stiffness, density);
return lusine.properties.speed_of_sound(stiffness = 4.0 * stiffness, density) == 2.0 * once
&& lusine.properties.speed_of_sound(stiffness, density = 4.0 * density) == 0.5 * once;
}
bool close_to(float<m/s> got, float<m/s> want) { return abs(got / want - 1.0) <= 0.001; }
output table<lusine.widget> panels = {
lusine.series { { panel = "the bar", chart = "bar speed", quantity = law.bar, steps = 160,
against = sweep.gigapascals, label = "steel's density" } },
lusine.series { { panel = "the bar", chart = "bar speed", quantity = law.dense, steps = 160,
against = sweep.gigapascals, label = "four times as dense" } },
lusine.value { { panel = "the bar", quantity = sweep.stiffness, label = "stiffness" } },
lusine.value { { panel = "the bar", quantity = law.bar, label = "speed" } },
lusine.value { { panel = "the bar", quantity = law.modulus, label = "rho c^2" } },
lusine.value { { panel = "the solids", quantity = law.steel, label = "steel" } },
lusine.value { { panel = "the solids", quantity = settings.steel_tabulated, label = "Kinsler's steel bar" } },
lusine.value { { panel = "the solids", quantity = law.copper, label = "copper" } },
lusine.value { { panel = "the solids", quantity = settings.copper_tabulated, label = "Kinsler's copper bar" } },
lusine.value { { panel = "the checks", quantity = checks.modulus, label = "rho c^2 is E" } },
lusine.value { { panel = "the checks", quantity = checks.fourfold, label = "four times" } },
lusine.value { { panel = "the checks", quantity = checks.tabulated, label = "Kinsler's bars" } },
};
void main()
{
sweep.step = sweep.step >= 159 ? 0 : sweep.step + 1;
sweep.stiffness = float(sweep.step) * settings.stride;
sweep.gigapascals = sweep.stiffness / 1000000000.0 Pa;
law.bar = lusine.properties.speed_of_sound(sweep.stiffness, density = density(phase = settings.steel));
law.dense = lusine.properties.speed_of_sound(sweep.stiffness, density = 4.0 * density(phase = settings.steel));
law.modulus = density(phase = settings.steel) * law.bar * law.bar;
law.steel = bar_speed(phase = settings.steel);
law.copper = bar_speed(phase = settings.copper);
checks.modulus = checks.modulus && abs(law.modulus - sweep.stiffness) <= 0.000001 * sweep.stiffness;
checks.fourfold = checks.fourfold && fourfold(sweep.stiffness, density = density(phase = settings.steel));
checks.tabulated = checks.tabulated && close_to(got = law.steel, want = settings.steel_tabulated)
&& close_to(got = law.copper, want = settings.copper_tabulated);
lamps.colour = lamp_colour(holds = checks.modulus && checks.fourfold && checks.tabulated);
}
The law's other proof (every solid in the library, and ρc² over solids at random) is on its proof page.