# 음향 환경과 마이크 응답 모델 micarrsim의 음향 합성은 마이크 어레이 배치와 위치추정 알고리즘의 상대 성능을 빠르게 비교하기 위한 모델이다. ADC나 마이크 전자회로까지 재현하는 하드웨어 시뮬레이터가 아니며, 자유음장과 계산량이 제한된 실내 희소 경로 근사 중 하나를 선택한다. ## 신호 처리 범위 Snapshot 한 번의 처리 순서는 다음과 같다. 1. tone, noise 또는 audio asset으로 음원 신호를 만든다. 2. 음원과 각 마이크 사이의 직접음 또는 희소 multipath 전달함수를 만든다. 3. 마이크별 `sensitivityDb`, `phaseOffsetDeg`와 `frequencyResponse`를 수신 신호에 적용한다. 4. 합성된 동기식 다채널 신호를 STFT하고 `beamforming.algorithm`으로 선택한 위치 추정 알고리즘의 scan map을 계산한다. 5. 알고리즘에 맞게 알려진 마이크 응답을 보정하고 map의 peak와 평가 지표를 구한다. Scene의 `acoustics`를 생략하거나 `model: "free-field"`로 지정하면 기존 직접음 결과를 유지한다. `model: "shoebox"`는 직육면체 방 안에서 경로 수가 제한된 근사를 추가한다. ## 자유음장 음원과 마이크 사이 거리 `r`, 음속 `c`에 대해 직접음의 지연은 `r / c`, 진폭은 최소 거리 clamp를 적용한 `1 / r`이다. 분수 sample 지연은 zero-padded FFT의 주파수 영역 위상 이동으로 계산한다. 이 모델은 반사가 거의 없는 조건의 기준선과 배열 자체의 aperture·형상·대역 효과를 비교할 때 적합하다. ## Shoebox 희소 경로 근사 `shoebox` 모델은 source–microphone 쌍마다 다음 경로만 만든다. - 직접음 1개. 축 정렬 occluder와 교차하면 `transmissionDb`만큼 감쇠한다. - 방의 여섯 면마다 최대 1개의 1차 image-source 반사. - 반사 에너지의 일부를 0.2–2 ms의 결정적 지연으로 나누는 scattering 경로. - 직접음을 막는 occluder마다 여덟 corner 중 최단 우회 거리로 만든 회절 경로 1개. - `tapCount`로 수를 제한하고 RT60에 걸쳐 -60 dB로 감쇠하는 결정적 diffuse tail. 같은 Scene seed와 source/microphone id에서는 scattering과 tail이 재현된다. 모든 희소 경로는 source–microphone 쌍의 주파수 전달함수 하나로 먼저 합쳐지고 IFFT는 한 번만 수행된다. 경로 위상은 recurrence로 갱신하고 1,024 bin마다 다시 고정해 bin마다 삼각함수를 반복하지 않는다. Scene JSON의 사용자 설정 예는 다음과 같다. ```json { "acoustics": { "model": "shoebox", "room": { "min": [-3.0, -2.5, -0.5], "max": [3.0, 2.5, 4.0] }, "reflections": { "order": 1, "wallGainDb": -8, "perWallDb": { "zMin": -14 }, "scattering": 0.25 }, "diffuseReverb": { "enabled": true, "rt60Seconds": 0.4, "gainDb": -20, "tapCount": 6 }, "occluders": [ { "id": "screen", "min": [-0.4, -0.1, 0.6], "max": [0.4, 0.1, 1.8], "transmissionDb": -18, "diffractionGainDb": -12 } ] } } ``` `room`은 shoebox에서 필수다. 정적 source, trajectory keyframe과 occluder는 room 안에 있어야 하며 occluder id는 중복될 수 없다. 사용자 설정에서도 마이크 좌표가 room 안에 놓이도록 구성해야 1차 반사가 생성된다. ## Camera 환경 preset과 비용 Camera의 **고급 설정 → 음향 환경**은 현재 geometry 전체가 들어가도록 room을 자동 추론하고 다음 preset을 적용한다. | 선택 | 벽 gain | scattering | RT60 / tail gain / taps | 수신점당 최대 경로 | | --- | ---: | ---: | ---: | ---: | | 자유음장 | — | — | — | 1 | | 흡음된 실내 | -14 dB | 0.15 | 0.2 s / -26 dB / 4 | 17 | | 일반 실내 | -8 dB | 0.25 | 0.4 s / -20 dB / 6 | 19 | | 반사 강한 실내 | -4 dB | 0.40 | 0.8 s / -14 dB / 10 | 23 | 표의 상한은 직접음 1개, 반사 6개, scattering 6개와 tail tap 수를 합한 값이다. 사용자 occluder는 각 source–microphone 직접 경로를 실제로 막을 때 하나씩 추가된다. 대략적인 합성 경로 예산은 `음원 수 × 마이크 수 × 수신점당 최대 경로`다. Camera는 실행 전에 이 예산을 표시한다. 반사·tail을 늘리면 신호 합성의 전달함수 누산도 늘어난다. DAS 계열의 scan 누산은 대략 `O(scan points × microphones × selected bins × STFT frames)`이고, GCC-PHAT는 pair별 상호 상관을 만든 뒤 `O(scan points × (microphones - 1) × bands)` lookup을 수행한다. 어느 방식이든 STFT와 거리 cache 비용은 별도로 필요하다. 처음에는 50×50 grid와 자유음장으로 기준선을 만들고, 같은 입력에서 환경과 알고리즘을 하나씩 바꾸어 비교하는 것이 좋다. ## 위치 추정 알고리즘 마이크 `m`, STFT frame `t`, 주파수 `f`의 복소 spectrum을 `X_m(t, f)`, scan point `p`와 마이크 사이 거리를 `r_m(p)`, 파수를 `k = 2πf/c`라고 하자. `φ_m(f)`는 알려진 마이크의 정적 phase offset과, 주파수 응답 보정을 켠 경우 response phase를 합한 값이다. 모든 map은 scan point 마다 하나의 비음수 상대값을 만들지만, 그 값은 위치의 확률이나 posterior가 아니다. ### DAS (`das`) Conventional frequency-domain delay-and-sum은 각 후보점에서 구면파 전파 위상을 되돌려 채널을 coherent sum한다. ```text B_DAS(p,t,f) = (1/M) Σ_m A_m⁻¹(f) X_m(t,f) exp(j[k r_m(p) - φ_m(f)]) P_DAS(p) = mean_(t,f) |B_DAS(p,t,f)|² ``` `A_m⁻¹(f)`에는 sensitivity의 역 gain과, 설정한 경우 frequency-response gain의 제한된 역보정이 들어간다. 구현은 frame별 제곱 크기를 먼저 평균하고 선택 band의 bin들을 다시 평균한다. 따라서 Result의 `rawMap.scale`은 `power`지만, 절대 SPL로 calibration한 power가 아니라 같은 입력·설정 안에서 비교하는 선형 상대 power다. CPU와 WebGPU를 지원한다. ### DAS-PHAT (`das-phat`) DAS-PHAT는 steering 전에 각 frame·bin·마이크 spectrum을 위상만 남기도록 정규화한다. ```text U_m(t,f) = X_m(t,f) / |X_m(t,f)| S_DAS-PHAT(p) = mean_(t,f) |(1/M) Σ_m U_m(t,f) exp(j[k r_m(p) - φ_m(f)])|² ``` 한 frame·bin에서 최강 마이크 크기의 기본 `10⁻⁶`배인 상대 floor 이하의 값은 `0`으로 두어 무음이나 극소값의 불안정한 위상을 제외한다. 입력과 calibration의 amplitude gain은 coherent sum에 사용하지 않고, 알려진 phase만 보정한다. 그 결과 source spectrum이나 채널 gain 차이에 덜 끌릴 수 있지만 유용한 amplitude 정보도 버리며, 약한 bin의 위상과 multipath에 민감할 수 있다. `rawMap.scale`은 무차원 `score`이고 CPU와 WebGPU를 지원한다. ### GCC-PHAT (`gcc-phat`) 현재 GCC-PHAT는 배열 중심에서 가장 먼 마이크 하나를 결정적인 reference로 고르고, reference와 나머지 `M - 1`개 마이크의 pair만 사용한다. 각 band와 pair에 대해 다음 PHAT cross spectrum을 STFT frame에 걸쳐 평균한다. ```text C_mr(t,f) = X_m(t,f) conj(X_r(t,f)) G_mr(f) = mean_t [C_mr(t,f) / max(|C_mr(t,f)|, floor)] × exp(j[φ_r(f) - φ_m(f)]) ``` 기본 `floor`는 해당 band·pair의 모든 선택 bin과 frame에서 얻은 최대 cross-spectrum 크기의 `10⁻⁶`배다. 이 floor는 amplitude를 score 가중치로 쓰기 위한 것이 아니라 극소 cross spectrum의 불안정한 위상 정규화를 제한한다. 선택 band 밖의 bin은 `0`으로 두고 켤레 대칭 spectrum을 IFFT하여 원형 상호상관 `R_mr,b(ℓ)`을 만든다. scan point마다 far-field 각도 근사가 아니라 정확한 거리 차이로 near-field 예측 lag를 계산한다. ```text ℓ_mr(p) = [r_m(p) - r_r(p)] sampleRate / c Q_b(p) = Σ_(m≠r) R_mr,b(ℓ_mr(p)) K_b = I(0 ∈ b) + I(N/2 ∈ b) + 2 × #(나머지 positive bins) S_b(p) = clamp[N Q_b(p) / ((M-1) K_b), 0, 1] ``` 분수 sample lag는 IFFT 원형 상호상관의 이웃 두 sample을 선형 보간한다. Hermitian coefficient 수 `K_b`, IFFT의 `1/N`, reference pair 수로 나눈 뒤 음의 상관은 0으로 두어 score를 0–1로 제한한다. 따라서 같은 위치 가설의 raw GCC score는 scan 범위나 마이크 수 자체에 의해 재척도화되지 않는다. 이 값도 확률이나 calibration된 confidence는 아니다. `rawMap.scale`은 `score`다. PHAT가 amplitude를 제거하므로 sensitivity와 frequency-response gain은 역보정하지 않고 알려진 phase만 보정한다. 현재 CPU만 지원하고 두 개 이상의 마이크가 필요하다. GCC-PHAT는 broadband 신호에서 상호상관 peak가 뚜렷할수록 유리하다. 단일 tone이나 지나치게 좁은 band는 주기적으로 같은 phase를 만드는 lag가 많아 여러 위치가 비슷한 score를 얻을 수 있고, 반사음이나 여러 동시 음원은 pair 상관 peak를 섞는다. IFFT 길이가 `N = fftSize`이면 표현 가능한 비중첩 원형 lag는 절대값 `N/2` sample까지다. 현재 구현은 scan 전체의 최대 기하학적 lag가 이를 넘으면 실행을 거절하므로 FFT를 키우거나 array aperture 또는 scan 범위를 줄여야 한다. 이 검사는 원형 lag alias를 막지만 좁은 대역의 주기적 모호성, 제한된 bandwidth, scan grid 양자화까지 해결하지는 않는다. 단일 reference 방식은 모든 마이크 쌍을 쓰는 GCC보다 계산량이 작지만 pair 중복성과 고장 마이크에 대한 강건성도 작다. ## 마이크 주파수 응답 각 마이크에는 2–64개의 측정점을 지정할 수 있다. `frequencyHz`는 0–1,000,000 Hz에서 중복 없이 오름차순이어야 하며 `gainDb` 범위는 -120–120 dB, 선택적 `phaseDeg` 범위는 -180–180°다. ```json { "id": "mic-001", "position": [-0.225, 0.225, 0], "sensitivityDb": 0.6, "phaseOffsetDeg": -1.5, "frequencyResponse": [ { "frequencyHz": 100, "gainDb": -8.0, "phaseDeg": -12 }, { "frequencyHz": 1000, "gainDb": -0.7, "phaseDeg": -2 }, { "frequencyHz": 8000, "gainDb": 2.1, "phaseDeg": 7 }, { "frequencyHz": 20000, "gainDb": -5.0, "phaseDeg": 20 } ] } ``` 측정점 사이 gain dB와 phase는 선형 보간한다. phase는 ±180° 경계에서 가장 짧은 방향으로 보간하고 측정 범위 밖에서는 가장 가까운 끝점 값을 유지한다. 합성기는 이 curve를 실제 마이크 채널에 적용한다. 합성기는 알고리즘과 무관하게 sensitivity, 정적 phase offset과 frequency-response curve를 수신 channel에 적용한다. 위치 추정에서의 역보정은 알고리즘별로 다르다. - DAS는 sensitivity 역 gain과 정적 phase를 항상 보정한다. `compensateFrequencyResponse`를 생략하거나 `true`로 두면 response의 역 gain과 phase도 보정한다. 응답 notch의 무제한 gain boost는 noise까지 키울 수 있으므로 `maxCompensationDb`로 제한하며 기본값은 24 dB, 허용 범위는 0–120 dB다. 응답 peak를 줄이는 attenuation과 phase 보상에는 이 boost 상한을 적용하지 않는다. - DAS-PHAT와 GCC-PHAT는 amplitude를 정규화하므로 sensitivity와 response gain의 역보정을 사용하지 않는다. 정적 phase는 항상 보정하고, `compensateFrequencyResponse`가 `true`이면 알려진 response phase도 보정한다. 따라서 `maxCompensationDb`는 두 PHAT 알고리즘의 score에는 영향을 주지 않는다. ```json { "beamforming": { "algorithm": "das", "backend": "auto", "minimumDistance": 0.01, "normalization": "peak", "dynamicRangeDb": 45, "compensateFrequencyResponse": true, "maxCompensationDb": 24 } } ``` Camera의 **마이크 주파수 응답 처리**에서 **측정 curve 적용 + 보정하지 않음**을 고르면 합성에는 curve가 남고 위치 추정의 response gain/phase 역보정만 꺼진다. DAS-PHAT와 GCC-PHAT는 여전히 amplitude를 버리지만, curve가 신호 대 잡음과 relative floor 통과 여부에 준 영향까지 되돌리지는 못한다. 같은 배열에서 알려진 response 보정 유무의 robustness를 비교할 때 사용한다. curve가 없는 마이크는 0 dB, 0°로 취급한다. ## 결과에서 확인할 값 Result `signalStats`에는 다음 선택 필드가 들어간다. - `acousticModel`: `free-field` 또는 `shoebox` - `acousticPathCount`: 실제 합성에 사용한 전체 경로 수 - `acousticPathCounts`: `direct`, `reflection`, `scattering`, `diffraction`, `diffuse` 종류별 수 같은 입력과 seed에서 환경 preset만 바꿨다면 이 값과 위치 오차·precision/recall·PSR을 함께 비교할 수 있다. Result 최상위 `algorithm`은 실제 실행한 `das`, `das-phat` 또는 `gcc-phat`를 기록한다. band의 `rawMap.scale`은 DAS에서 `power`, 두 PHAT 방식에서 `score`다. peak 정규화된 `displayMap`은 시각 비교용일 뿐 어느 scale도 확률분포나 신뢰구간으로 바꾸지 않는다. ## 정확도 범위와 제외 사항 이 구현은 FDTD/FEM/BEM이나 room impulse response 측정치를 대신하지 않는다. 다음 항목은 계산하지 않는다. - 파동 방정식과 고차 반사 - 재질별 주파수 의존 흡음과 복잡한 mesh 산란 - edge 형상·파장에 따른 물리 회절 - 음원과 마이크 지향성, 바람, Doppler - 절대 음압/SPL, 마이크 self-noise와 비선형 왜곡 - preamp, anti-alias filter, ADC quantization, channel clock jitter·drift - 실제 장착 구조와 마이크 위치 공차 따라서 preset의 RT60이나 wall gain은 특정 방을 인증하는 값이 아니라 배열과 위치 추정 알고리즘이 multipath에 얼마나 민감한지 비교하는 조건이다. 실제 장치 성능을 평가할 때는 같은 Array/scan/band 설정으로 동기식 실측 채널을 [실시간 위치추정 코어](realtime-porting.md)에 입력하고 합성 결과와 나란히 비교해야 한다. 주파수 응답 curve만으로 noise floor, distortion, ADC와 clock 오차까지 모사되지는 않는다.