42 lines
1.5 KiB
JavaScript
42 lines
1.5 KiB
JavaScript
import {
|
|
describeFrequencyAliasing,
|
|
observeFrequencyBand,
|
|
} from "/packages/acoustics-core/sampling.js";
|
|
|
|
/**
|
|
* Select evaluation truth sources for one observed band.
|
|
*
|
|
* Arrival ids come from synthesis path timing and take precedence over the
|
|
* legacy emission-time fallback. This helper is evaluation-only; localization
|
|
* never receives truth positions or ids.
|
|
*/
|
|
export function sourcesForObservedBand(
|
|
scene,
|
|
band,
|
|
fftSize,
|
|
options = {},
|
|
) {
|
|
const observation = observeFrequencyBand(band, scene.sampleRate, fftSize);
|
|
const observedBins = new Set(observation.bins);
|
|
const arrivingSourceIdSet = Array.isArray(options.arrivingSourceIds)
|
|
? new Set(options.arrivingSourceIds)
|
|
: null;
|
|
const time = options.time ?? null;
|
|
return scene.sources.filter((source) => {
|
|
if (arrivingSourceIdSet) {
|
|
if (!arrivingSourceIdSet.has(source.id)) return false;
|
|
} else if (time !== null) {
|
|
const startTime = source.startTime ?? 0;
|
|
const endTime = startTime + (source.duration ?? scene.duration);
|
|
if (time < startTime || time >= endTime) return false;
|
|
}
|
|
if (source.signal.type !== "tone") return true;
|
|
const analogInside =
|
|
source.signal.frequency >= band.minHz && source.signal.frequency <= band.maxHz;
|
|
if (analogInside) return true;
|
|
const alias = describeFrequencyAliasing(source.signal.frequency, scene.sampleRate);
|
|
const nearestAdcBin = Math.round(alias.adcFrequencyHz / observation.binWidthHz);
|
|
return observedBins.has(nearestAdcBin);
|
|
});
|
|
}
|