fuzzyworld

nordic-skating / local-littlejs / files / test / acoustics.test.ts

Branch local-littlejs · default branch · all branches

acoustics.test.ts

Blame: the commit that last changed each line · file · history

174b4a1a 2026-10-09 Pavel Safronov1import { describe, expect, it } from 'vitest'
2import {
3 SOUND_SPEED_AIR, chirp, groupSpeed, phaseSpeed, singingFrequency, thicknessFromFrequency,
4 travelTime, wavenumber,
5} from '../src/ice/acoustics.js'
6
7describe('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})