feat: add comparable localization algorithms

This commit is contained in:
2026-08-28 20:20:57 +09:00
parent 7fe846fbf9
commit d58f673402
20 changed files with 2104 additions and 68 deletions
+53
View File
@@ -12,6 +12,48 @@ import {
} from "/packages/webgpu-kernels/das.js";
import { computeDasWithBackend } from "/packages/webgpu-kernels/compute.js";
test("WebGPU DAS-PHAT packing phase-normalizes above a relative floor", () => {
const stft = {
frameCount: 1,
microphoneCount: 3,
spectra: new Map([[
8,
{
real: Float32Array.of(3, 0, 1e-8),
imaginary: Float32Array.of(4, 2, 0),
},
]]),
};
const microphones = [
{
frequencyResponse: [
{ frequencyHz: 0, gainDb: 60, phaseDeg: 90 },
{ frequencyHz: 4_000, gainDb: 60, phaseDeg: 90 },
],
},
{
frequencyResponse: [
{ frequencyHz: 0, gainDb: -60, phaseDeg: 0 },
{ frequencyHz: 4_000, gainDb: -60, phaseDeg: 0 },
],
},
{},
];
const packed = packStftBatch(stft, [8], {
algorithm: "das-phat",
microphones,
sampleRate: 8_000,
fftSize: 256,
});
assertNear(packed[0], 0.8, 1e-6, "response-phase corrected real");
assertNear(packed[1], -0.6, 1e-6, "response-phase corrected imaginary");
assertNear(packed[2], 0, 1e-7, "second microphone real");
assertNear(packed[3], 1, 1e-7, "response gain is ignored");
assertEqual(packed[4], 0, "below-floor real is suppressed");
assertEqual(packed[5], 0, "below-floor imaginary is suppressed");
});
function assertNear(actual, expected, tolerance, label) {
assert(
Math.abs(actual - expected) <= tolerance,
@@ -53,6 +95,17 @@ test("WebGPU DAS uniform과 microphone calibration을 WGSL layout으로 packing
assertNear(calibration[3], Math.PI / 2, 1e-6, "+90 degree phase");
assertNear(calibration[4], 2, 1e-6, "-6 dB inverse gain");
assertNear(calibration[5], -Math.PI / 4, 1e-6, "-45 degree phase");
const phaseOnlyCalibration = packMicrophoneCalibration([
{ sensitivityDb: 0, phaseOffsetDeg: 0 },
{ sensitivityDb: 6.020599913, phaseOffsetDeg: 90 },
{ sensitivityDb: -6.020599913, phaseOffsetDeg: -45 },
], { includeAmplitude: false });
assertNear(phaseOnlyCalibration[0], 1, 1e-7, "phase-only unity gain 0");
assertNear(phaseOnlyCalibration[2], 1, 1e-7, "phase-only unity gain 1");
assertNear(phaseOnlyCalibration[4], 1, 1e-7, "phase-only unity gain 2");
assertNear(phaseOnlyCalibration[3], Math.PI / 2, 1e-6, "phase-only preserves +90 phase");
assertNear(phaseOnlyCalibration[5], -Math.PI / 4, 1e-6, "phase-only preserves -45 phase");
});
test("STFT batch를 bin-frame-microphone-complex 순서로 packing한다", () => {