diff --git a/README.md b/README.md index b24a7dc..9163edc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # micarrsim -192채널 MEMS 마이크 배열의 배치와 자유음장 DAS 음향 영상을 비교하는 로컬 브라우저 +192채널 MEMS 마이크 배열의 배치와 자유음장·저비용 실내 근사에서의 DAS 음향 영상을 비교하는 로컬 브라우저 시뮬레이터입니다. Dataset Builder에서 녹음 파일·합성 신호와 이동 경로를 포함한 재현 가능한 음향 장면을 만들고 Acoustic Camera에서 CPU 또는 WebGPU로 배열 응답, acoustic map과 위치 검출 지표를 계산하거나 이동 장면을 시간축으로 재생합니다. @@ -46,7 +46,7 @@ powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -File .\scripts\serve. 1. 시작 화면에서 **Acoustic Camera**를 엽니다. 2. 기본 192채널 rectangular 배열, single-tone scene과 50×50 experiment가 준비될 때까지 기다립니다. -3. **기본 예제 실행**을 누릅니다. +3. Snapshot 카드의 **▶ Snapshot 실행**을 누릅니다. 4. 계산이 끝나면 overlay와 평가 지표를 확인하고 **Result JSON**을 누릅니다. 실제 완료 시간은 브라우저와 장치에 따라 다릅니다. CPU fallback에서는 WebGPU보다 오래 걸릴 수 @@ -54,8 +54,8 @@ powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -File .\scripts\serve. ### 이동 음원 바로 보기 -1. Acoustic Camera에서 **이동 예제**를 누릅니다. -2. **라이브 준비**를 눌러 2 Hz acoustic map을 계산합니다. +1. Acoustic Camera에서 **이동 예제 열기**를 누릅니다. +2. Moving 카드의 **Map 준비**를 눌러 2 Hz acoustic map을 계산합니다. 3. **재생**을 누르거나 시간 slider를 움직여 음원과 heatmap의 이동을 확인합니다. 이 기능은 trajectory가 있는 합성 Scene의 준정적 시간창 재생입니다. 실제 192채널 마이크 장치에서 @@ -118,6 +118,23 @@ WebGPU 경로도 신호 합성과 STFT 일부는 CPU에서 수행합니다. grid 100×100은 4배, 200×200은 16배입니다. 처음에는 50×50을 사용하고 해상도가 필요할 때만 높이세요. 실행 시간은 microphone 수, scene 길이, FFT, 대역 폭과 장치에 함께 좌우됩니다. +## 음향 환경과 마이크 응답 + +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 map이며 위치 확률분포가 아닙니다. Camera는 map의 @@ -143,13 +160,22 @@ index와 audio asset 재생 위치가 이어지도록 신호를 합성합니다. - 모델: 준정적 위치 변화이며 Doppler와 창 내부의 연속 전파 경로 변화는 포함하지 않음 - 실제 장치: 물리 192채널 capture/stream gateway는 하드웨어 형식이 정해진 뒤 별도 adapter가 필요 +Scene 합성 없이 동기식 `Float32Array` 마이크 채널을 바로 처리하는 +`createLocalizationPlan`, `localizeMultichannel`과 `StreamingDasLocalizer`가 +`packages/acoustics-core`에 분리되어 있습니다. 고정 ring buffer, oldest-first drop, +반복 geometry·steering cache와 `AbortSignal` 취소를 제공하며 실제 capture 장치에는 +channel/clock/transport adapter만 별도로 연결합니다. 실시간 여부는 각 결과의 +`processingTimeMs <= deadlineMs`와 누적 `deadlineMisses`·`droppedSamples`로 +해당 장치에서 확인합니다. 복사할 파일과 운용 계약은 +[실측 다채널 위치추정 코어 포팅](docs/realtime-porting.md)을 참고하세요. + ## Result JSON Result JSON은 계약 버전 `1.0.0`의 `micarrsim.result` 문서입니다. 주요 내용은 다음과 같습니다. - 실행한 `experimentId`, `arrayId`, `sceneId`, 실제 `backend`와 생성 시각 - Array·Scene·Experiment의 canonical SHA-256인 `inputHash` -- 정규화 전 peak, 적용 scale과 clipping 수를 담은 `signalStats` +- 정규화 전 peak, 적용 scale, clipping 수와 음향 모델·희소 경로 수를 담은 `signalStats` - 전체·신호 생성·beamforming 시간인 `timingMs` - 주파수 대역별 선형 power `rawMap`, 표시용 `displayMap`, 검출 `peaks` - 위치 오차, precision/recall, truth 반경 내 energy, peak-to-sidelobe, main-lobe 폭을 계산하기 @@ -166,10 +192,12 @@ noise source는 스펙트럼을 미리 알 수 없으므로 모든 band의 groun 않습니다. 선택한 파일은 브라우저 메모리에서 읽으며 생성한 JSON/WAV는 브라우저 다운로드로만 저장됩니다. -현재 음향 모델은 직접 경로와 거리 감쇠를 사용하는 자유음장 모델입니다. 반사, 잔향, 회절, -차폐, 바람, 실제 MEMS 비선형과 장착 구조는 모델링하지 않습니다. Beamformer는 conventional -DAS이며 UI의 DAMAS와 CLEAN-SC는 아직 사용할 수 없습니다. 따라서 결과는 배열·grid·대역의 상대 -비교와 소프트웨어 검증용이며, 현장 성능 인증이나 안전 판단을 대신하지 않습니다. +음향 모델은 직접 경로의 자유음장과 1차 반사·scattering·occluder 회절·RT60 tail을 제한된 +경로로 계산하는 shoebox 근사를 제공합니다. 파동 방정식, 고차 반사, 재질별 주파수 의존 흡음, +복잡한 mesh 회절, 바람, Doppler, 마이크 self-noise·비선형, ADC와 channel clock은 모델링하지 +않습니다. Beamformer는 conventional DAS이며 UI의 DAMAS와 CLEAN-SC는 아직 사용할 수 없습니다. +따라서 결과는 배열·grid·대역의 상대 비교와 소프트웨어 검증용이며, 현장 성능 인증이나 안전 +판단을 대신하지 않습니다. ## 배열 예제 @@ -200,6 +228,8 @@ test.cmd ## 저장 형식과 개발 문서 - [`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 포팅 - [`schemas/README.md`](schemas/README.md): JSON Schema 구성 - [`docs/execution-plan.md`](docs/execution-plan.md): 구현 단계와 기술 결정 - [`goal.md`](goal.md): 프로젝트 목표 diff --git a/apps/acoustic-camera/README.md b/apps/acoustic-camera/README.md index d4d807b..25e5e70 100644 --- a/apps/acoustic-camera/README.md +++ b/apps/acoustic-camera/README.md @@ -1,9 +1,10 @@ # Acoustic Camera -Scene과 마이크 배열로 자유음장 microphone signal을 합성하고, STFT와 conventional DAS를 통해 -주파수 대역별 acoustic map과 ground-truth 평가 지표를 만드는 브라우저 앱입니다. +Scene과 마이크 배열로 자유음장 또는 저비용 shoebox microphone signal을 합성하고, STFT와 +conventional DAS를 통해 주파수 대역별 acoustic map과 ground-truth 평가 지표를 만드는 브라우저 +앱입니다. 정지 장면은 Snapshot, trajectory 장면은 Moving 흐름으로 분리되어 있습니다. -## 열기와 기본 예제 +## 열기와 Snapshot 저장소의 `start.cmd`를 실행한 뒤 시작 화면에서 **Acoustic Camera**를 선택하거나 을 엽니다. `index.html`을 직접 열지 마세요. @@ -12,11 +13,11 @@ Scene과 마이크 배열로 자유음장 microphone signal을 합성하고, STF 1. 기본 fixture가 준비될 때까지 기다립니다. 2. 192채널 rectangular 배열, single-tone scene과 50×50 grid를 그대로 둡니다. -3. **기본 예제 실행**을 누릅니다. +3. 상단 작업 순서에서 입력·설정 상태를 확인한 뒤 Snapshot 카드의 **▶ Snapshot 실행**을 누릅니다. 4. 완료 후 overlay, 위치 오차와 timing을 확인하고 **Result JSON**을 저장합니다. -이동 장면을 바로 보려면 **이동 예제 → 라이브 준비 → 재생** 순서로 누릅니다. 기본 예제는 -24×18 grid와 2 Hz map rate를 사용해 CPU fallback에서도 준비량을 줄였습니다. +이동 장면을 바로 보려면 Moving 카드에서 **이동 예제 열기 → Map 준비 → 재생** 순서로 누릅니다. +이동 예제는 24×18 grid와 2 Hz map rate를 사용해 CPU fallback에서도 준비량을 줄였습니다. ## 사용자 입력 불러오기 @@ -51,6 +52,45 @@ Camera가 SHA-256을 계산해 manifest에 연결합니다. 같은 이름이라 WebGPU가 감지돼도 실제 장치는 실행 시 확인합니다. 계산 중 **계산 취소**를 누르면 Worker를 종료하며, 이미 완료된 이전 결과가 있으면 그대로 남습니다. +## 음향 환경과 마이크 주파수 응답 + +**고급 설정 → 음향 환경**에서 다음 preset을 선택합니다. + +- **자유음장 · 직접음만**: 거리 지연과 `1/r` 감쇠의 기준선 +- **흡음된 실내 · 짧은 잔향**: 수신점당 최대 17개 sparse path +- **일반 실내 · 균형**: 수신점당 최대 19개 sparse path +- **반사 강한 실내**: 수신점당 최대 23개 sparse path + +실내 preset은 현재 마이크, 정적·trajectory source와 scan corner를 포함하도록 직육면체 room을 +자동 추론합니다. 직접음에 여섯 면의 1차 image-source 반사, 결정적 scattering과 tap 수가 제한된 +RT60 diffuse tail을 추가합니다. Scene JSON에 사용자 `shoebox`와 축 정렬 +`occluders`를 넣으면 직접음 감쇠와 최단 corner 우회 회절도 계산합니다. 사용자 설정은 +dropdown에 **Scene 사용자 설정**으로 표시되고 preset 값으로 덮어쓰기 전까지 유지됩니다. + +Array의 각 microphone에는 선택적 `frequencyResponse`를 넣을 수 있습니다. + +```json +{ + "id": "mic-001", + "position": [-0.225, 0.225, 0], + "frequencyResponse": [ + { "frequencyHz": 100, "gainDb": -8, "phaseDeg": -12 }, + { "frequencyHz": 1000, "gainDb": -0.7, "phaseDeg": -2 }, + { "frequencyHz": 10000, "gainDb": 1.2, "phaseDeg": 8 } + ] +} +``` + +curve는 합성 microphone channel에 항상 적용됩니다. **마이크 주파수 응답 처리**의 기본 +**측정 curve 적용 + 위치추정에서 역보정**은 CPU와 WebGPU DAS에서 알려진 gain/phase를 +역보정합니다. **측정 curve 적용 + 보정하지 않음**은 합성 응답은 유지하고 역보정만 꺼서 영향을 +비교합니다. curve가 없는 마이크는 기존 결과를 유지합니다. 응답 notch를 과도하게 증폭하지 +않도록 역보정의 양의 gain boost는 기본 24 dB로 제한하며, 사용자 Experiment JSON의 +`beamforming.maxCompensationDb`에서 0–120 dB로 지정할 수 있습니다. + +모델 수식, preset 값, Scene/Array/Experiment 예와 제외 범위는 +[음향 환경과 마이크 응답 모델](../../docs/acoustic-model.md)을 참고하세요. + ## Grid, STFT와 대역 50×50은 2,500 points입니다. 이를 1로 보면 100×100은 4배, 200×200은 16배 points를 계산합니다. @@ -87,11 +127,11 @@ WebGPU가 감지돼도 실제 장치는 실행 시 확인합니다. 계산 중 * ## 이동 음원 라이브 -Scene source에 두 개 이상의 `trajectory` keyframe이 있으면 **라이브 준비**가 활성화됩니다. +Scene source에 두 개 이상의 `trajectory` keyframe이 있으면 **Map 준비**가 활성화됩니다. Builder에서는 **시간에 따라 음원 이동**과 경로 미리보기 slider로 이 데이터를 만들 수 있습니다. 1. Map rate와 backend를 선택합니다. 처음에는 2 Hz와 Auto를 권장합니다. -2. **라이브 준비**를 누릅니다. 현재 입력 snapshot을 최대 48개, map당 최대 2,500 points의 짧은 +2. **Map 준비**를 누릅니다. 현재 입력 snapshot을 최대 48개, map당 최대 2,500 points의 짧은 분석창으로 계산합니다. 3. **재생** 또는 시간 slider로 이동합니다. Heatmap은 이웃한 acoustic map 사이를 보간하고 source 위치는 keyframe 사이를 연속 보간합니다. @@ -107,7 +147,8 @@ Scene 시간에 이어 붙입니다. 한 창 안에서는 중앙 시각의 위 - `experimentId`, `arrayId`, `sceneId`, `createdAt`, 실제 `backend` - 실행 입력 전체의 canonical SHA-256인 `inputHash` -- `signalStats`: 정규화 전 peak, 적용 scale, clipped sample 수 +- `signalStats`: 정규화 전 peak, 적용 scale, clipped sample 수, 실제 음향 모델과 sparse + path 전체·종류별 수 - `timingMs`: 전체, signal generation과 beamforming 시간 - band별 `rawMap` 선형 power, `displayMap`, 검출 `peaks` - 각 peak의 비보정 half-power 공분산과 RMS ellipse인 `beamSpread` @@ -120,9 +161,19 @@ z가 scan z와 다르면 평면에 투영한 x/y를 사용하므로 UI 경고와 ## 해석 한계 -신호 모델은 직접 경로와 거리 감쇠를 사용하는 자유음장입니다. 반사, 잔향, 회절, 차폐, 바람, -센서 비선형과 장착 구조는 포함하지 않습니다. 배열 JSON의 sensitivity/phase calibration은 적용하지만 -결과는 상대 배열 비교와 알고리즘 검증용이며 실측 인증을 대신하지 않습니다. +신호 모델은 직접 경로의 자유음장과 선택적인 shoebox 희소 근사입니다. shoebox는 1차 반사, +deterministic scattering, 축 정렬 occluder의 직접음 감쇠·최단 corner 우회 회절과 제한된 RT60 +tail을 포함합니다. 파동 방정식, 고차 반사, 재질별 주파수 의존 흡음, 복잡한 mesh, 바람, Doppler, +센서 self-noise·비선형, ADC·clock과 장착 구조는 포함하지 않습니다. 배열 JSON의 +sensitivity/phase/frequency-response calibration은 적용하지만 결과는 상대 배열 비교와 알고리즘 +검증용이며 실측 인증을 대신하지 않습니다. + +실제 동기식 microphone `Float32Array`를 Scene 합성 없이 위치추정하려면 +[실시간 위치추정 코어 포팅](../../docs/realtime-porting.md)의 +`createLocalizationPlan`, `localizeMultichannel` 또는 +`StreamingDasLocalizer`를 사용하세요. 실시간성은 장치에서 +`processingTimeMs <= deadlineMs`와 `deadlineMisses`·`droppedSamples`를 +측정해 판정해야 합니다. WebGPU 성능을 별도로 측정하려면 서버 실행 후 을 여세요. diff --git a/docs/acoustic-model.md b/docs/acoustic-model.md new file mode 100644 index 0000000..d5fd38a --- /dev/null +++ b/docs/acoustic-model.md @@ -0,0 +1,182 @@ +# 음향 환경과 마이크 응답 모델 + +micarrsim의 음향 합성은 마이크 어레이 배치와 위치추정 알고리즘의 상대 성능을 빠르게 비교하기 +위한 모델이다. ADC나 마이크 전자회로까지 재현하는 하드웨어 시뮬레이터가 아니며, 자유음장과 +계산량이 제한된 실내 희소 경로 근사 중 하나를 선택한다. + +## 신호 처리 범위 + +Snapshot 한 번의 처리 순서는 다음과 같다. + +1. tone, noise 또는 audio asset으로 음원 신호를 만든다. +2. 음원과 각 마이크 사이의 직접음 또는 희소 multipath 전달함수를 만든다. +3. 마이크별 `sensitivityDb`, `phaseOffsetDeg`와 `frequencyResponse`를 수신 신호에 적용한다. +4. 합성된 동기식 다채널 신호를 STFT하고 conventional DAS map을 계산한다. +5. 설정에 따라 알려진 마이크 응답을 DAS에서 역보정하고 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을 늘리면 beamforming의 `O(scan points × microphones × selected bins × STFT frames)` +뿐 아니라 신호 합성의 전달함수 누산도 늘어난다. 처음에는 50×50 grid와 자유음장으로 기준선을 +만들고, 같은 입력에서 preset을 하나씩 바꾸어 비교하는 것이 좋다. + +## 마이크 주파수 응답 + +각 마이크에는 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를 실제 마이크 +채널에 적용한다. + +Experiment에서 `beamforming.compensateFrequencyResponse`를 생략하거나 `true`로 두면 +CPU와 WebGPU DAS가 선택 FFT bin에서 알려진 curve의 역 gain/phase를 적용한다. 응답 notch의 +무제한 역보정은 noise까지 크게 증폭할 수 있으므로 양의 보상 boost는 +`beamforming.maxCompensationDb`로 제한하며 기본값은 24 dB다. 허용 범위는 0–120 dB이고 +응답 peak를 줄이는 attenuation과 phase 보상은 이 boost 상한에 의해 잘리지 않는다. + +```json +{ + "beamforming": { + "algorithm": "das", + "backend": "auto", + "minimumDistance": 0.01, + "normalization": "peak", + "dynamicRangeDb": 45, + "compensateFrequencyResponse": true, + "maxCompensationDb": 24 + } +} +``` + +Camera의 **마이크 주파수 응답 처리**에서 **측정 curve 적용 + 보정하지 않음**을 고르면 합성에는 +curve가 남고 DAS 역보정만 꺼진다. 같은 배열에서 보정 유무의 robustness를 비교할 때 사용한다. +curve가 없는 마이크는 0 dB, 0°로 취급한다. + +## 결과에서 확인할 값 + +Result `signalStats`에는 다음 선택 필드가 들어간다. + +- `acousticModel`: `free-field` 또는 `shoebox` +- `acousticPathCount`: 실제 합성에 사용한 전체 경로 수 +- `acousticPathCounts`: `direct`, `reflection`, `scattering`, + `diffraction`, `diffuse` 종류별 수 + +같은 입력과 seed에서 환경 preset만 바꿨다면 이 값과 위치 오차·precision/recall·PSR을 함께 +비교할 수 있다. + +## 정확도 범위와 제외 사항 + +이 구현은 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은 특정 방을 인증하는 값이 아니라 배열과 DAS가 multipath에 +얼마나 민감한지 비교하는 조건이다. 실제 장치 성능을 평가할 때는 같은 Array/scan/band 설정으로 +동기식 실측 채널을 [실시간 위치추정 코어](realtime-porting.md)에 입력하고 합성 결과와 나란히 +비교해야 한다. 주파수 응답 curve만으로 noise floor, distortion, ADC와 clock 오차까지 모사되지는 +않는다. diff --git a/docs/data-contracts.md b/docs/data-contracts.md index f4e15f5..0ab0584 100644 --- a/docs/data-contracts.md +++ b/docs/data-contracts.md @@ -18,8 +18,17 @@ scene JSON에는 192채널 원시 sample이나 원본 asset byte를 넣지 않 `sha256` manifest로 참조한다. 사용자 컴퓨터의 절대 경로, URL, `..` 경로는 저장하지 않는다. array의 `sensitivityDb`와 `phaseOffsetDeg`는 각 마이크 수신 channel에 적용되는 편차다. 합성기는 -이를 신호에 주입하고, beamformer는 알려진 calibration 값의 역 gain/phase를 적용한다. 따라서 -두 값이 0이 아닌 배열도 오류 없이 조용히 무시되지 않는다. +이를 신호에 주입하고, beamformer는 알려진 calibration 값의 역 gain/phase를 적용한다. 선택적 +`frequencyResponse`는 2–64개의 `{ frequencyHz, gainDb, phaseDeg? }` 측정점이다. +주파수는 0–1,000,000 Hz에서 중복 없이 증가해야 하며, dB와 wrapped phase를 구간 선형 보간하고 +측정 범위 밖에서는 가까운 끝점을 사용한다. + +Experiment의 선택적 `beamforming.compensateFrequencyResponse`는 기본 `true`다. 합성 +channel에는 curve가 항상 적용되며, `true`이면 CPU/WebGPU DAS가 선택 bin에서 curve의 +역 gain/phase도 적용한다. `false`이면 sensitivity/phase calibration은 유지하고 curve +역보정만 끈다. 선택적 `beamforming.maxCompensationDb`는 응답 notch의 역보정에서 양의 +gain boost만 제한하는 0–120 dB 값이며 생략 시 24 dB다. 응답 peak를 줄이는 attenuation과 +phase 보상은 이 boost 상한을 그대로 적용하지 않는다. ## 로컬 asset 재연결 @@ -45,6 +54,26 @@ Camera 라이브 미리보기는 sample 경계에 맞춘 시간창 중앙에서 창으로 Scene 시간을 다시 기준화해도 tone 위상, noise sample index와 audio asset 재생 위치는 원래 절대 시간에 이어진다. 이는 준정적 근사이며 Doppler를 계약하지 않는다. +## 음향 환경 + +Scene의 선택적 `acoustics.model`은 `free-field` 또는 `shoebox`다. 필드를 +생략한 문서는 free-field로 해석해 이전 직접음 결과를 유지한다. free-field에는 사용되지 않는 +`room`, `reflections`, `diffuseReverb` 또는 `occluders`를 함께 둘 수 없다. + +shoebox에는 `room.min`과 `room.max`가 필요하다. 각 축에서 min은 max보다 작아야 하며 +정적 source와 모든 trajectory keyframe은 room 안에 있어야 한다. `reflections.order`는 +0 또는 1이고, `wallGainDb`와 선택적 면별 `perWallDb`는 -60–0 dB, +`scattering`은 0–1이다. + +`diffuseReverb`는 `enabled`, 0.05–5 s의 `rt60Seconds`, -60–0 dB의 +`gainDb`와 1–32의 `tapCount`를 갖는다. 축 정렬 `occluders`는 최대 8개이며 +room 안의 min/max, 고유 id, -120–0 dB의 `transmissionDb`와 +`diffractionGainDb`를 갖는다. + +이 계약은 직접음, 여섯 면의 1차 image-source, 결정적 scattering, 막힌 occluder별 최단 corner +우회와 제한된 RT60 tail을 위한 것이다. 재질 mesh나 고차 room impulse response 계약은 아니다. +세부 계산과 preset은 [음향 환경과 마이크 응답 모델](acoustic-model.md)에 설명한다. + ## 오디오와 map 정규화 `scene.mix.normalization`은 마이크 신호 합성 전에 적용할 오디오 mix 정책이다. `none`은 원래 @@ -81,6 +110,11 @@ threshold와 최소 거리, sidelobe 제외 반경, half-power 비율, dynamic r 버전과 함께 저장한다. `environment`에는 실제 backend, microphone/grid 수, scan bounds와 z, 가능한 경우 GPU adapter 및 fallback 정보를 기록한다. +`signalStats`는 정규화 전 peak, scale과 clipping 수 외에 선택적으로 +`acousticModel`, 실제 전체 `acousticPathCount`와 `acousticPathCounts`를 +기록한다. 종류별 key는 `direct`, `reflection`, `scattering`, +`diffraction`과 `diffuse`다. + 대역별 ground truth는 tone의 주파수가 band 안에 있을 때 그 tone source를 포함한다. noise와 asset source는 현재 모든 band의 truth로 간주한다. 즉 녹음 asset의 실제 spectrum energy를 대역별로 판정하는 계약은 아직 없으며, 이 가정은 실제 데이터 결과를 해석할 때 고려해야 한다. @@ -100,8 +134,19 @@ SHA-256을 계산해 scene의 해당 asset `sha256` 필드를 채운 상태로 c - 중복 id와 array/scene/experiment/result 참조 - asset 종류와 안전한 상대 경로 - Nyquist 및 시간·scan 범위 +- 마이크 주파수 응답점의 범위·정렬과 shoebox room/occluder 포함 관계 - map shape와 source peak 매칭 - band별 evaluation 파라미터와 허용 metric -- 현재 비스트리밍 CPU backend의 512 MiB channel-buffer 예산 +- Snapshot channel·최대 sparse delay FFT working set의 512 MiB 예산 지원하지 않는 schemaVersion은 묵시적으로 변환하지 않고 오류로 알린다. + +실측 channel을 받는 portable API는 저장 JSON 계약과 별도로 입력 Array를 같은 규칙으로 검사한다. +CPU 분석 계획은 기본 512 MiB, 반복 steering cache는 64 MiB, streaming ring과 분석창은 기본 +256 MiB hard cap을 할당 전에 적용한다. 채널 순서와 streaming 상태 계약은 +[실측 다채널 위치추정 코어 포팅](realtime-porting.md)을 참고한다. + +portable block 결과의 `processingTimeMs`는 DAS와 local-peak 검출 wall time이다. Streaming +결과는 `deadlineMs`와 `deadlineMet`을 추가하고 상태에는 최근·최대 처리 시간, +`deadlineMisses`와 `droppedSamples`를 누적한다. 이 runtime telemetry는 +`micarrsim.result` 저장 스키마의 필수 필드가 아니다. diff --git a/docs/execution-plan.md b/docs/execution-plan.md index 3b1df55..80031ff 100644 --- a/docs/execution-plan.md +++ b/docs/execution-plan.md @@ -2,15 +2,16 @@ > 구현 상태 · 2026-08-28 > -> 단계 0–4는 완료되어 설치 없는 브라우저 앱, CPU/WebGPU DAS, Builder→Camera asset 재연결, -> 임의 오디오·이동 trajectory, 빔 분포·복수 peak 감도, 라이브 시간축 재생, 배열 비교와 -> Result 내보내기를 71개 자동 테스트로 검증했다. 단계 5는 실제 장치·공간 모델 고도화 범위다. +> 단계 0–4와 단계 5의 저비용 음향 환경·마이크 응답·portable streaming core까지 완료했다. +> 설치 없는 브라우저 앱, CPU/WebGPU DAS, Builder→Camera asset 재연결, 임의 오디오·이동 +> trajectory, 빔 분포·복수 peak 감도, 라이브 시간축 재생, 배열 비교와 Result 내보내기를 +> 전체 자동 테스트로 검증했다. 실제 장치 adapter와 현장 검증은 장치 계약이 필요한 후속 범위다. ## 1. 목표와 성공 기준 이 프로젝트는 정방형 평면에 배치할 192개 MEMS 마이크의 배열을 비교하기 위한 재현 가능한 -시뮬레이터를 만든다. 첫 버전은 자유음장(free field), 점 음원, 구면파 전파를 가정하며 다음 흐름을 -끝까지 수행해야 한다. +시뮬레이터를 만든다. 기준선은 자유음장(free field), 점 음원과 구면파 전파이며, 같은 입력에서 +마이크 응답과 계산량이 제한된 shoebox multipath를 선택해 다음 흐름을 끝까지 수행한다. 1. 기계음 데이터와 ambient audio를 조합해 장면 및 ground truth를 생성한다. 2. 배열 JSON과 장면 정보를 사용해 각 마이크에 도달하는 신호를 합성한다. @@ -42,8 +43,8 @@ CPU 기준 구현과 GPU 결과의 수치 오차가 합의된 허용 범위 안 seed 고정, 합성 오디오와 ground truth manifest 내보내기 - `acoustic-camera`: manifest와 배열 JSON 읽기, 마이크 신호 전파 합성, steering vector 생성, DAS 실행, overlay·수치 평가·실험 결과 내보내기 -- `acoustics-core`: 두 앱이 공유하는 좌표계, 단위, 구면 감쇠·지연, STFT, 정답 rasterization, - 지표 및 CPU reference +- `acoustics-core`: 두 앱이 공유하는 좌표계, 단위, 구면 감쇠·희소 multipath·마이크 응답, + STFT, 정답 rasterization, 지표, CPU reference와 실측 channel용 streaming localizer - `webgpu-kernels`: steering/DAS 커널, buffer layout, 장치 한도 검사와 benchmark ## 3. 데이터 계약 @@ -52,43 +53,62 @@ JSON Schema를 먼저 고정하고 모든 길이는 m, 시간은 s, 주파수는 명시한다. - `array.schema.json`: schema version, 배열 폭·높이, 192개 마이크의 id와 `[x,y,z]`, 선택적 - 감도·채널 보정값 + 감도·위상·주파수 응답 보정값 - `scene.schema.json`: 배경 이미지 크기와 실제 평면 변환, 음원별 위치·오디오 참조·시작/종료· - gain, ambient 참조, sample rate, seed + gain, ambient 참조, sample rate, seed, 선택적 자유음장·shoebox 환경 - `experiment.schema.json`: 배열/장면 참조, AC-음원 거리, 음속, frequency band 목록과 색, STFT window/hop, scan bounds와 해상도, 알고리즘 및 normalization - `result.schema.json`: 실행 환경, timing, acoustic map, peak, 평가 지표, 입력 hash 오디오 파일은 manifest 옆의 상대 경로로 참조한다. 브라우저 내 객체 URL은 저장 형식에 포함하지 -않는다. 스키마에는 버전을 두고 향후 잔향 모델과 마이크 지향성을 선택 필드로 추가한다. +않는다. 스키마에는 버전을 두며, 현재 잔향은 1차 반사·scattering·RT60 tail의 희소 근사로 +계약한다. 마이크 지향성과 더 복잡한 재질·mesh 모델은 후속 선택 필드로 남긴다. ## 4. 음향 및 연산 모델 -첫 모델에서 음원 `s`와 마이크 `m` 사이 거리 `r`에 대해 지연은 `r/c`, 진폭은 기준 거리와 -최소 거리 clamp를 둔 `1/r`로 계산한다. 분수 sample 지연은 주파수 영역의 phase shift로 처리한다. -복수 음원과 ambient를 선형 합산하되 clipping 전 peak와 최종 normalization을 기록한다. +기준 자유음장은 음원 `s`와 마이크 `m` 사이 거리 `r`에 대해 지연 `r/c`와 최소 거리 +clamp를 둔 `1/r` 진폭을 사용한다. 선택적 shoebox는 직접음, 여섯 면의 1차 image-source, +반사 에너지의 deterministic scattering, 축 정렬 occluder의 transmission·최단 corner 우회와 +tap 수가 제한된 RT60 tail만 추가한다. 경로를 source–microphone 전달함수 하나로 합치고 IFFT를 +한 번만 수행하며 위상 recurrence로 bin별 삼각함수 호출을 줄인다. + +마이크별 2–64점 `frequencyResponse`는 dB와 wrapped phase를 보간해 수신 channel에 적용한다. +기본 DAS는 sensitivity/phase와 frequency curve의 알려진 역응답을 적용하되 notch의 양의 boost는 +기본 24 dB로 제한하고, curve 보정만 끈 robustness 비교도 저장 가능하다. 복수 음원과 ambient를 +선형 합산하되 clipping 전 peak, 최종 normalization, 음향 모델과 실제 종류별 경로 수를 기록한다. DAS는 STFT 후 각 scan point와 마이크 사이 거리로 steering phase를 만들고, 선택된 주파수 bin의 정렬 합 power를 계산한다. 여러 주파수 구간은 각각 독립 map과 색을 갖는다. CPU reference를 먼저 작성한 뒤 같은 buffer layout으로 WGSL 결과를 대조한다. DAMAS, CLEAN-SC는 인터페이스만 마련하고 초기 완료 범위에서는 제외한다. -연산량의 주항은 대략 `O(P × M × F)`다. `M=192`, `P=50²=2,500`일 때 주파수 bin 하나당 +연산량의 주항은 대략 `O(P × M × F × T)`다. `M=192`, `P=50²=2,500`일 때 STFT +frame·주파수 bin 하나당 약 48만 개의 복소 steering 누산이 필요하다. 100×100은 50×50보다 4배, 200×200은 16배이므로 장치별 실제 GPU timing을 UI에 표시하고 목표 frame budget에 맞춰 해상도를 제한한다. 정확한 성능과 메모리는 대표 GPU에서 benchmark하여 기록하며 이론치만으로 약속하지 않는다. +실측·반복 분석용 CPU 계획은 거리 행렬, bin calibration, 임시 map과 허용되는 steering matrix를 +재사용한다. 192채널·50×50·2 bins를 10회 분석하는 기준에서 거리 계산은 4,800,000회에서 +480,000회, steering pair는 9,600,000회에서 960,000회로 줄어든다. snapshot working set과 계획은 +512 MiB, steering cache는 64 MiB, streaming input은 256 MiB 기본 hard cap을 할당 전에 적용한다. +Streaming ring은 backlog에서 가장 오래된 sample을 버리고 호출당 결과 수를 제한한다. +각 portable 분석은 `processingTimeMs`를 기록하고 streaming은 hop 기반 +`deadlineMet`, `deadlineMisses`와 `droppedSamples`로 실제 장치의 지속 +처리 가능 여부를 측정한다. cache 수치만으로 실시간성을 보장하지 않는다. + ## 5. UI 계획 -`acoustic-camera`는 폭 600px 이상인 좌측 scene canvas에 기기 이미지, ground-truth hint, -주파수별 acoustic overlay를 표시한다. 우측에는 배열 geometry를 좌표와 함께 정적 평면도로 -표시하고 그 아래에 제어 패널을 둔다. 작은 화면에서는 두 열을 세로로 쌓는다. 확대·회전 상호작용은 -향후 필요성 검증 뒤 추가한다. +`acoustic-camera`는 **입력 → 설정 → 실행 → 확인**의 고정 작업 순서를 먼저 보여준다. 실행은 +정지 장면의 Snapshot과 trajectory의 Moving 카드로 나뉘며, 결과 canvas를 주 작업 영역으로 둔다. +Scene·Array·Experiment·Assets 준비 상태와 실행 가능 여부를 가까이 표시하고, 비교 기록과 저장 +기능은 필요할 때 펼치는 보조 영역으로 내린다. 작은 화면에서는 한 열로 쌓는다. -필수 입력은 음원 수와 위치, AC 거리, 다중 주파수 구간과 색, ambient 파일, scan grid 크기, -후처리 선택이다. 여기에 sample rate, 음속/온도, STFT window·hop, scan 영역, dynamic range, -colormap/opacity, 음원별 gain·시작 시간, random seed, 정규화 방법을 추가한다. 잘못된 단위, -Nyquist 초과 대역, WebGPU buffer 한도는 실행 전에 검증한다. +일상적으로 바꾸는 backend, grid, 대역과 peak 감도는 설정 단계에 유지한다. 음속, seed, scan +범위, STFT, 음향 환경 preset과 마이크 응답 보상은 **고급 설정**에 묶는다. 장문의 개발 요구나 +미구현 기능 홍보는 작업 화면에서 제거하고, 물리 모델·데이터 계약·포팅 설명은 문서로 연결한다. +잘못된 단위, Nyquist 초과 대역, room 포함 관계와 CPU/GPU·신호 working-set 한도는 실행 전에 +검증한다. ## 6. 평가 방법 @@ -158,26 +178,31 @@ flattening이 모델 타당성을 훼손하는지 청취 및 spectrum 통계로 완료 조건: 사용자가 코드 수정 없이 배열 JSON 두 개를 같은 장면에서 비교할 수 있다. -### 단계 5 — 실제 데이터와 고도화 · 향후 +### 단계 5 — 현실성·포팅과 실제 데이터 · 부분 완료 -- 라이선스 검토를 통과한 DCASE/MIMII adapter와 batch workflow 추가 -- microphone calibration·noise 모델 검토 -- 실제 192채널 장치의 channel/clock/sample 형식이 정해진 뒤 capture·stream adapter 추가 -- 필요 시 DAMAS/CLEAN-SC를 플러그인형 후처리로 추가 -- image-source method 또는 room impulse response 기반 잔향 모듈 추가 +- [x] 마이크별 gain·phase·frequency-response 합성 및 선택적 DAS 역보정 +- [x] 자유음장을 보존하는 선택형 shoebox 1차 반사·scattering·회절·RT60 tail +- [x] Scene 합성에서 분리한 block/streaming multichannel 위치추정 API +- [x] 반복 거리·calibration·steering cache, bounded ring과 메모리 hard cap +- [ ] 라이선스 검토를 통과한 DCASE/MIMII adapter와 batch workflow +- [ ] 실제 장치의 channel/clock/sample 형식에 맞춘 capture·transport adapter와 현장 검증 +- [ ] 필요 시 센서 self-noise·위치 공차와 DAMAS/CLEAN-SC 후처리 -완료 조건: 자유음장 결과를 훼손하지 않고 propagation model을 선택해 재실행할 수 있다. +현재 완료 조건은 기존 자유음장 결과를 유지한 채 propagation model과 응답 보상을 선택해 +재실행하고, 같은 CPU DAS를 실측 `Float32Array` channel에 직접 적용하는 것이다. 실제 +hardware deadline과 정확도는 장치 adapter가 정해진 뒤 별도 측정한다. ## 9. 주요 위험과 대응 - WebGPU 미지원/장치 한도: 시작 시 capability를 표시하고 CPU fallback 및 grid 상한을 둔다. - 좌표·phase 부호 오류: analytic tone test와 배열 대칭성 test를 먼저 만든다. -- 브라우저 메모리: snapshot은 전체 192채널 signal buffer에 512 MiB 한도를 적용하고, 이동 - 미리보기는 최대 48개·2,500 points의 짧은 시간창으로 제한한다. 실제 장시간 capture는 향후 - chunk/STFT streaming backend로 확장한다. +- 브라우저 메모리: snapshot signal·최대 sparse delay FFT에 512 MiB 한도를 적용하고, 이동 + 미리보기는 최대 48개·2,500 points의 짧은 시간창으로 제한한다. 장시간 입력은 256 MiB 기본 + 한도의 fixed ring streaming core에서 처리하고 overload의 `droppedSamples`를 감시한다. - 데이터셋 부적합/라이선스: 로컬 asset 계약을 유지하고 synthetic fixture를 기본 test 입력으로 쓴다. 실제 데이터 adapter는 단계 5의 라이선스 검토 뒤 추가한다. -- 실제 AC와 simulation gap: 감도, 위상, 위치 오차를 이후 calibration/noise model로 주입 가능하게 한다. +- 실제 AC와 simulation gap: gain·phase·주파수 응답과 희소 실내 환경을 비교 조건으로 제공하되, + 위치 공차·self-noise·ADC·clock은 실측 adapter와 현장 검증으로 다룬다. - post-processing이 기본 결과를 가림: raw DAS map과 후처리 map을 항상 별도로 보존한다. ## 10. 구현 결과와 다음 백로그 @@ -193,11 +218,16 @@ flattening이 모델 타당성을 훼손하는지 청취 및 spectrum 통계로 - [x] 이동 trajectory 계약·편집·시간창 합성·Camera 라이브 재생 - [x] 비확률 beam spread RMS contour와 Result export - [x] 복수 음원용 Experiment peak 검출 감도 +- [x] 마이크 주파수 응답 합성·CPU/WebGPU 역보정 비교 +- [x] 자유음장·shoebox 희소 반사/산란/회절/RT60 환경 선택 +- [x] portable block/streaming localizer와 반복 DAS cache·메모리 상한 +- [x] Camera 입력→설정→실행→확인의 Snapshot/Moving UI 재구성 - [x] `test.cmd` one-command headless browser 검증 - [ ] DCASE/MIMII 라이선스 검토와 adapter -- [ ] 실제 192채널 capture/stream adapter -- [ ] 잔향·calibration·noise model +- [ ] 실제 192채널 capture/transport adapter와 deadline·정확도 검증 +- [ ] 센서 self-noise·위치 공차·지향성 모델 - [ ] DAMAS/CLEAN-SC 후처리 -정확성 test를 먼저 통과시킨 뒤 UI 또는 최적화를 진행한다는 원칙은 유지한다. 단계 5 기능은 -자유음장 DAS 결과를 바꾸지 않는 선택형 확장으로 추가한다. +정확성 test를 먼저 통과시킨 뒤 UI 또는 최적화를 진행한다는 원칙은 유지한다. 추가 현실성 모델은 +자유음장 DAS 결과를 바꾸지 않는 선택형 확장으로, 장치 연결은 portable localizer 앞의 adapter로 +추가한다. diff --git a/docs/index.html b/docs/index.html index 5358043..82c7277 100644 --- a/docs/index.html +++ b/docs/index.html @@ -18,6 +18,7 @@ 빠른 시작 이동 라이브 내 데이터 + 환경·실측 결과 해석 문제 해결 @@ -25,11 +26,10 @@
-

Local user guide

-

설치 없이 시작하는
음향 카메라 실험

+

micarrsim 사용 설명서

- Windows 10/11과 최신 Chrome 또는 Edge만 있으면 됩니다. 모든 입력과 계산은 이 - 컴퓨터의 브라우저 안에서 처리되며 외부 서버로 업로드되지 않습니다. + start.cmd로 열고, 장면을 실행하고, 결과를 저장하는 순서만 먼저 확인하세요. + 입력과 계산은 로컬 브라우저에서 처리됩니다.

@@ -41,7 +41,7 @@
  1. start.cmd를 더블클릭합니다.
  2. 홈에서 Acoustic Camera를 엽니다.
  3. -
  4. ▶ 기본 예제 실행을 누릅니다.
  5. +
  6. Snapshot 카드의 ▶ Snapshot 실행을 누릅니다.
  7. 완료되면 Result JSON을 눌러 다운로드 폴더에 저장합니다.