fix: expose physical aliasing and delayed arrivals

This commit is contained in:
2026-08-29 10:21:33 +09:00
parent e048ccbadc
commit de0053eae3
38 changed files with 3086 additions and 214 deletions
+4
View File
@@ -3,6 +3,10 @@
이미지 평면에 source ground truth를 배치하고 tone, noise, 로컬 audio asset과 ambient를 조합해
재현 가능한 `micarrsim.scene` JSON을 만드는 브라우저 앱입니다.
Tone 주파수는 Scene Nyquist 위도 입력할 수 있습니다. source 카드는 anti-alias filter 없는 이상적
ADC에서 관측될 alias 주파수를 함께 표시합니다. 이는 고주파를 복원하거나 감쇠시키는 기능이 아니며,
실제 장치의 analog anti-alias filter는 별도 모델 대상입니다.
## 열기
저장소의 `start.cmd`를 실행한 뒤 시작 화면에서 **Dataset Builder**를 선택하거나
+1 -1
View File
@@ -150,7 +150,7 @@
</div>
</section>
<label class="field field--wide"><span>신호 종류</span><select id="source-type"><option value="tone">Tone</option><option value="noise">Noise</option><option value="asset">Audio asset</option></select></label>
<div id="tone-fields"><label class="field field--wide"><span>주파수 (Hz)</span><input id="tone-frequency" type="number" min="1" step="1" /></label></div>
<div id="tone-fields"><label class="field field--wide" title="Nyquist를 넘어도 허용됩니다. 0–1 MHz는 현재 수치·마이크 모델의 검증 범위이며, 이상적 anti-alias filter 없는 ADC에서 접힌 주파수는 source 카드에 표시됩니다."><span>아날로그 tone 주파수 (Hz)</span><input id="tone-frequency" type="number" min="1" max="1000000" step="1" /></label></div>
<div id="noise-fields"><label class="field field--wide"><span>Noise color</span><select id="noise-color"><option value="white">White</option><option value="pink">Pink</option></select></label></div>
<div id="asset-fields">
<label class="field field--wide"><span>Audio asset</span><select id="source-asset"></select></label>
+2 -1
View File
@@ -190,7 +190,7 @@ function renderSourceCards() {
name.title = source.name;
heading.append(dot, name);
const signal = document.createElement("small");
signal.textContent = describeSignal(source.signal);
signal.textContent = describeSignal(source.signal, state.scene.sampleRate);
const position = document.createElement("small");
const motion = Array.isArray(source.trajectory) ? ` · 이동 ${source.trajectory.length}점` : "";
position.textContent = `x ${source.position[0].toFixed(2)} · y ${source.position[1].toFixed(2)} · z ${source.position[2].toFixed(2)} m${motion}`;
@@ -683,6 +683,7 @@ function bindSceneControls() {
if (asset.kind === "audio") state.assetErrors.delete(asset.id);
}
renderAssetList();
renderSourceCards();
}, "change");
bindInput("speed-of-sound", (input) => { state.scene.speedOfSound = numberFrom(input); });
bindInput("scene-seed", (input) => { state.scene.seed = numberFrom(input); });
+16 -2
View File
@@ -1,3 +1,5 @@
import { describeFrequencyAliasing } from "/packages/acoustics-core/sampling.js";
export const DEFAULT_VIEW_PLANE = Object.freeze({
xMin: -0.6,
xMax: 0.6,
@@ -192,8 +194,20 @@ export function changeSignalType(source, type, firstAudioAssetId = "") {
}
}
export function describeSignal(signal) {
if (signal.type === "tone") return `${signal.frequency} Hz tone`;
export function describeSignal(signal, sampleRate) {
if (signal.type === "tone") {
if (!Number.isFinite(sampleRate)) return `${signal.frequency} Hz tone`;
const observation = describeFrequencyAliasing(signal.frequency, sampleRate);
const alias = observation.aliased
? ` → ADC ${observation.adcFrequencyHz} Hz alias`
: "";
const edge = observation.dcEdge
? " · DC phase-degenerate edge"
: observation.nyquistEdge
? " · Nyquist phase-degenerate edge"
: "";
return `${signal.frequency} Hz tone${alias}${edge}`;
}
if (signal.type === "noise") return `${signal.color} noise`;
if (signal.type === "asset") return `asset · ${signal.assetId || "미선택"}`;
return "알 수 없는 신호";