/** * Everything in SI: metres, seconds, hertz, metres per second. * * The domain is deliberately small. A three-dimensional grid costs the cube of * its resolution, so where the flat sibling can afford 512 points across ten * metres this one gets 128 across two, and the number that decides whether * what is on screen is physics or grid dispersion is the same either way: how * many cells fit in a wavelength. At 128 points across 2 m a 1.5 kHz tone is * about fifteen cells per wavelength, which is comfortable; raise the * frequency and the app says when it stops being so. */ /** Speed of sound in air at about 20 °C, m/s. */ export const C_AIR = 343; /** Side of the cubic domain, metres. Room-corner sized rather than * hall sized, for the reason above. */ export const DOMAIN = 2; /** Fraction of the domain given to the absorbing layer at each face. */ export const SPONGE_FRAC = 0.15; /** Absorption rate the sponge reaches at the wall, inverse seconds. */ export const SPONGE_MAX = 9000; /** Cells per wavelength below which what is on screen is as much grid * dispersion as it is sound. */ export const POOR_RESOLUTION = 8; /** A length in metres, written the way a person would say it. */ export const fmtLength = (m: number): string => Math.abs(m) < 1 ? `${(1000 * m).toPrecision(3)} mm` : `${m.toPrecision(3)} m`; /** A duration in seconds, likewise. */ export const fmtTime = (s: number): string => { const a = Math.abs(s); if (a > 0 && a < 1e-3) return `${(1e6 * s).toPrecision(3)} µs`; if (a < 1) return `${(1e3 * s).toPrecision(3)} ms`; return `${s.toPrecision(3)} s`; };