feat: compare localization algorithms in camera
This commit is contained in:
@@ -1,4 +1,8 @@
|
||||
import { getFrameCount, binsForBand } from "/packages/acoustics-core/stft.js";
|
||||
import {
|
||||
DEFAULT_LOCALIZATION_ALGORITHM,
|
||||
localizationAlgorithmDefinition,
|
||||
} from "/packages/acoustics-core/localization-algorithms.js";
|
||||
|
||||
const RESULT_METRIC_KEYS = [
|
||||
"peakToSidelobeDb",
|
||||
@@ -25,6 +29,17 @@ export function canonicalStringify(value) {
|
||||
return JSON.stringify(sortForCanonicalJson(value));
|
||||
}
|
||||
|
||||
export function createComparisonSignature(scene, sourceExperiment) {
|
||||
if (!scene || !sourceExperiment) return "";
|
||||
const experiment = structuredClone(sourceExperiment);
|
||||
experiment.arrayId = "$array";
|
||||
if (experiment.beamforming) {
|
||||
experiment.beamforming.algorithm = "$algorithm";
|
||||
experiment.beamforming.backend = "$backend";
|
||||
}
|
||||
return canonicalStringify({ scene, experiment });
|
||||
}
|
||||
|
||||
export async function hashSimulationInputs({ arrayDefinition, scene, experiment }) {
|
||||
const canonical = canonicalStringify({ array: arrayDefinition, experiment, scene });
|
||||
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(canonical));
|
||||
@@ -42,17 +57,38 @@ export function estimateExperimentWorkload(arrayDefinition, scene, experiment) {
|
||||
const bandBins = experiment.frequencyBands.map((band) =>
|
||||
binsForBand(band, scene.sampleRate, experiment.stft.fftSize),
|
||||
);
|
||||
const bandBinSelectionCount = bandBins.reduce((total, bins) => total + bins.length, 0);
|
||||
const selectedBinCount = new Set(bandBins.flat()).size;
|
||||
const pointCount = experiment.scan.columns * experiment.scan.rows;
|
||||
const microphoneCount = arrayDefinition.microphones.length;
|
||||
const complexMacCount = pointCount * microphoneCount * frameCount * selectedBinCount;
|
||||
const algorithm = experiment.beamforming?.algorithm ?? DEFAULT_LOCALIZATION_ALGORITHM;
|
||||
const algorithmDefinition = localizationAlgorithmDefinition(algorithm);
|
||||
const referencePairCount = Math.max(0, microphoneCount - 1);
|
||||
const stftTransformCount = frameCount * microphoneCount;
|
||||
const dasComplexMacCount = pointCount * microphoneCount * frameCount * selectedBinCount;
|
||||
const gccCrossSpectrumComplexOps =
|
||||
2 * referencePairCount * frameCount * bandBinSelectionCount;
|
||||
const gccScanScoreOps = pointCount * referencePairCount * bandBins.length;
|
||||
const inverseFftTransformCount = referencePairCount * bandBins.length;
|
||||
const scanOperationCount = algorithm === "gcc-phat" ? gccScanScoreOps : dasComplexMacCount;
|
||||
return {
|
||||
algorithm,
|
||||
algorithmLabel: algorithmDefinition?.label ?? algorithm,
|
||||
rawScale: algorithmDefinition?.rawScale ?? "power",
|
||||
pointCount,
|
||||
microphoneCount,
|
||||
frameCount,
|
||||
selectedBinCount,
|
||||
bandBinSelectionCount,
|
||||
minimumBandBinCount: Math.min(...bandBins.map((bins) => bins.length)),
|
||||
bandBins,
|
||||
complexMacCount,
|
||||
stftTransformCount,
|
||||
referencePairCount,
|
||||
scanOperationCount,
|
||||
scanOperationKind: algorithm === "gcc-phat" ? "reference-pair lookup" : "complex MAC",
|
||||
gccCrossSpectrumComplexOps: algorithm === "gcc-phat" ? gccCrossSpectrumComplexOps : 0,
|
||||
inverseFftTransformCount: algorithm === "gcc-phat" ? inverseFftTransformCount : 0,
|
||||
complexMacCount: algorithm === "gcc-phat" ? 0 : dasComplexMacCount,
|
||||
scalingVs50: pointCount / 2500,
|
||||
distanceMiB: (pointCount * microphoneCount * 4) / 1024 ** 2,
|
||||
};
|
||||
@@ -207,6 +243,14 @@ function environmentForResult({ arrayDefinition, experiment, run }) {
|
||||
if (adapter?.architecture) environment.gpuArchitecture = adapter.architecture;
|
||||
if (adapter?.device) environment.gpuDevice = adapter.device;
|
||||
if (run.gpu?.timingKind) environment.gpuTimingKind = run.gpu.timingKind;
|
||||
const referenceMic =
|
||||
run.referenceMic ??
|
||||
run.referenceMicrophoneId ??
|
||||
run.workload?.referenceMic ??
|
||||
run.workload?.referenceMicrophoneId;
|
||||
if (typeof referenceMic === "string" || Number.isFinite(referenceMic)) {
|
||||
environment.referenceMic = referenceMic;
|
||||
}
|
||||
return environment;
|
||||
}
|
||||
|
||||
@@ -220,6 +264,8 @@ export function createResultDocument(options) {
|
||||
inputHash,
|
||||
createdAt = new Date().toISOString(),
|
||||
} = options;
|
||||
const algorithm = run.algorithm ?? experiment.beamforming?.algorithm ?? DEFAULT_LOCALIZATION_ALGORITHM;
|
||||
const rawScale = localizationAlgorithmDefinition(algorithm)?.rawScale ?? "power";
|
||||
return {
|
||||
schemaVersion: "1.0.0",
|
||||
kind: "micarrsim.result",
|
||||
@@ -227,6 +273,7 @@ export function createResultDocument(options) {
|
||||
arrayId: arrayDefinition.id,
|
||||
sceneId: scene.id,
|
||||
createdAt,
|
||||
algorithm,
|
||||
backend: run.backend,
|
||||
inputHash,
|
||||
signalStats: {
|
||||
@@ -246,7 +293,8 @@ export function createResultDocument(options) {
|
||||
timingMs: {
|
||||
total: run.timingMs.total,
|
||||
signalGeneration: run.timingMs.signalGeneration,
|
||||
beamforming: run.timingMs.beamforming,
|
||||
localization: run.timingMs.localization ?? run.timingMs.beamforming,
|
||||
beamforming: run.timingMs.beamforming ?? run.timingMs.localization,
|
||||
},
|
||||
environment: environmentForResult({ arrayDefinition, experiment, run }),
|
||||
bands: run.bands.map((band) => {
|
||||
@@ -257,7 +305,7 @@ export function createResultDocument(options) {
|
||||
rawMap: {
|
||||
rows: experiment.scan.rows,
|
||||
columns: experiment.scan.columns,
|
||||
scale: "power",
|
||||
scale: band.rawScale ?? rawScale,
|
||||
values: Array.from(band.rawMap),
|
||||
},
|
||||
displayMap: {
|
||||
@@ -286,9 +334,11 @@ export function createHistorySummary({ arrayDefinition, scene, experiment, run,
|
||||
arrayName: arrayDefinition.name,
|
||||
sceneId: scene.id,
|
||||
experimentId: experiment.id,
|
||||
algorithm: run.algorithm ?? experiment.beamforming?.algorithm ?? DEFAULT_LOCALIZATION_ALGORITHM,
|
||||
backend: run.backend,
|
||||
pointCount: experiment.scan.rows * experiment.scan.columns,
|
||||
totalMs: run.timingMs.total,
|
||||
localizationMs: run.timingMs.localization ?? run.timingMs.beamforming,
|
||||
localizationErrorM: firstMatchedPeak?.localizationErrorM ?? null,
|
||||
peakToSidelobeDb: evaluation?.metrics?.peakToSidelobeDb ?? null,
|
||||
inputHash,
|
||||
|
||||
Reference in New Issue
Block a user