feat: add physically explicit narrowband MUSIC

This commit is contained in:
2026-08-29 12:40:48 +09:00
parent 044be3cf92
commit 11fee76280
40 changed files with 6473 additions and 275 deletions
+34 -3
View File
@@ -83,6 +83,7 @@ Portable plan은 top-level `algorithm`으로 위치 추정기를 선택한다.
| `das` | frequency-domain delay-and-sum | `power` | CPU |
| `das-phat` | phase-only spectrum을 steering하는 DAS | `score` | CPU |
| `gcc-phat` | 한 reference mic에 대한 `M-1`개 GCC-PHAT 지연 scan | `score` | CPU only |
| `music` | 표준 좁은대역 Schmidt noise-subspace scan | `noise-projection` | CPU only |
같은 array·scan·band·STFT로 알고리즘을 비교할 때도 알고리즘마다 별도 plan을 만든다.
@@ -103,6 +104,14 @@ const gccPhatPlan = createLocalizationPlan({
algorithm: "gcc-phat",
phatFloorRatio: 1e-6,
});
const musicPlan = createLocalizationPlan({
...commonConfig,
algorithm: "music",
normalization: "none",
musicSourceCountMethod: "fixed",
musicSourceCount: 1,
});
```
`phatRelativeFloor`는 DAS-PHAT의 channel spectrum 정규화 floor이고, `phatFloorRatio`는
@@ -151,7 +160,7 @@ const plan = createLocalizationPlan({
{ id: "machine", minHz: 900, maxHz: 1100, color: "#65f2bf" },
],
stft: { fftSize: 512, hopSize: 256 },
algorithm: "das", // "das" | "das-phat" | "gcc-phat"
algorithm: "das", // "das" | "das-phat" | "gcc-phat" | "music"
speedOfSound: 343,
normalization: "peak",
compensateFrequencyResponse: true,
@@ -174,7 +183,7 @@ const plan = createLocalizationPlan({
- scan의 `columns`와 `rows`는 양의 정수
- `speedOfSound`는 양수
- `normalization`은 `peak` 또는 `none`
- `algorithm`은 `das`, `das-phat`, `gcc-phat` 중 하나
- `algorithm`은 `das`, `das-phat`, `gcc-phat`, `music` 중 하나
- `phatRelativeFloor`와 `phatFloorRatio`는 지정한 경우 0–1
- `maxCompensationDb`는 0–120 dB
- `peakDetection.thresholdRatio`는 0–1,
@@ -186,7 +195,29 @@ const plan = createLocalizationPlan({
STFT·correlation workspace를 유지한다. 같은 계획으로 두 분석을 동시에 실행하지 말고 worker마다
별도 계획을 만든다. Array·scan·band·STFT·알고리즘을 바꾸면 새 계획을 만들어야 한다.
Portable plan의 generic cache는 `plan.analysisPlan`이며 기존 호출자를 위해 DAS 계열에는
`plan.dasPlan`, GCC-PHAT에는 `plan.gccPhatPlan` alias도 제공한다.
`plan.dasPlan`, GCC-PHAT에는 `plan.gccPhatPlan`, MUSIC에는 `plan.musicPlan` alias도 제공한다.
### MUSIC 포팅 경계
MUSIC raw `q = ||E_n^H a||²/(a^H a)`는 작은 값이 좋은 noise projection이다. 표시용
`P/Pmax = q_min/q`도 확률·신뢰도·Gaussian 신뢰구간이 아니며, raw q 보존을 위해
`normalization: "none"`만 허용한다.
band마다 사용자가 지정한 analog FFT-grid 가설 하나와 접힌 positive ADC bin 하나만 사용한다.
Scene carrier/위치 truth는 읽지 않는다. analog carrier `f_a`의 공간 위상을 alias orientation
`η`로 `exp[-j η 2π f_a Δr/c]`에 적용하며, inversion이면 calibration과 steering을 포함한
전체 complex manifold를 켤레화한다. 정확한 DC/Nyquist는 quadrature-degenerate라 거절한다.
Fixed K는 `1..M-1`이다. Wax–Kailath MDL/AIC는 complete non-overlapping frame, `T > M`,
strict-positive noise eigenvalue, IID complex Gaussian snapshot·spatially white noise·고정 K를
가정한다. non-overlap은 독립성의 증명이 아니다. 조건 불충족과 식별 불가능한 partition은
`MusicUnavailableError` (`code: "MUSIC_UNAVAILABLE"`)이며 fixed fallback은 없다.
diagonal loading, floor, spatial smoothing, multibin/wideband fusion도 없다. grating lobe,
동률과 coherent rank deficiency를 결과가 좋아 보이도록 제거하지 않는다.
계획은 allocation 전에 typed working bytes, FFT butterfly, covariance complex accumulation,
Jacobi pair update와 projection MAC 상한을 검사한다. 이 CPU cap은 메모리·응답성 보호 장치이지
realtime 보장이 아니므로 `processingTimeMs`와 streaming deadline 통계를 대상 장치에서 측정한다.
portable 계획의 기본 scan point batch는 DAS 계열 256개, GCC-PHAT 4,096개이고 STFT transform
batch는 128개다. GCC-PHAT cross-spectrum은 16,384 operation 단위로도 양보한다. 각 batch 경계에서