docs: explain localization choices and cost
This commit is contained in:
@@ -6,7 +6,55 @@
|
||||
- 자유음장 직접음과 선택적 저비용 shoebox multipath
|
||||
- zero-padded FFT 전달함수 기반 fractional sample delay와 마이크 주파수 응답
|
||||
- radix-2 FFT, Hann STFT와 선택 bin 추출
|
||||
- scan grid 거리 cache 및 conventional frequency-domain DAS
|
||||
- scan grid 거리 cache 및 DAS·DAS-PHAT·GCC-PHAT 위치 추정
|
||||
|
||||
## 위치 추정 알고리즘
|
||||
|
||||
`localization-algorithms.js`의 registry와 `localization.js`의 generic API가 다음 세 경로를
|
||||
공통 interface로 제공합니다.
|
||||
|
||||
| `algorithm` | 계산 | raw scale | backend |
|
||||
| --- | --- | --- | --- |
|
||||
| `das` | conventional frequency-domain delay-and-sum | `power` | CPU, WebGPU |
|
||||
| `das-phat` | 채널 spectrum을 phase-only로 만든 DAS | `score` | CPU, WebGPU |
|
||||
| `gcc-phat` | 하나의 reference mic와 나머지 mic의 GCC-PHAT 지연 scan | `score` | CPU only |
|
||||
|
||||
Portable API에서는 top-level `algorithm`으로 선택합니다. 생략하면 기존과 같은 `das`이며, 낮은
|
||||
수준의 generic API는 `experiment.beamforming.algorithm`을 사용합니다.
|
||||
|
||||
```js
|
||||
import {
|
||||
createLocalizationPlan,
|
||||
localizeMultichannel,
|
||||
} from "./packages/acoustics-core/realtime-localizer.js";
|
||||
|
||||
const plan = createLocalizationPlan({
|
||||
...commonConfig, // sampleRate, array, scan, bands, stft
|
||||
algorithm: "gcc-phat", // "das" | "das-phat" | "gcc-phat"
|
||||
phatFloorRatio: 1e-6,
|
||||
});
|
||||
|
||||
// 반복 분석에서도 같은 plan을 재사용합니다.
|
||||
const result = await localizeMultichannel({ plan, channels });
|
||||
```
|
||||
|
||||
`das-phat`의 `phatRelativeFloor`와 `gcc-phat`의 `phatFloorRatio`는 모두 0~1의 상대
|
||||
크기 floor이며 기본값은 `1e-6`입니다. GCC-PHAT는 `phatRelativeFloor`도 호환 alias로
|
||||
받지만 새 코드에서는 알고리즘별 이름을 권장합니다. PHAT 경로는 mic gain을 위치 score에
|
||||
사용하지 않고 알려진 mic·frequency-response phase만 보정합니다.
|
||||
|
||||
GCC-PHAT는 단일 tone보다 여러 FFT bin에 에너지가 있는 broadband 입력을 권장합니다. 하나의
|
||||
band에 선택된 bin이 8개 미만이면 코어는 계산을 허용하지만 주기적 모호성과 ghost peak를 직접
|
||||
검증해야 합니다. 또한 reference pair의 scan 전체 최대 절대 기하 지연이 `fftSize / 2` sample을
|
||||
넘으면 circular correlation alias를 피하기 위해 plan 생성을 거절합니다. 이때는 `fftSize`를
|
||||
늘리거나 배열·scan 기하를 조정합니다.
|
||||
|
||||
각 band의 `rawScale`은 `power` 또는 `score`입니다. `rawValue`가 scale에 무관한 표준 peak
|
||||
값이며, `rawPower`는 `power`, `rawScore`는 `score`일 때만 쓰는 편의 alias입니다. `score`는
|
||||
확률·신뢰도·SPL이 아니고 동일 알고리즘·설정 안에서 상대 peak를 비교하는 비교정 값입니다.
|
||||
`power`도 입력과 calibration이 절대 단위로 교정되지 않았다면 물리적 W 또는 Pa²로 해석하지 않습니다.
|
||||
GCC-PHAT score는 pair 수, band coefficient 수와 IFFT 크기로 정규화한 0–1 양의 상관 응답이라
|
||||
scan 범위와 마이크 수에 의한 단순 재척도화는 피하지만, 여전히 확률로 보정된 confidence는 아닙니다.
|
||||
|
||||
## 실측 다채널 스트림 위치 추정
|
||||
|
||||
@@ -15,6 +63,10 @@
|
||||
디렉터리를 그대로 복사해 사용할 수 있습니다. 채널 순서는 `array.microphones` 순서와 같아야 하고
|
||||
각 chunk는 동일 길이의 `Float32Array` 목록이어야 합니다.
|
||||
|
||||
`StreamingLocalizer`는 알고리즘 중립 class 이름입니다. 기존 `StreamingDasLocalizer`와 같은 class의
|
||||
export alias이므로 오래된 import도 그대로 동작하며, `createStreamingLocalizer()` factory도 세
|
||||
알고리즘을 모두 지원합니다.
|
||||
|
||||
```js
|
||||
import { createStreamingLocalizer } from "./packages/acoustics-core/realtime-localizer.js";
|
||||
|
||||
@@ -24,6 +76,7 @@ const localizer = createStreamingLocalizer({
|
||||
scan: { xMin: -1, xMax: 1, yMin: -1, yMax: 1, z: 2, columns: 50, rows: 50 },
|
||||
bands: [{ id: "machine", minHz: 900, maxHz: 1100, color: "#65f2bf" }],
|
||||
stft: { fftSize: 512, hopSize: 256 },
|
||||
algorithm: "das", // 호환 기본값. "das-phat" 또는 "gcc-phat"도 선택할 수 있습니다.
|
||||
maxCompensationDb: 24,
|
||||
peakDetection: { thresholdRatio: 0.5, maximumDetections: 8 },
|
||||
analysisWindowSamples: 4_800,
|
||||
@@ -38,15 +91,17 @@ localizer.append(channels);
|
||||
// Analysis loop: 호출마다 설정된 상한 이하의 map만 반환합니다.
|
||||
const results = await localizer.analyzeAvailable({ signal: abortController.signal });
|
||||
for (const result of results) {
|
||||
const { position, rawPower } = result.locations[0];
|
||||
drawMarker(position, rawPower, result.centerTime);
|
||||
const { position, rawValue, rawScale } = result.locations[0];
|
||||
drawMarker(position, rawValue, rawScale, result.centerTime);
|
||||
if (!result.deadlineMet) reportOverload(result.processingTimeMs, result.deadlineMs);
|
||||
}
|
||||
```
|
||||
|
||||
`locations`는 band 순서, 같은 band 안에서는 raw power 내림차순의 평평한 목록입니다. 각 항목은
|
||||
기존 `{ bandId, index, position, rawPower }`에 `rank`를 더하며 같은 band의 여러 local peak를
|
||||
포함할 수 있습니다. `peakDetection.thresholdRatio` 기본값은 최강 peak의 0.5배,
|
||||
`locations`는 band 순서, 같은 band 안에서는 `rawValue` 내림차순의 평평한 목록입니다. 각 항목은
|
||||
`{ bandId, rank, index, position, rawValue, rawScale }`이며 같은 band의 여러 local peak를 포함할
|
||||
수 있습니다. 기존 DAS 결과의 `rawPower` 별칭은 그대로 유지됩니다. PHAT score는 `rawValue`와
|
||||
`rawScale`을 기준으로 읽고, score peak 객체에 포함된 경우 `rawScore`를 같은 값의 별칭으로 씁니다.
|
||||
`peakDetection.thresholdRatio` 기본값은 최강 peak의 0.5배,
|
||||
`minimumPeakDistanceM` 기본값은 scan cell 대각선, `maximumDetections` 기본값은 8입니다.
|
||||
기존처럼 `locations[0]`만 읽으면 최강 후보를 그대로 얻습니다.
|
||||
|
||||
@@ -55,10 +110,13 @@ Streaming 계산이 중단되거나 실패하면 해당 분석창과 sequence를
|
||||
`onResult` callback의 예외는 `failedAnalyses`에 포함하지 않습니다. 계산 중 capture overflow가 나면
|
||||
ring의 오래된 sample은 평소와 같이 drop telemetry에 기록됩니다.
|
||||
|
||||
한 블록 결과의 `processingTimeMs`는 DAS와 local-peak 검출에 걸린 실제 시간을 기록합니다. Streaming
|
||||
한 블록 결과의 `processingTimeMs`는 선택한 위치 추정 알고리즘과 local-peak 검출에 걸린 실제 시간을
|
||||
기록합니다. Streaming
|
||||
결과는 `deadlineMs = analysisHopSamples / sampleRate × 1000`과 `deadlineMet`을 더하며,
|
||||
`getState()`는 최근/최대 처리 시간과 `deadlineMisses` 누계를 제공합니다. `deadlineMisses` 또는
|
||||
`droppedSamples`가 증가하면 grid·대역 bin·분석창·update rate를 장치 성능에 맞게 줄여야 합니다.
|
||||
이 deadline 비교는 실시간 성능 보장이 아니라 완료된 창의 측정값입니다. 목표 장치에서 warm-up을 거친
|
||||
지속 부하를 직접 측정하고, capture·adapter·출력을 포함한 end-to-end deadline은 별도로 검증해야 합니다.
|
||||
|
||||
깊은 응답 notch의 역필터가 sensor noise까지 폭증시키지 않도록 inverse response의 양의 boost는 기본
|
||||
24 dB로 제한합니다. Experiment의 `beamforming.maxCompensationDb` 또는 portable plan의 top-level
|
||||
@@ -71,16 +129,27 @@ cache가 나중에 `maximumPlanBytes`를 넘지 않습니다.
|
||||
buffer byte 수를 돌려주므로 capture adapter가 지연을 감시할 수 있습니다. 실제 장치의 clock,
|
||||
channel framing과 transport는 하드웨어별 adapter 책임이며 이 모듈은 그 다음 단계부터 시작합니다.
|
||||
|
||||
반복 CPU 분석 계획은 거리 행렬, bin calibration, Hann window, Float64 FFT workspace, 임시 bin map과
|
||||
예산 내의 Float64 steering matrix를 재사용합니다. 예를 들어 192채널·50×50·2 bins를 10회 분석하면
|
||||
반복 CPU 분석 계획은 공통 거리 행렬과 STFT workspace를 재사용합니다. DAS 계열은 bin calibration,
|
||||
Hann window, 임시 bin map과 예산 내의 Float64 steering matrix를, GCC-PHAT는 reference 선택과
|
||||
correlation workspace를 추가로 유지합니다. 같은 plan을 동시에 두 분석에 쓰지 말고 설정이나 알고리즘이
|
||||
바뀌면 새 plan을 만듭니다. 예를 들어 DAS로 192채널·50×50·2 bins를 10회 분석하면
|
||||
거리 계산은 4,800,000회에서 480,000회로, steering point/microphone pair는 9,600,000회에서
|
||||
960,000회로 줄어듭니다(sin/cos 호출 17,280,000회 회피). 이 경우 약 16.5 MiB를 유지합니다.
|
||||
|
||||
기본 64 MiB보다 전체 wide-band steering matrix가 크더라도 cache 전체를 끄지 않습니다. 선택 bin
|
||||
앞쪽부터 예산에 들어가는 만큼만 Float64로 유지하고 나머지는 고정 microphone workspace에서 계산합니다.
|
||||
`analysisCache`는 cached bin capacity, uncached 사용 횟수·pair 수, STFT transform·FFT butterfly·DAS
|
||||
complex MAC 수와 실제 workspace allocation/reuse 수를 제공합니다. 자동 테스트는 부분 cache와
|
||||
cache 없음 사이 raw/display Float32 map의 전 요소 bit-exact 일치를 고정합니다.
|
||||
`analysisCache`는 알고리즘별 실제 작업을 제공합니다. DAS 계열은 cached bin capacity,
|
||||
uncached steering pair, STFT transform·FFT butterfly·complex MAC을, GCC-PHAT는 STFT/IFFT,
|
||||
2-pass cross-spectrum operation, scan lookup과 correlation workspace reuse를 기록합니다.
|
||||
|
||||
`P`를 scan point 수, `M`을 mic 수, `T`를 STFT frame 수, `F`를 선택한 고유 bin 수,
|
||||
`B`를 band 수, `N`을 `fftSize`라 하면 DAS의 주 scan 연산은 대략
|
||||
`P × M × T × F` complex MAC입니다. GCC-PHAT는 forward STFT에 더해 reference pair `M-1`개마다
|
||||
band bin을 두 번 순회하는 cross spectrum, `(M-1) × B`회의 길이 `N` IFFT,
|
||||
`P × (M-1) × B`회의 fractional correlation lookup을 수행합니다. band별 bin 수를 `F_b`라 하면
|
||||
cross-spectrum 항목 수는 구현의 두 pass를 포함해 `2 × (M-1) × T × ΣF_b`입니다. 따라서 GCC가
|
||||
scan MAC을 줄여도 작은 grid에서는 forward STFT와 pair별 IFFT가 전체 시간을 지배할 수 있으므로
|
||||
두 알고리즘 모두 실제 목표 장치에서 측정해야 합니다.
|
||||
|
||||
## 이동 음원과 분석 시간창
|
||||
|
||||
@@ -94,25 +163,30 @@ seed 기반 noise index, audio asset 재생 위치와 ambient가 전체 timeline
|
||||
|
||||
## Beam spread 의미
|
||||
|
||||
Peak의 `beamSpread`는 half-power 연결 성분을 power 가중한 공간 covariance(`covarianceM2`, m²)와 그
|
||||
RMS 주축 ellipse로 요약한 빔 폭입니다. 가우시안 확률 모델, 위치 확률 또는 신뢰구간으로 보정된 값이
|
||||
아니며 `calibrated: false`를 유지합니다.
|
||||
Peak의 `beamSpread`는 raw map의 peak 주변 연결 성분을 가중한 공간 covariance(`covarianceM2`, m²)와
|
||||
그 RMS 주축 ellipse로 요약한 폭입니다. `power` map은 half-power/power-weighted,
|
||||
`score` map은 half-maximum/score-weighted 규칙을 사용합니다. 어느 쪽도 가우시안 확률 모델,
|
||||
위치 확률 또는 신뢰구간으로 보정된 값이 아니며 `calibrated: false`를 유지합니다.
|
||||
|
||||
FFT는 `X[k] = Σ x[n] exp(-j2πkn/N)` 규약을 사용합니다. 마이크 신호의 전파 phase
|
||||
`exp(-j2πfr/c)`를 정렬하기 위해 DAS steering은 `exp(+j2πfr/c)`를 곱합니다. 단일 tone의
|
||||
ground-truth 위치에서 peak가 생기는 회귀 테스트로 이 부호를 고정합니다.
|
||||
|
||||
마이크 `sensitivityDb`와 `phaseOffsetDeg`는 수신 channel에 편차로 적용하고, DAS에서는 알려진
|
||||
calibration 값의 역 gain/phase로 보정합니다. raw power map과 표시용 normalized map은 서로 다른
|
||||
buffer로 보존합니다. bin spectrum은 제한된 batch로 처리합니다. cooperative yield는 지원 환경에서
|
||||
마이크 `sensitivityDb`와 `phaseOffsetDeg`는 수신 channel에 편차로 적용합니다. Conventional DAS는
|
||||
알려진 calibration의 역 gain/phase를 모두 보정하고, DAS-PHAT와 GCC-PHAT는 amplitude gain을 무시한
|
||||
채 알려진 phase만 보정합니다. raw `power`/`score` map과 표시용 normalized map은 서로 다른 buffer로
|
||||
보존합니다. bin spectrum은 제한된 batch로 처리합니다. cooperative yield는 지원 환경에서
|
||||
`scheduler.yield()`, 그 외에는 `MessageChannel`을 사용하고 timer task에도 주기적으로 기회를 주므로
|
||||
진행 callback과 `AbortSignal` 취소를 유지하면서 연속 `setTimeout(0)` clamp를 피합니다. portable
|
||||
plan의 기본 batch는 point 256개·STFT transform 128개이며 `computeOptions`로 조정할 수 있습니다.
|
||||
plan의 기본 point batch는 DAS 계열 256개, GCC-PHAT 4,096개이고 STFT transform batch는
|
||||
128개입니다. GCC-PHAT의 두 cross-spectrum pass도 16,384 operation마다 양보합니다.
|
||||
`pointBatchSize`, `stftTransformBatchSize`, `crossSpectrumBatchSize`를
|
||||
`computeOptions`로 조정할 수 있습니다.
|
||||
|
||||
마이크별 `frequencyResponse`는 2~64개의 `{ frequencyHz, gainDb, phaseDeg? }` 점으로 정의합니다.
|
||||
`interpolateFrequencyResponse`는 dB와 wrapped phase를 구간 선형 보간하고 측정 범위 밖에서는 가장
|
||||
가까운 끝점을 사용합니다. 합성 시 기존 sensitivity/phase 편차에 이 응답을 추가하며, CPU DAS는
|
||||
선택 FFT bin의 역응답을 calibration/steering cache에 포함합니다. WebGPU 경로는 GPU 전송 직전의
|
||||
가까운 끝점을 사용합니다. 합성 시 기존 sensitivity/phase 편차에 이 응답을 추가하며, CPU 위치 추정은
|
||||
선택 FFT bin의 알고리즘별 역응답을 calibration에 포함합니다. WebGPU DAS 계열 경로는 GPU 전송 직전의
|
||||
packed STFT에 같은 역응답을 적용합니다. `beamforming.compensateFrequencyResponse: false`는
|
||||
sensitivity/phase 보정은 유지한 채 곡선 보정만 꺼 robustness 비교를 재현합니다.
|
||||
|
||||
@@ -143,6 +217,9 @@ Scene의 `acoustics`를 생략하거나 `{ "model": "free-field" }`로 두면
|
||||
snapshot 합성은 전체 signal과 가장 늦은 sparse path를 포함하는 delay FFT working set을
|
||||
512 MiB로 제한합니다. 실측·장시간 입력은 위 streaming localizer의 bounded ring buffer로
|
||||
전체 녹음을 메모리에 보관하지 않고 처리할 수 있습니다. CPU analysis plan도 기본 512 MiB
|
||||
hard cap을 할당 전에 검사하며 steering cache는 별도의 64 MiB 안에서 가능한 bin만 유지합니다.
|
||||
hard cap을 할당 전에 검사합니다. DAS steering cache는 별도의 64 MiB 안에서 가능한 bin만 유지하고,
|
||||
GCC-PHAT는 거리·STFT·correlation workspace 전체를 plan 한도 안에서 검사합니다. Plan 없는 단발
|
||||
GCC 분석도 거리 행렬을 만들기 전에 spectrum·calibration·output을 포함한 working set을 preflight합니다.
|
||||
|
||||
192채널·50×50 fixture는 브라우저 통합 테스트에서 실제 합성부터 DAS peak 검출까지 실행합니다.
|
||||
192채널·50×50 fixture는 기존 DAS 호환 경로를 실제 합성부터 peak 검출까지 고정하며, 별도의 결정적
|
||||
회귀 fixture가 DAS-PHAT와 GCC-PHAT의 score scale·lag 부호·plan 재사용을 검사합니다.
|
||||
|
||||
Reference in New Issue
Block a user