# micarrsim
192채널 MEMS 마이크 배열의 배치와 자유음장·저비용 실내 근사에서 DAS·DAS-PHAT·GCC-PHAT·MUSIC
위치 추정을 비교하고, 표준 CFAR와 spectral flux로 ADC 대역의 원시 활동 후보를 확인하는 로컬 브라우저
시뮬레이터입니다. Array Builder에서 마이크 배치를 설계하고, Dataset Builder에서 녹음 파일·합성
신호와 이동 경로를 포함한 재현 가능한 음향 장면을 만든 뒤, Acoustic Camera에서 CPU 또는
WebGPU로 배열 응답, acoustic map과 위치 검출 지표를 계산하거나 이동 장면을 시간축으로 재생합니다.
별도 프로그램이나 패키지를 설치하지 않습니다. 모든 앱과 계산은 이 저장소와 브라우저 안에서
실행됩니다.
## 실행 환경
- Windows 10/11
- 최신 Microsoft Edge 또는 Google Chrome
- 저장소에 포함된 Windows PowerShell과 브라우저 외 추가 런타임 불필요
- WebGPU가 없거나 장치를 열 수 없어도 CPU backend로 실행 가능
## 가장 간단하게 시작하기
1. 저장소 최상위의 `start.cmd`를 더블클릭합니다.
2. 기본 브라우저에서 micarrsim 시작 화면이 열립니다.
3. 사용을 마치면 함께 열린 콘솔에서 `Ctrl+C`를 눌러 로컬 서버를 종료합니다.
브라우저가 자동으로 열리지 않으면 을 직접 여세요. HTML module과
Worker를 사용하므로 `index.html` 파일을 탐색기에서 직접 열어서는 안 됩니다.
다른 포트를 쓰거나 브라우저를 자동으로 열지 않으려면 명령 프롬프트에서 실행합니다.
```bat
start.cmd -Port 4174 -NoBrowser
```
PowerShell에서 서버를 직접 실행할 수도 있습니다.
```powershell
powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -File .\scripts\serve.ps1 -Port 4174 -NoBrowser
```
이 명령의 `ExecutionPolicy Bypass`는 실행 중인 PowerShell 프로세스에만 적용되며 시스템 정책을
영구 변경하지 않습니다. 해당 명령을 사용했다면 을 여세요.
실행 후 브라우저용 빠른 시작과 문제 해결은 에서도 볼 수 있습니다.
### 30초 기본 예제
1. 시작 화면에서 **Acoustic Camera**를 엽니다.
2. 기본 192채널 rectangular 배열, single-tone scene과 50×50 experiment가 준비될 때까지
기다립니다.
3. 처음에는 **DAS · 기준 power**를 두고 Snapshot 카드의 **▶ Snapshot 실행**을 누릅니다.
4. 계산이 끝나면 overlay와 평가 지표를 확인하고 **Result JSON**을 누릅니다.
같은 입력에서 **위치 추정 알고리즘**만 DAS-PHAT으로 바꿔 다시 실행하면 아래 비교 기록에 두 결과가
나란히 남습니다. GCC-PHAT은 광대역 입력에서 비교하세요.
MUSIC을 바로 확인하려면 현재 장면 제목 옆 **MUSIC 빠른 예제**를 누른 뒤
**▶ Snapshot 실행**만 누르면 됩니다. 12채널·1.125 kHz 단일-bin·Fixed K=1 설정이 함께 열립니다.
실제 완료 시간은 브라우저와 장치에 따라 다릅니다. CPU fallback에서는 WebGPU보다 오래 걸릴 수
있습니다.
### 분석 주파수를 모를 때
1. Acoustic Camera의 분석 대역 아래에서 **전 대역 활동 검사**를 펼칩니다.
2. 물리 마이크 한 채널과 **OS-CFAR**, **CA-CFAR** 또는
**Dixon spectral flux**를 고릅니다.
3. **전 대역 검사**를 누르고 frame slider에서 원시 ADC-bin 통계 또는 onset novelty를 봅니다.
4. CFAR candidate의 **아날로그 center 가설**을 직접 입력합니다. 기본값은 관측 ADC
center일 뿐 원 주파수 정답이 아닙니다.
5. **이 가설을 대역으로 추가**한 뒤 위치 추정 알고리즘을 골라 Snapshot을 실행합니다.
6. 감사 가능한 모든 frame/bin 값은 **Activity JSON**으로 저장합니다.
예를 들어 48 kHz ADC의 1,125 Hz 관측에는 1,125 Hz뿐 아니라 46,875 Hz,
49,125 Hz 같은 서로 다른 아날로그 가설이 대응합니다. Nyquist 초과 값도 막지 않지만,
Camera가 Scene truth로 alias order를 고르지는 않습니다. 각 가설을 별도 band로 넣어 배열의
spatial alias·grating lobe·실패 양상을 그대로 비교하세요.
CFAR의 Pfa는 IID exponential 배경 모델의 **tested CUT 하나당 명목값**이며 위치 확률이나
실측 confidence가 아닙니다. Spectral flux는 지속 신호 검출이 아니라 onset novelty입니다.
세 검출 경로와 위치 map을 자동 합의·평균·maximum fusion하지 않습니다. 수식, 미검사 edge와
causal latency는 [전 대역 활동 검출 모델](docs/activity-detection.md)에 설명되어 있습니다.
### 화면 폭 조절
데스크톱에서는 Array Builder와 Acoustic Camera의 왼쪽 설정 패널, Dataset Builder의 오른쪽 설정
패널 경계를 드래그해 넓힐 수 있습니다. 경계선에 키보드 초점을 두면 `←`/`→`로 16px씩,
`Shift`와 함께 누르면 64px씩 조절됩니다. `Home`/`End`는 최소·최대
폭, `Enter` 또는 더블클릭은 기본 폭으로 되돌립니다.
조절한 폭은 앱별로 현재 브라우저에 저장됩니다. 화면이 좁아지면 저장된 값과 관계없이 패널과 작업
영역이 자동으로 위아래로 쌓이고, 다시 데스크톱 폭으로 돌아오면 저장된 폭이 복원됩니다.
### 이동 음원 바로 보기
1. Acoustic Camera에서 **이동 예제 전체 열기**를 누릅니다.
2. Moving 카드의 **Map 준비**를 눌러 2 Hz acoustic map을 계산합니다.
3. **재생**을 누르거나 시간 slider를 움직여 음원과 heatmap의 이동을 확인합니다.
이 기능은 trajectory가 있는 합성 Scene의 준정적 시간창 재생입니다. 실제 192채널 마이크 장치에서
들어오는 스트림을 캡처하는 기능은 아닙니다.
이 버튼은 Scene뿐 아니라 Array와 Experiment, 분석 대역까지 예제 전체로 교체합니다. 여러 대역이나
저장하지 않은 설정이 있으면 교체 전에 확인합니다.
## 내 장면으로 전체 흐름 실행하기
### 1. Array Builder에서 마이크 배열 만들기 (선택)
1. 시작 화면에서 **Array Builder**를 엽니다.
2. aperture 너비·높이와 프리셋을 배치할 **생성 경계**(사각형 또는 타원)를 정합니다.
3. **격자**, **선형**, **원형**, **Fermat 나선**, **균일 랜덤** 중 하나로 배치합니다. 랜덤은
seed로 같은 좌표를 재현하며, 최소 간격과 경계 여백도 지정할 수 있습니다.
4. **추가** 도구로 canvas에 마이크를 놓고, 선택한 점을 드래그하거나 x/y/z 입력으로 수정합니다.
목록에서는 삭제와 채널 순서 변경도 할 수 있습니다.
5. canvas 아래 **수신 빔 패턴**에서 아날로그 주파수·360° 절단면·조향각을 바꿔 polar 응답과
조건부 −3.0103 dB 폭, sampled peak 동률을 확인합니다.
6. 상태가 **Array JSON 저장 가능**이면 **Array JSON 저장**을 누릅니다.
불러온 Array의 `sensitivityDb`, `phaseOffsetDeg`, `frequencyResponse` 보정 정보는 마이크 위치·ID나
채널 순서를 편집해도 보존됩니다. 프리셋 생성은 마이크 목록 전체를 새로 만드는 작업이므로 기존
채널별 보정값도 교체됩니다.
생성 경계 형상, 프리셋 종류, random seed와 최소 간격은 편집을 돕는 설정이며 표준 Array JSON에
저장되지 않습니다. 저장되는 것은 aperture 너비·높이와 최종 마이크 좌표·순서 및 채널별 보정값입니다.
빔 패턴 주파수·절단면·조향각도 preview 설정이므로 Array JSON과 undo/dirty 상태에 들어가지 않습니다.
자세한 사용법은 [`apps/array-builder/README.md`](apps/array-builder/README.md)를 참고하세요.
### 2. Dataset Builder에서 Scene 만들기
1. 시작 화면에서 **Dataset Builder**를 엽니다.
2. 선택적으로 배경 이미지와 오디오를 추가합니다.
3. 녹음 파일은 **+ 오디오 파일 음원** 한 번으로 asset과 source를 함께 만들 수 있습니다. 합성
음원은 별도 버튼으로 추가합니다.
4. canvas 또는 x/y/z 입력으로 위치를 정하고 tone·noise·audio asset과 ambient를 설정합니다.
5. 움직이는 음원은 **시간에 따라 음원 이동**을 켜고 keyframe과 경로 미리보기 시간을 편집합니다.
6. 상태가 **저장 가능한 장면**이면 **Scene JSON 저장**을 누릅니다.
**Preview WAV 저장**은 source와 ambient를 공간 정보 없이 하나의 mono channel로 합친 청취
확인용 파일입니다. 192채널 마이크 신호나 beamforming 결과가 아닙니다.
### 3. Acoustic Camera에서 실행하기
1. 홈으로 돌아가 **Acoustic Camera**를 엽니다.
2. 권장 순서인 **Scene → Array → Experiment → Assets**로 입력합니다. Experiment는 어느
시점에 열어도 모든 분석 대역과 원래의 `sceneId`/`arrayId` provenance label을 유지하며,
실행에는 현재 열린 Scene·Array가 사용됩니다.
3. **Scene**에서 Builder가 저장한 `.scene.json`을 선택합니다.
4. 기본 배열을 사용하지 않을 때는 **Array**에서 Array Builder가 저장한 `.array.json`을 선택합니다.
5. 별도 실험 문서를 사용할 때만 **Experiment**에서 `.experiment.json`을 선택합니다.
6. Scene에 이미지나 audio asset이 있다면 **Assets**에서 Builder에 사용했던 원본 파일을 다시
선택합니다. 여러 파일을 한 번에 선택할 수 있습니다.
7. 입력 검증이 통과하면 위치 추정 알고리즘, backend와 scan grid를 정하고 실행합니다.
8. 완료 후 **Result JSON**을 저장합니다.
Experiment를 불러오면 Camera가 먼저 문서 자체의 계약을 검사하고 가져온 `sceneId`,
`arrayId`, `frequencyBands`와 나머지 분석 설정을 그대로 보존합니다. 두 ID가 현재 입력과
달라도 거부하지 않으며, Result의 ID와 hash에는 실제 실행에 사용한 Scene·Array를 기록합니다. Nyquist 위 tone과
band는 오류가 아니라 ideal ADC alias 실험으로 허용되며, 원 주파수와 실제 ADC FFT range가 UI와
Result에 함께 기록됩니다. 잘못된 범위·scan·asset 같은 실제 오류는 그대로 거부됩니다. Scene을
다시 불러오면 이전 asset 연결은 해제됩니다.
Camera 안의 **Builder 새 탭** 링크는 편집 중인 Experiment와 분석 대역을 원래 Camera 탭에
유지합니다. Builder에서 JSON을 저장한 뒤 새 Camera를 다시 열지 말고 원래 Camera 탭으로 돌아와
Scene 또는 Array를 선택하세요. 같은 Camera 페이지에서 Scene을 교체하면 scan 영역과
plane을 새 Scene에 맞추되 Experiment의 provenance ID와 기존 `frequencyBands`는 보존합니다.
Camera에서 수정한 Scene·Experiment, 완료 Result와 전체 배열 비교 기록은 각각 JSON으로 저장할 수
있습니다. 저장하지 않은 항목이나 실행 중 계산이 있으면 페이지를 닫을 때 브라우저가 확인합니다.
## Scene JSON과 로컬 assets
Scene JSON에는 원본 이미지나 오디오 byte가 들어가지 않습니다. 대신 asset id, 종류, 파일명과
SHA-256 manifest를 저장합니다. 브라우저는 새 페이지나 세션에서 로컬 파일 접근 권한을 유지할 수
없으므로 원본 파일을 다시 선택해야 합니다.
- Camera는 SHA-256으로 선택한 파일을 manifest에 다시 연결합니다.
- 같은 이름이라도 내용이 달라 hash가 일치하지 않으면 거절합니다.
- 로컬 asset 한 파일은 최대 128 MiB, 연결된 파일 합계는 최대 512 MiB입니다.
- 실제 decode되어 메모리에 유지되는 오디오 합계는 최대 192 MiB입니다.
- Scene JSON에는 원본 파일명이 기록될 수 있으므로 파일을 외부에 공유하기 전에 확인하세요.
## 알고리즘, Backend와 계산량
| 알고리즘 | 원시 map | backend | 용도와 주의점 |
| --- | --- | --- | --- |
| DAS | 상대 acoustic power | CPU, WebGPU | 가장 단순한 기준선. 채널 gain과 알려진 마이크 응답을 보정합니다. |
| DAS-PHAT | 무차원 score | CPU, WebGPU | 마이크별 진폭을 버리고 위상 정합을 비교해 gain·반사에 더 강건할 수 있습니다. |
| GCC-PHAT | 무차원 score | CPU | 한 reference와 나머지 마이크의 TDOA 상관을 사용합니다. 광대역이 필요하며 협대역에서는 주기적 모호성이 큽니다. |
| MUSIC | noise-subspace projection `q` | CPU | [Schmidt narrowband MUSIC](https://doi.org/10.1109/TAP.1986.1143830)의 근거리 구면파 구현입니다. band마다 아날로그 FFT-grid carrier 가설 하나와 source 수를 지정해야 합니다. |
- **Auto (GPU→CPU)**: 권장값입니다. WebGPU adapter나 device를 사용할 수 없거나 지원되는 장치
한계를 넘으면 CPU로 계속합니다.
- **WebGPU 강제**: GPU 경로만 사용합니다. 장치를 열 수 없거나 한계를 넘으면 fallback하지 않고
오류를 표시합니다.
- **CPU 강제**: 비교와 호환성 확인을 위해 선택한 알고리즘의 CPU 구현을 사용합니다.
GCC-PHAT과 MUSIC은 현재 CPU 전용이므로 선택하면 Auto 또는 CPU만 사용할 수 있습니다. Camera는 각 band가
8개 미만의 FFT bin을 포함하면 협대역 경고를 표시합니다.
MUSIC의 원시 값은
`q(r)=Σ|E_nᴴa(r)|²/(a(r)ᴴa(r))`이며 작은 값이 더 좋은 위치 가설입니다. Camera가 표시·peak
검출에 쓰는 `P/Pmax`는 `P=1/q`를 scan 안에서 다시 0–1로 나타낸 값일 뿐, `q`와 `P/Pmax`
모두 위치 확률·posterior·confidence 또는 신뢰구간이 아닙니다. `q=0`인 이상적 pole, 동일
최솟값 tie와 완전히 평평한 map은 큰 유한값으로 조작하지 않고 별도로 처리합니다.
`musicSourceCountMethod`은 사용자가 지정한 `fixed` K 또는
[Wax–Kailath AIC/MDL](https://doi.org/10.1109/TASSP.1985.1164557)입니다. AIC/MDL은
비중첩 frame, `T>M`, 양의 noise eigenvalue 외에도 IID complex Gaussian snapshot,
spatially white noise와 창 동안 일정한 source 수를 **가정**합니다. 비중첩은 통계적 독립성의
증명이 아니며 criterion score 역시 확률이나 confidence가 아닙니다.
WebGPU 경로도 신호 합성과 STFT 일부는 CPU에서 수행합니다. grid의 point 수는 50×50을 1로 보면
100×100은 4배, 200×200은 16배입니다. 처음에는 50×50을 사용하고 해상도가 필요할 때만 높이세요.
실행 시간은 microphone 수, scene 길이, FFT, 대역 폭과 장치에 함께 좌우됩니다.
DAS 계열의 scan 주항은 `P × M × T × F`입니다. 192채널·50×50·46 frames·2 bins의 기존
fixture는 44,160,000 complex MAC입니다. GCC-PHAT은 같은 조건에서 forward STFT를 그대로
수행한 뒤 191 reference pairs에 대해 35,144회의 2-pass cross-spectrum 연산, 191회의 inverse
FFT와 477,500회의 point/pair lookup을 수행합니다. 따라서 큰 grid·광대역에서는 scan 비용을
줄이지만 작은 grid에서는 공통 STFT 때문에 전체 시간이 같은 비율로 줄지는 않습니다.
저장된 Intel Gen9 측정에서 DAS 50×50의 GPU wall은 79.2 ms였지만 CPU STFT는 1,669.8 ms,
signal 합성은 별도 1,200.5 ms였습니다. 즉 현재 기본 fixture의 병목은 단순히 grid scan 하나가
아닙니다. Camera의 workload 줄은 STFT, DAS MAC 또는 GCC cross-spectrum·inverse FFT·lookup,
signal path와 distance cache를 따로 표시합니다.
## 음향 환경과 마이크 응답
Camera의 **고급 설정**에서 자유음장, 흡음된 실내, 일반 실내와 반사 강한 실내를 선택할 수
있습니다. 실내 preset은 현재 Array·Scene·scan을 감싸는 shoebox room을 만들고 직접음에 다음의
희소 경로를 추가합니다.
- 여섯 면의 1차 image-source 반사와 결정적 scattering
- 축 정렬 occluder의 직접음 감쇠와 최단 corner 우회 회절
- RT60·gain·tap 수로 제한한 deterministic diffuse tail
각 마이크의 Array JSON에는 선택적 `frequencyResponse` 측정 curve를 넣을 수 있습니다.
합성기는 curve를 수신 채널에 적용하고, 기본 DAS는 알려진 curve를 역보정합니다. **마이크 주파수
응답 처리**를 보정하지 않음으로 바꾸면 같은 curve를 합성에만 적용해 robustness를 비교합니다.
응답 notch의 양의 역보정 boost는 기본 24 dB로 제한합니다.
필드, preset별 경로 예산과 물리적 한계는
[음향 환경과 마이크 응답 모델](docs/acoustic-model.md)에 정리되어 있습니다.
## 위치 추정, 빔 분포와 복수 음원
DAS 출력은 각 scan point의 상대 acoustic power, PHAT 계열 출력은 무차원 score이며 어느 쪽도
위치 확률분포가 아닙니다. Camera는 map의 local peak를 위치 후보로 표시합니다. **빔 분포**를 켜면
각 peak의 연결된 half-maximum lobe에 대해 map 값 가중 공분산을 계산해 1× RMS 점선과 2× RMS
영역을 그립니다. Gaussian의 등고선처럼 보일 수 있지만 통계적으로 보정된 Gaussian, 신뢰구간 또는
발생 확률은 아닙니다.
GCC-PHAT raw score는 pair 수·band coefficient 수·IFFT 크기로 정규화한 0–1 양의 상관 응답입니다.
scan 범위나 마이크 수 때문에 값이 단순히 커지는 현상은 막지만, 0.8을 “위치 확률 80%”로 읽을 수는
없고 다른 알고리즘의 score와 절대값을 비교해서도 안 됩니다.
복수 음원은 각각 별도 local peak가 남을 만큼 공간적으로 분리되고 선택 대역에 에너지가 있어야
검출됩니다. **Peak 검출 임계값 (%)**은 최강 peak 대비 후보의 최소 map 값입니다. 기본 25%에서 약한
두 번째 음원이 빠지면 10–20%로 낮출 수 있지만 sidelobe 오검출도 늘어납니다. 서로 같은 대역에서
main lobe보다 가깝거나 gain 차이가 큰 음원은 conventional DAS의 물리·알고리즘 한계 때문에
threshold만으로 분리되지 않을 수 있습니다.
MUSIC band는 FFT spacing에 맞는 사용자가 지정한 아날로그 carrier 가설을 정확히 하나만 포함해야
합니다. Nyquist 위 가설도 허용되며 signed ADC alias가 음수이면 positive-bin coefficient,
마이크 calibration과 전체 complex 근거리 manifold를 켤레 방향으로 사용합니다. 공간 위상의
크기는 접힌 ADC 주파수가 아니라 analog carrier `f_a`이고 alias 부호는 orientation만 정합니다. 이는 Scene의
실제 tone을 조회해 정답 alias order를 고르는 기능이 아닙니다. 가설은 Experiment band에서만
오고 Scene truth는 위치추정에 사용되지 않습니다. 같은 ADC bin의 다른 alias order는 별도 band로
직접 만들어 비교해야 하며 자동 선택·평균·maximum fusion은 없습니다. DC와 정확한 Nyquist bin은
실수 sampling에서 quadrature가 퇴화하므로 거부됩니다.
표준 narrowband MUSIC은 coherent한 같은-frequency source에서 covariance rank가 줄어드는 현상을
고치지 않습니다. 현재 구현에는 diagonal loading, spatial smoothing, 임의 wideband/multiband
fusion이 없고, [Wax–Shan–Kailath broadband eigenstructure 방법](https://doi.org/10.1109/TASSP.1984.1164400)도
구현하지 않았습니다. grating lobe와 동일 최솟값은 배열 설계 결과로 그대로 남고, signal/noise
subspace가 수치적으로 식별되지 않으면 `MUSIC_UNAVAILABLE`로 실패합니다.
## 이동 음원 라이브의 동작
Builder의 trajectory는 Scene 시작 기준 절대 시간의 keyframe 사이를 직선 보간합니다. Camera는
장면을 sample 경계에 맞춘 짧은 시간창으로 나누고, 각 창 중앙의 음원 위치에서 tone 위상, noise
index와 audio asset 재생 위치가 이어지도록 신호를 합성합니다. 계산된 map 사이에서는 heatmap을
보간하고 ground-truth 위치는 연속 보간합니다.
- Map rate: 초당 분석 map 목표 수. 높을수록 움직임이 세밀하지만 준비 시간이 늘 수 있습니다.
- 라이브 미리보기 상한: 48 maps, map당 최대 2,500 scan points
- 모델: 준정적 위치 변화이며 Doppler와 창 내부의 연속 전파 경로 변화는 포함하지 않음
- 실제 장치: 물리 192채널 capture/stream gateway는 하드웨어 형식이 정해진 뒤 별도 adapter가 필요
Scene 합성 없이 동기식 `Float32Array` 마이크 채널을 바로 처리하는
`createLocalizationPlan`, `localizeMultichannel`과 `StreamingLocalizer`가
`packages/acoustics-core`에 분리되어 있습니다. 고정 ring buffer, oldest-first drop,
반복 geometry·workspace cache와 `AbortSignal` 취소를 제공하며 실제 capture 장치에는
channel/clock/transport adapter만 별도로 연결합니다. 실시간 여부는 각 결과의
`processingTimeMs <= deadlineMs`와 누적 `deadlineMisses`·`droppedSamples`로
해당 장치에서 확인합니다. 복사할 파일과 운용 계약은
[실측 다채널 위치추정 코어 포팅](docs/realtime-porting.md)을 참고하세요.
## Result JSON
Result JSON은 계약 버전 `1.1.0`의 `micarrsim.result` 문서입니다. Array·Scene·Experiment는
`1.0.0`을 유지합니다. 주요 내용은 다음과 같습니다.
- 실행한 `experimentId`, `arrayId`, `sceneId`, 실제 `algorithm`·`backend`와 생성 시각. 이 ID들은
provenance label이며 물리 호환성 판정값이 아닙니다. Camera는 가져온 Experiment를 현재
Scene·Array에 연결한 뒤 Result에 실제 실행 ID와 hash를 기록합니다.
- Array·Scene·Experiment의 canonical SHA-256인 `inputHash`
- 정규화 전 peak, 적용 scale, clipping 수와 음향 모델·희소 경로 수를 담은 `signalStats`
- 원 tone→signed ADC alias, DC/Nyquist 퇴화와 anti-alias filter 부재를 담은 필수 sampling provenance
- 전체·신호 생성·위치 추정 시간인 `timingMs.localization`과 기존 reader용 `beamforming` alias
- 주파수 대역별 power 또는 score `rawMap`, 표시용 `displayMap`, 검출 `peaks`
- band별 Nyquist zone fold, FFT bin-center 선택, 실제 localization model과 동일 ADC band 목록
- 위치 오차, precision/recall, truth 반경 내 energy, peak-to-sidelobe, main-lobe 폭을 계산하기
위한 평가 파라미터와 `metrics`
- peak별 half-power 공분산과 RMS ellipse를 담은 `beamSpread` (`calibrated: false`)
평가에서 tone source는 요청 analog interval 또는 접힌 주파수의 nearest ADC bin을 기준으로
사용합니다. Audio asset과 noise
source는 임의 spectrum threshold를 만들지 않고 모든 band의 ground truth로 취급합니다. 정확한
정책은 Result `evaluation.truthSelection`에 기록됩니다.
## 개인정보와 모델의 한계
서버는 `127.0.0.1` loopback에만 열리고 외부 서비스로 파일을 업로드하거나 telemetry를 보내지
않습니다. 선택한 파일은 브라우저 메모리에서 읽으며 생성한 JSON/WAV는 브라우저 다운로드로만
저장됩니다.
음향 모델은 직접 경로의 자유음장과 1차 반사·scattering·occluder 회절·RT60 tail을 제한된
경로로 계산하는 shoebox 근사를 제공합니다. 파동 방정식, 고차 반사, 재질별 주파수 의존 흡음,
복잡한 mesh 회절, 바람, Doppler, 마이크 self-noise·비선형, ADC quantization·nonlinearity와
channel clock jitter·drift는 모델링하지 않습니다. 위치 추정기는 DAS, DAS-PHAT, CPU GCC-PHAT와
CPU narrowband MUSIC을 제공하지만 full-pair SRP-PHAT, wideband MUSIC, DAMAS와 CLEAN-SC는
구현하지 않습니다.
따라서 결과는 배열·grid·대역의 상대 비교와 소프트웨어 검증용이며, 현장 성능 인증이나 안전
판단을 대신하지 않습니다.
## 배열 예제
- **채널 수 비교:** 같은 0.45 m aperture에서 4·12·48·192·384채널 rectangular 배열
- **물리 크기 비교:** 같은 192채널 16×12 topology에서 0.12·0.45·1.20 m 배열
- **배치 비교:** 같은 192채널 규모의 rectangular baseline과 0.45 m Fermat spiral
Camera의 **배열 선택**에서 8개 fixture를 바로 불러와 같은 Scene/Experiment로 연속 실행할 수 있습니다.
저채널·대형 배열의 grating lobe나 compact 배열의 넓은 main lobe는 배치 trade-off를 관찰하기 위한
의도된 예제 특성입니다.
새 배치를 직접 만들려면 [Array Builder](apps/array-builder/README.md)를 사용하세요. 저장소 fixture의
상세한 생성법은 [`assets/array-geometries/README.md`](assets/array-geometries/README.md)를 참고하세요.
Array Builder는 현재 배치의 geometry-only conventional receive array factor를 XZ·YZ·XY 360°
polar 단면으로 즉시 표시합니다. 이 계산은 ADC sample rate 없이 원 아날로그 파장을 사용하므로
Nyquist 초과 조건도 실행하며, 각도 해상도가 부족하면 raw 선을 남긴 채 HPBW·peak 해석을 보류합니다.
## 테스트와 benchmark
최상위 폴더에서 자동 서버·headless 브라우저·정리까지 한 번에 실행하려면 다음을 사용합니다.
```bat
test.cmd
```
서버를 실행한 뒤 다음 주소를 브라우저에서 엽니다.
- 전체 browser test runner:
- WebGPU scaling benchmark:
포트를 바꿨다면 URL의 포트도 같은 값으로 바꾸세요. 테스트 범위는
[`tests/unit/README.md`](tests/unit/README.md)와
[`tests/integration/README.md`](tests/integration/README.md), 기준 실측은
[`docs/benchmarks/README.md`](docs/benchmarks/README.md)에 설명되어 있습니다.
## 저장 형식과 개발 문서
- [전 대역 활동 검출 모델](docs/activity-detection.md): CA/OS-CFAR, spectral flux와 alias 가설 흐름
- [수신 빔 패턴 모델](docs/beam-pattern.md): array factor 수식, polar 단면, HPBW와 해상도 기준
- [`docs/data-contracts.md`](docs/data-contracts.md): Array·Scene·Experiment·Result 계약
- [`docs/acoustic-model.md`](docs/acoustic-model.md): 마이크 응답과 자유음장·shoebox 희소 근사
- [`docs/realtime-porting.md`](docs/realtime-porting.md): 실측 다채널 위치추정 API 포팅
- [`apps/array-builder/README.md`](apps/array-builder/README.md): 배열 생성·직접 편집과 Camera 전달
- [`schemas/README.md`](schemas/README.md): JSON Schema 구성
- [`docs/execution-plan.md`](docs/execution-plan.md): 구현 단계와 기술 결정
- [`goal.md`](goal.md): 프로젝트 목표
원본 DCASE/MIMII 데이터, 사용자가 선택한 assets와 생성된 대용량 결과는 저장소에 커밋하지
않습니다.
## 디렉터리 구조
```text
apps/ Array Builder, Dataset Builder와 Acoustic Camera UI
assets/ 마이크 배열과 synthetic Scene/Experiment fixture
benchmarks/ 현재 브라우저에서 실행하는 WebGPU scaling 측정
docs/ 사용자 안내, 데이터 계약, 실행 계획과 기준 실측
packages/ 음향 수치 모델, 계약 검증, UI, WebGPU kernel
schemas/ Array·Scene·Experiment·Result JSON Schema
scripts/ 무설치 로컬 서버와 fixture 생성기
tests/ 브라우저 unit·integration·end-to-end test
start.cmd Windows 원클릭 실행 진입점
```