소형 스피커(예: Ø40 mm 드라이버 + Ø70 mm 하우징)의 리플렉터·방사구 형상을 설계하기 위한 브라우저 기반 음향 시뮬레이터. 2D 축대칭(r-z) FDTD 파동 시뮬레이션으로 회절·반사·간섭을 포함해 압력장, 지향성(polar), 주파수 응답을 계산한다.
npm install
npm run dev # http://localhost:5173
npm run validate # 무한 배플 피스톤 이론값과 비교 (PASS 확인)src/engine/scene.ts— 씬(형상) 스키마. mm 단위 r-z 단면. rect/polygon, rigid/fabric/air, piston/radial 드라이버.src/engine/rasterize.ts— 씬 → 격자(고체 마스크, 흐름저항, 소스 면, 측정점).src/engine/fdtd.ts— 축대칭 FDTD 솔버(CPU). 참조 구현이자 node 검증용.src/engine/gpu.ts— 같은 수식의 WebGPU(WGSL) 구현. 속도·소스·압력·측정점 4개 컴퓨트 패스를 스텝당 실행하고 측정점 시계열은 GPU에 누적.backend: auto | gpu | cpu, UI의 "CPU/GPU 일치 검사"로 두 백엔드를 비교할 수 있다.src/engine/analysis.ts— 임펄스 응답 → 주파수 응답, 지향성.src/engine/presets.ts— 프리셋 씬(측면 방사형, 정면, 상향 360, 검증용 배플 피스톤).src/worker/sim.worker.ts— Web Worker 실행.src/ui/— 셸(App)·레이어·라이브러리·인스펙터·결과 도크·탐색·설계안 패널, 단면 캔버스, polar·주파수 응답 차트, 테마 브리지.scripts/validate.ts— 솔버 검증.
Figma·Plasticity 류의 도구와 같은 4분면 구조다. 어떤 작업을 하든 선택한 요소의 속성은 항상 오른쪽에, 결과는 항상 아래에 있다.
- 왼쪽 레일: 활동 전환. 레이어(1) · 라이브러리(2) · 설계 탐색(3) · 설계안(4).
?로 단축키 목록. - 레이어 패널 (
src/ui/LayersPanel.tsx): 씬 아웃라이너. 드라이버 → 형상 → 환경(측정 원호·바닥·해석 영역) 순. 클릭으로 선택(Shift 로 다중), 더블클릭으로 이름 변경, 위/아래로 적용 순서 변경(위에 있을수록 나중에 래스터라이즈되어 슬롯이 벽을 뚫는다), Delete 로 삭제.+메뉴에서 펜/사각형/원 도구, 드라이버, 드라이버 몸체, 슬롯·패브릭 띠를 추가한다. - 라이브러리 패널 (
src/ui/LibraryPanel.tsx): 썸네일이 있는 예제 형상, SVG 가져오기/내보내기, JSON 내보내기, 빈 설계, 씬 JSON 직접 편집. - 캔버스: 편집기이자 압력장 뷰어. 하단 중앙 도구 막대(선택 V · 펜 P · 사각형 R · 원 E · 실행취소/다시실행), 우상단 보기 컨트롤(확대/축소 배율, 기기에 맞춤, 해석 영역 전체, 격자 마스크), 좌상단 상태·범례, 우하단 축척·좌표. 탐색/설계안에서 후보를 고르면 캔버스가 미리보기로 바뀌고 상단 배너의 "편집으로 돌아가기"(Esc)로 복귀한다.
- 인스펙터 (
src/ui/Inspector.tsx, 오른쪽): 선택한 형상·띠·드라이버·측정 원호의 속성. 아무것도 선택하지 않으면 씬 설정 (실행 전 확인, 해석 설정 dx·시간·대역·흡수층·연산 장치, 해석 영역, 바닥, 설명, CPU↔GPU 일치 검사). - 결과 도크 (
src/ui/ResultsDock.tsx, 아래): 지향성 polar(주파수 슬라이더), 주파수 응답(마우스를 올리면 주파수와 각 곡선의 dB 값 표시), 실행 정보. 높이는 상단 가장자리를 끌어 조절하고 접을 수 있다. 탐색/설계안에서 체크한 항목이 공통 기준으로 겹쳐 그려진다. - 상단 바: 설계 이름(클릭해 편집), 실행 전 확인 상태 칩(클릭하면 목록), 라이트/다크 테마, 사이드 패널 접기, 해석 실행(Ctrl+Enter).
- 색 테마는 CSS 변수(
src/index.css)로 정의되고 캔버스·차트는src/ui/theme.ts를 통해 같은 팔레트를 읽는다.
가운데 캔버스가 편집기이자 미리보기다 (src/ui/SectionCanvas.tsx).
- 형상은 모두 닫힌 3차 베지어 경로(
kind: 'path', 앵커 + 들어오는/나가는 핸들). 핸들이 없으면 직선. 솔버에는 0.5 mm 간격으로 평탄화한 폴리곤이 들어가고, 축 정렬 사각형은 예전 rect 와 완전히 같은 격자를 만든다. - 앵커 드래그(핸들 동반), 앵커 더블클릭 코너↔곡선, 선 더블클릭으로 형상을 바꾸지 않고 앵커 삽입(드 카스텔죠 분할), 핸들 드래그(기본 대칭, Alt 로 비대칭), Delete 로 핸들/앵커/형상 삭제. 펜(P): 클릭 = 코너, 클릭-드래그 = 곡선 앵커. 사각형(R)·원(E) 드래그(Shift = 정사각형/정원). Shift 드래그는 앵커·핸들·형상 이동을 수직/수평으로 고정. 앵커를 선택하면 좌표와 코너/곡선 전환 팝오버가 뜬다. 인스펙터의 "모두 곡선/모두 직선". 0.5 mm 앵커 스냅, 0.1 mm 핸들 스냅, r < 0 불가.
- 슬롯과 패브릭은 띠(band) 로 편집한다. 축대칭에서는 시작 z 와 길이(패브릭은 두께도)만 의미가 있으므로 위/아래
핸들 두 개와 숫자 입력만 제공하고, r 범위는 숫자로 조정한다. 레이어의
+메뉴가 바깥 벽 위치에 기본 띠를 추가한다. 인스펙터의 "자유 형상으로 전환"을 누르면 일반 경로로 돌아가 앵커를 편집할 수 있다. 내부 표현은 축 정렬 사각형 경로라 솔버·SVG는 동일. - 띠에는 방향이 있다. 옆면(axis z)은 시작 z + 길이, 윗면/아랫면(axis r)은 시작 r + 길이로 판 두께를 관통한다.
+메뉴의 옆면/윗면/아랫면 선택으로 어느 면에 붙일지 고른다. - 바닥: 레이어의 바닥 스위치(또는 인스펙터 씬 설정)를 켜면 z ≤ 바닥 높이가 도메인 전체 폭에서 강체가 된다(책상·바닥 반사). 측정 원호는 바닥 위까지만 잡히도록 최대 각도가 자동으로 줄어든다.
- 드라이버는 진동판 면(선)이고 "드라이버 몸체"로 바스켓·마그넷 형태의 강체(역할
driver)를 뒤에 붙일 수 있다. 역할 "기타"로 임의 부품을 그려 실제 형상에 가깝게 만들 수 있다. 최적화에서 드라이버 높이를 움직이면 몸체도 따라간다. - SVG 내보내기/가져오기(
src/engine/svg.ts): 1 unit = 1 mm, x = r, y = −z. Figma/Illustrator 에서 그린 단면을 곡선 그대로 불러온다 (path M/L/H/V/C/S/Q/Z, rect, polygon, transform). 역할은 data-role 또는 채움색으로 복원. - 드라이버는 끝점 드래그로 크기, 선 드래그로 위치. 측정 원호는 위쪽 핸들로 반경, 중심 핸들로 높이.
- 휠로 확대/축소, 빈 곳 드래그로 영역 선택, 가운데 버튼 드래그로 이동. Ctrl+Z / Ctrl+Y 실행취소·다시실행.
- 색: 하우징 회색, 리플렉터 주황, 슬롯 청록 점선, 패브릭 황토 빗금, 드라이버 분홍(화살표 = 방사 방향), 측정 원호 초록 점선, 바깥 띠 = 흡수층.
- 형상 충돌(진동판 앞이 고체 안, 측정 원호가 고체 통과, 자기교차·퇴화 폴리곤)은 캔버스의 빨간 외곽선·느낌표 마커와
레이어 행의 빨간 테두리로 표시되고 실행이 잠긴다.
src/engine/geometry.ts,scripts/test-geometry.ts. - 압력장은 벡터 형상 아래에 보간해 그리므로 격자 계단이 보이지 않는다. "격자 마스크"를 켜면 솔버가 실제로 보는 셀을 겹쳐 볼 수 있다.
레일의 "설계안" 활동(src/ui/VariantPanel.tsx). 편집 중인 씬을 안(案)으로 저장(Ctrl+S, 브라우저 저장소에 유지)하고 "모두 평가"로
인스펙터의 해석 설정(dx·시간·백엔드) 그대로 차례로 계산해 목적함수 점수로 순위를 매긴다. 체크한 안들의 polar(공통 기준)와
측면 응답을 결과 도크에 겹쳐 보고, 카드 클릭으로 캔버스 미리보기, "편집"으로 편집기에 복원, "갱신"으로 현재 편집 형상을 덮어쓴다.
설정이 바뀌면 "재평가 필요"가 표시된다.
기본 모델은 현재 형상이다. 레일의 "설계 탐색" 활동(src/ui/OptimizePanel.tsx)에 들어가면 편집기의 씬이 기준으로 잡히고, 리플렉터의 앵커마다 z(선택적으로 r),
슬롯의 높이 이동·배율, 드라이버 높이가 설계변수가 된다(기준값 = 현재 좌표, 범위 ±8 mm). 베지어 핸들은 앵커와 함께
움직이므로 곡선 형상이 유지된다. 탐색은 기본 "국소"(기준에서 가우시안 변형, 폭 = 범위의 25 %)이고 "전역"(라틴 하이퍼큐브)을
고를 수 있다. "적용"한 후보는 다시 기준이 되므로 편집 → 최적화 → 적용 → 편집을 반복할 수 있다.
그 외 분석 모델: 원뿔 파라미터(꼭짓점 높이·바닥 반경)와 자유 프로파일(반경 0, 8, 16, 24, 33.5 mm 의 높이 5개).
엔진: src/engine/optimize.ts.
- 파라메트릭 모델(측면 방사형): 리플렉터 꼭짓점 높이, 바닥 반경, 슬롯 하단 높이, 슬롯 높이, 드라이버 높이. 변수마다 사용 여부와 최소/최대/기준값을 입력한다.
- 목적함수(높을수록 좋음) = w₁·측면 레벨 − w₂·수평 ±30° 편차 − w₃·측면 응답 편차 − w₄·상하 누설. 모두 지정 대역(기본 1~8 kHz) 평균. 가중치와 대역, 측면 각도를 바꿀 수 있다.
- 탐색: 기준 형상 평가 → 라틴 하이퍼큐브 탐색(nSamples) → 상위 topK 를 부모로 한 국소 정련(nRefine). 시드 기반 PRNG(mulberry32)라 같은 시드·설정이면 결과가 동일하다.
- 후보 목록에서 체크한 후보들의 polar(공통 기준)와 측면 응답을 결과 도크에 겹쳐 비교하고, 카드를 누르면 캔버스에 미리보기가 뜨며, "설계에 적용"으로 후보 형상을 편집기의 씬으로 보낸다. 탐색은 거친 dx(기본 2 mm)로 순위를 매기므로 최종 후보는 dx 1 mm 로 재확인한다.
scripts/test-optimize.ts: 목적함수 sanity, LHS 층화, 재현성(같은 시드 → 동일 결과), 단순 기준 형상(거의 평평한 리플렉터) 대비 개선 예제.
npm test— 씬 검증·수치 설정 경고 조건 단위 테스트.npm run validate— 무한 배플 피스톤 이론 비교(dx 1 mm 기준 0.75 dB 이내) + 격자 수렴 검사(dx 2 → 1.5 → 1 mm). 기준 미달 시 exit code 1.npm run check— 타입 검사 + 테스트 + 검증 일괄 실행.- UI는 실행 전에 씬 구조(음수·0 치수, 영역 밖 드라이버·측정점), 파장당 셀 수, 측정 원호와 흡수층 거리, fMin 대비 필요한 해석 시간, Courant 수를 검사한다. 오류가 있으면 실행 버튼이 잠긴다.
- 해석 시간으로 신뢰할 수 없는 저주파(첫 도달 이후 3주기 미만)는 결과에서 잘라낸다.
- 실행 후 종료 시점 신호가 피크 대비 -30 dB 위에 남아 있으면 감쇠 부족 경고를 낸다.
- 2D 축대칭이므로 모든 측면 홀은 원주 전체에 열린 환형 슬롯으로 해석된다. 이산 홀, 슬롯 개수, 비대칭 구조, 원주 방향 간섭은 계산하지 못한다 (3D sector 해석이 필요).
- 절대 SPL이 아니라 정규화된 피스톤 소스 기준 상대 dB. Thiele–Small, 진동판 분할진동, 구조–음향 연성은 없다. 드라이버는 지정 속도의 hard piston source.
- 흡수 경계는 PML이 아닌 sponge 층. 파장이 흡수층 두께보다 훨씬 긴 저주파(수백 Hz 이하)에서는 잔류 반사가 있다.
- 패브릭은 흐름저항(σ, Pa·s/m²) 셀로 근사한다. 다공성 매질의 주파수 의존 임피던스는 아니다.
- 좁은 틈의 열점성 손실은 미포함 (틈 폭이 1 mm 이하로 내려가면 무시할 수 없다).
- 형상은 격자에 계단식으로 올라간다. 곡면 리플렉터는 dx 를 줄여야 정확해진다 (수렴 검사 참고).
- STEP/STL/CAD 입력, 파라미터 기반 리플렉터 최적화, 전용 형상 편집 UI는 아직 없다.