nordic-skating / mistral-medium-35-littlejs / files / test / acoustics.test.ts
Branch mistral-medium-35-littlejs · default branch · all branches
acoustics.test.ts
| 1 | import { describe, expect, it } from 'vitest' |
| 2 | import { |
| 3 | SOUND_SPEED_AIR, chirp, groupSpeed, phaseSpeed, singingFrequency, thicknessFromFrequency, |
| 4 | travelTime, wavenumber, |
| 5 | } from '../src/ice/acoustics.js' |
| 6 | |
| 7 | describe('ice acoustics', () => { |
| 8 | it('agrees with the ice measured in the paper the model is from', () => { |
| 9 | // Romeyn et al. 2021: the film's lake, about 725 Hz from about 4.3 cm; and a lake |
| 10 | // whose ice quakes had a 190 Hz component, about 16 cm. |
| 11 | expect(thicknessFromFrequency(725)).toBeCloseTo(0.043, 2) |
| 12 | expect(thicknessFromFrequency(190)).toBeCloseTo(0.16, 2) |
| 13 | }) |
| 14 | |
| 15 | it('sings higher the thinner it is, and very nearly in inverse proportion', () => { |
| 16 | expect(singingFrequency(0.03)).toBeGreaterThan(singingFrequency(0.05)) |
| 17 | for (const h of [0.02, 0.04, 0.08, 0.2]) { |
| 18 | expect(singingFrequency(h) * h).toBeCloseTo(30.3, 0) |
| 19 | expect(thicknessFromFrequency(singingFrequency(h))).toBeCloseTo(h, 6) |
| 20 | } |
| 21 | }) |
| 22 | |
| 23 | it('sings at the frequency whose bending wave keeps step with sound in air', () => { |
| 24 | const h = 0.041 |
| 25 | const note = singingFrequency(h) |
| 26 | expect(phaseSpeed(wavenumber(note, h), h)).toBeCloseTo(SOUND_SPEED_AIR, 3) |
| 27 | // Above the note the wave outruns sound in air and can radiate; below it, it cannot. |
| 28 | expect(phaseSpeed(wavenumber(note * 2, h), h)).toBeGreaterThan(SOUND_SPEED_AIR) |
| 29 | expect(phaseSpeed(wavenumber(note / 2, h), h)).toBeLessThan(SOUND_SPEED_AIR) |
| 30 | }) |
| 31 | |
| 32 | it('carries high frequencies faster than low ones', () => { |
| 33 | const h = 0.041 |
| 34 | let before = 0 |
| 35 | for (const f of [200, 740, 1500, 3000, 6000]) { |
| 36 | const speed = groupSpeed(wavenumber(f, h), h) |
| 37 | expect(speed).toBeGreaterThan(before) |
| 38 | before = speed |
| 39 | } |
| 40 | expect(travelTime(6000, h, 100)).toBeLessThan(travelTime(740, h, 100)) |
| 41 | }) |
| 42 | |
| 43 | it('makes a chirp that falls onto the note, and falls for longer from further off', () => { |
| 44 | const h = 0.041 |
| 45 | const near = chirp(h, 50) |
| 46 | const far = chirp(h, 400) |
| 47 | for (const { frequencies } of [near, far]) { |
| 48 | expect(frequencies[0]).toBeCloseTo(6000, -1) |
| 49 | for (let i = 1; i < frequencies.length; i++) expect(frequencies[i]).toBeLessThan(frequencies[i - 1]!) |
| 50 | expect(frequencies[frequencies.length - 1]! / singingFrequency(h)).toBeCloseTo(1.02, 2) |
| 51 | } |
| 52 | expect(far.duration / near.duration).toBeCloseTo(8, 5) |
| 53 | // A crack 400 m off falls for a third of a second: long enough to hear as a "pew". |
| 54 | expect(far.duration).toBeGreaterThan(0.25) |
| 55 | expect(far.duration).toBeLessThan(0.5) |
| 56 | }) |
| 57 | }) |