Acouvero
下载
TECHNICAL DOC · v0.5.0

房间声学,
从测量到
方案的全栈。

Acouvero 是一款运行在 iPhone / iPad 上的房间声学分析与吸音方案生成工具。本文面向对声学工程或客户端实现感兴趣的读者,覆盖核心算法、几何系统、测量方法、推荐系统与工程实现要点。

倍频带
6段
房型
4类几何
多阶反射
1–3阶
§ 01

应用概述

输入:用户手动录入房间尺寸 / 形状 / 装修材质、音箱与听音位位置,或用 AR 卷尺量房(无需 LiDAR)/ LiDAR(RoomPlan)扫描得到房间几何。

输出
  • 早期反射点定位
  • RT60(实测 + 模拟)与 EDT / C50 / C80 / D50(模拟 RIR 派生)全套声学指标
  • 房间模态频率列表
  • 吸音板布置方案(位置、数量、产品 SKU)
  • 3D 可视化 + 反射能量热力图
  • 安装手册级 PDF 导出
  • ESS 扫频 / 拍手脉冲实测(内置麦克风或 USB 测量麦)
  • USB 测量麦校准与 SPL 标定、实时频谱 RTA
  • 频响叠加与多位置平均、REW 互导、PEQ / 低音炮对齐、AI 声学助手

支持矩形、L 形、U 形与任意简单多边形房型,一阶反射与面积/包含判定按真实多边形计算;2/3 阶反射与房间模态按外接矩形近似(见 §9)。

§ 02

声学模型

通俗版 · PLAIN VERSION 这些概念各有面向普通读者的详解:什么是混响时间(RT60)、房间模态与驻波、镜像声源法。

2.1 Sabine RT60

经典 Sabine 公式:

SABINE · RT60RT60=0.161⋅V∑iSiαi RT_{60} = \frac{0.161 \cdot V}{\sum_i S_i \alpha_i}
VV
房间体积(m³),多边形房型走 Shoelace 面积 × 高度,扣除柱 / 梁等障碍物体积。
∑iSiαi\sum_i S_i \alpha_i
各面表面积乘吸声系数。系数采用 6 段倍频带(125 / 250 / 500 / 1k / 2k / 4k Hz)。
0.1610.161
= 24·ln(10)/c,其中 c = 343 m/s(20°C)。

应用层提供 4 个装修材质预设(硬质空房 / 普通硬装 / 软装家具 / 已有处理),每个预设给出按频段的吸声系数曲线;顶部单值 RT60 估算与板数预算用中高频平均吸声系数,6 段 Sabine 曲线用于分频段显示。目标 RT60 也按 6 段曲线给(不是单值),覆盖低频允许更长尾混响的 EBU Tech 3276 / THX 等行业标准。

2.2 图像源法(Image Source Method, ISM)

第一次反射点用镜像法:把声源关于墙面镜像,求“镜像源 → 听音位”的线段与墙面的交点即反射点。

  • 矩形房间:直接对 6 面平面(4 墙 + 地 + 顶)做镜像,闭式解。
  • 非矩形房间(PolygonReflectionCalculator):把 RoomPolygon.walls() 拆出的每一段墙做镜像 + 段内参数 s ∈ [0, 1] 校验(地板/天花反射另要求反射点 XY 在多边形内);一阶路径还做 2D 遮挡检测——声源→反射点→听音位连线穿过其它墙段即丢弃。

多阶反射(1–3 阶)由 MultiOrderReflectionCalculator 按 pyroomacoustics 的递归思路实现:

  1. 枚举所有“墙面序列” [s₁, …, sₙ],相邻不同墙
  2. 镜像源迭代:S₀ = source,Sₖ = mirror(Sₖ₋₁, sₖ)
  3. 从 listener 反向 trace:从 Sₙ 拉线到 listener,与 sₙ 的交点是 Pₙ;再从 Sₙ₋₁ 拉到 Pₙ,与 sₙ₋₁ 的交点是 Pₙ₋₁;一路回推
  4. 每个交点必须在墙面有效范围内 + 段内参数 t ∈ (0, 1)
近似 · APPROXIMATION 多阶在非矩形房间用外接矩形近似(凹角附近会有“幽灵反射”),在分析层会过滤掉反射点距任一真实墙段 > 0.3 m 的路径,剩下的合法路径才进入 flutter / slapback 检测。

2.3 路径能量

宽带能量按反射次数 + 距离衰减:

PATH ENERGYErel=(1−αˉ)N⋅ddirect2dtotal2 E_{rel} = (1 - \bar{\alpha})^N \cdot \frac{d_{direct}^2}{d_{total}^2}
  • α 限制在 [0, 0.99],避免 α = 1 时出现 log(0) 或 pow(负, N) = NaN 污染整条路径
  • 距离衰减按球面发散 1/r²
  • 转 dB 用 10·log₁₀(能量域)

分频段能量按 6 段倍频带分别算(每段用 finishProfile.absorptionByBand 的频段系数)。

2.4 RT60 估算(实测)

ImpulseResponseEstimator:

  • 匹配滤波:录到的扫频先做 ESS 反向滤波(Farina 法)压成单脉冲;处理增益 ≈ 10·log₁₀(T·B),以 3 s、180 Hz–4 kHz 手机粗测档计约 +41 dB 等效 SNR
  • rmsEnvelope:滑窗 RMS 包络
  • Schroeder 反向积分:E_back(t) = ∫ₜ^∞ s²(τ) dτ,做 10·log₁₀ 归一化得 EDC 曲线
  • 斜率线性回归:按 SNR 优先取 T30 [−5, −35 dB],不够回退到 T20 [−5, −25] 或 T10 [−5, −15]
  • RT₆₀ = −60 / slope

倍频带 RT60:在匹配滤波后的样本上,按实际扫频范围选取的 ISO 倍频带中心频率 + Q = √2 做带通滤波,对每段独立跑 Schroeder。

2.5 RIR 模拟

SimulatedRIRGenerator 把多阶反射路径转成离散脉冲事件,写到 8 kHz × 0.5 s PCM 缓冲:

SimulatedRIRGeneratorpseudocode
for path in reflectionPaths:
    t   = path.totalDistance / speedOfSound
    amp = 10^(path.relativeEnergyDB / 20)
    impulse[round(t * sampleRate)] += amp

加上直达声脉冲,再做 Schroeder 反向积分提取 EDT / RT60 / C50 / C80 / D50 五个指标。

Before / After 对比 每条反射路径按其经过的墙累计板数衰减,生成“装板后”模拟 RIR。UI 可以 A/B 切换看 EDT / C50 改善量,再用 AVAudio 卷积干信号实时听处理前后的差异。

2.6 房间模态

矩形房间模态频率:

ROOM MODESfnx,ny,nz=c2(nxLx)2+(nyLy)2+(nzLz)2 f_{n_x, n_y, n_z} = \frac{c}{2} \sqrt{\left(\frac{n_x}{L_x}\right)^2 + \left(\frac{n_y}{L_y}\right)^2 + \left(\frac{n_z}{L_z}\right)^2}

按 nₓ, n_y, n_z 中非零的个数分类:1 个 = 轴向(axial),2 个 = 切向(tangential),3 个 = 斜向(oblique)。

枚举范围:每轴 n ≤ 4 且频率 ≤ 300 Hz。非矩形房型用外接矩形近似估算(精确模态需 FEM 求解),在 UI 上明示。

§ 03

几何系统

3.1 房型支持

  • 矩形 — width × length × height
  • L 形 — 在指定角去掉一个 nw × nl 凹槽
  • U 形 — 在指定墙中央去掉一个 nw × nl 凹槽
  • 自定义 — 任意简单多边形(≥ 3 顶点,≤ 24 顶点)

所有非矩形由 RoomPolygon.from(shape:, bboxWidth:, bboxLength:) 转成 CCW 顶点列表。一阶反射、面积/周长与包含判定直接用这套顶点;非法自定义多边形(顶点 < 3 / > 24、自相交、面积近零)会静默降级为外接矩形。

3.2 多边形几何工具

  • 面积 — Shoelace 公式
  • 周长 — 直接累加边长
  • contains(x, y) — Ray-casting + 边界 epsilon 兜底(角点处避免误报)
  • clamped(point) — 矩形房型走 [0, w] × [0, l] 快速路径;非矩形走 polygon.boundingBox 的真实 [minₓ, maxₓ] × [min_y, max_y],然后 polygon.contains 测,不在多边形内时二分拉向 bbox 中心
  • walls() — 把多边形拆成按 inward normal 分类的墙段(自动归到 leftWall / rightWall / frontWall / backWall),方便复用矩形版面板推荐器
  • PolygonValidator.isSimple — 校验非自相交简单多边形

3.3 RoomPlan 扫描

通过 RoomCaptureSession(iOS 16+ API;App 内扫描功能整体门槛为 iOS 17)调起扫描,CapturedRoomMapper 把扫描结果映射为 ScannedRoom(包含 wallSegments + openings + furniture)。坐标系映射:

ARKit (x, y, z) → y 是垂直 App (x, y, z) → z 是垂直 墙端点 (z=0 地面) App.x = ARKit.x App.y = ARKit.z App.z = 0 门窗 / 家具中心  App.x = ARKit.x App.y = ARKit.z App.z = ARKit.y

扫描结果按墙段数判定:恰好 4 段墙直接按矩形处理,其余走 RectangularRoomSimplifier.polygonShapeFromScan 把 wallSegments 链成 polygon 顶点。RoomPlan 端点典型误差 3–8 cm,12 段闭环可累积 5 cm,所以闭环 epsilon 用 12 cm。链不通则降级到外接矩形 + 提示用户重新扫描。

3.4 AR 卷尺量房

无 LiDAR 的机型走 ARTapeMeasureView(RealityKit ARView 世界跟踪):准星对准墙面,两次点击记录起点 / 终点,按 宽 → 长 → 高 分步量房,最后确认生成矩形房间;含相机权限引导与追踪失败提示。

3.5 自由顶点编辑器

FreeVertexEditorView 让用户在 SwiftUI Canvas 上拖动顶点:

  • 长按删除(顶点数 > 3 时,删后仍 ≥ 3)
  • 拖动逐帧做 isSimple 校验,自相交的新位置不生效(顶点原地停住);空白处点按可在最近边插入顶点,另有逐顶点数值输入与「重置为外接矩形」
  • 0.05 m 网格吸附
  • bbox 外预留 max(0.5, bbox × 0.2) 米拖动余量,让用户能把顶点拖出当前 bbox(父视图自动撑大 room.width / length)
§ 04

听音区与多 listener

AcousticConfiguration.listeners 支持 1..N 个听音位(0 听音位时自动合成默认主听位并告警;0 音箱时走 §5.2 的通用模板)。声学分析把每个 listener 都跑一次镜像法,反射点合并到一个数组(primary listener 的点排在前面)。面板推荐器按每面墙的反射点 count 加权(cap = max(6, speakerCount × listenerCount)),多座位共用一面墙自然把该墙推向预算上限。

UI 视觉
  • 3D 视图中 secondary listener 节点用 opacity 0.45 + scale 0.75
  • 顶视图(RoomPlanView)中 primary 反射点全色 r=5,secondary 用 0.45 透明 r=3
  • 反射点列表(RecommendationView)只列 primary 的,副听位用脚注 “+ N 处反射已计入推荐方案”

多阶反射 / RIR / 热力图仍按 primary listener 一次算(per-listener O(speakers × surfaces³) 计算量太重,且 RIR 是单点指标)。

§ 05

推荐系统

PanelPlacementRecommender 输出 [PanelRecommendation],每条包含:位置(左墙 / 右墙 / 顶 / 前墙 / 后墙 / 角)、数量、优先级(必装 / 强推 / 推荐 / 可选)、effectivenessMultiplier、targetReflectionPointId。

5.1 比例分配(最大余数法)

老版本用贪心 add():左墙吃完 → 右墙 0;budget 紧时天花 / 前 / 后墙也会被饿死。新版用 largest-remainder method:

  • 算每面 wall 的 raw desired(反射点数 + 房间深浅 + 用例)
  • floor(raw × budget / total) 作为初始分配
  • raw &gt; 0 的墙保证至少 1 块;仅当预算小于有需求的墙面数时,按优先级从低到高归零
  • 总和 &gt; budget 时按 fractional remainder 从最小开始削
  • 左右墙对称 pass:raw[0] == raw[1] 时强制 alloc[0] == alloc[1]
  • 剩余 leftover 按 frac 最大重分

5.2 用例差异化模板

无音箱场景下走 use-case-specific 模板:

  • 会议室:天花板 35% + 后墙 20% + 两侧墙各 12%
  • 播客:麦克风正前 25% + 两侧各 18% + 顶 20%
  • 录音棚:四面对称压死 + 预算内尽量凑满 4 个墙角低频陷阱(真正绕过预算的强制 4 角只在 §5.3 低频模态密集路径)
  • 通用听音:对称基础铺底 + 提示加音箱

5.3 物理刚需绕过预算

墙角低频陷阱在 80–150 Hz 模态密集时强制 4 根,绕过 totalPanel 限制。理由:墙角声压最大,低频陷阱效率比墙面高 ~1.5×,是物理刚需而不是预算项。

5.4 听音位近端加权

后处理把听音位 1.5 m 半径内的墙面推荐标成 .nearListener,effectivenessMultiplier ×1.15,title / reason 提示用户这是“贴身吸声敏感区”。

§ 06

测量

通俗版 · PLAIN VERSION 这三个话题各有面向普通读者的详解:正弦扫频测量、拍手测试、测量麦克风怎么选。

6.1 ESS 扫频

ESS 对数扫频(Farina 法),四档预设 + 自定义,扫频时长 3 / 6 / 12 秒可选:

  • 手机粗测:内置输出 180 Hz–4 kHz;外置输出 75 Hz–4 kHz(唯一支持内置扬声器的档位)
  • 低频 / 低音炮:15–300 Hz(需外置输出)
  • 全频:20 Hz–20 kHz(需外置输出)
  • 自定义:10 Hz–20 kHz 范围内任选起止频率,至少覆盖一个倍频程(需外置输出)
  • 反向滤波(makeInverseSweep)= 时间反转 + 幅度补偿(+6 dB/倍频程,随频率上升,抵消 ESS 的粉噪频谱)
  • 录音用 AVAudioRecorder 写无损 Linear PCM(16-bit 单声道 .caf,约 96 dB 动态范围,感知压缩不适合脉冲测量;采样率跟随音频会话——内置麦 44.1 kHz,USB 测量麦按其原生 48 kHz)
  • 读回 → 匹配滤波 → analyzeImpulse

播放信号、逆扫频与分析共用同一配置,最高频率跟随实际采样率限制;低频 / 全频 / 自定义档在没有外置输出时阻止启动。RT60 倍频带按实际扫频范围选取;预设的频率范围是激励配置,实际可信范围仍受音响、麦克风与测量质量限制。

采样率对齐 扫频 WAV、逆扫频与录音全部按音频会话的实际采样率生成(makeInverseSweep(sampleRate:) 已参数化)——匹配滤波在内置麦 44.1 kHz 与 USB 测量麦 48 kHz 下都始终生效。

6.2 拍手脉冲

不放任何声音,用户在 1 秒窗口内大力拍一次手,共录 4.5 s(约 3.5 s 尾音)。直接走 analyzeImpulse(不需要匹配滤波,因为脉冲本身就是窄脉冲)。覆盖 125 Hz 倍频带(手机粗测档从 180 Hz 起,覆盖不到 125)。

6.3 实测 vs 模拟对比

MeasuredVsSimulatedCard 拉项目最近一次实测 RT60,跟当前几何模拟 RT60 并排显示偏差:

< 15%模型与实测吻合
15–30%有差异(可能由未建模家具 / 装修材料导致)
> 30%差异较大,建议核对房间几何 / 材料

6.4 环境噪声 & 校准

AmbientNoiseEstimator 录 3 s 静默(掐头去尾各 100 ms)算房间背景噪声:宽带平均 / 峰值 dBFS + 5 档安静度评级(未标定时 dBFS 仅作相对比较;做过 SPL 标定则显示 dB SPL)。近场延迟校准复用同一 ESS 扫频:手机放在距音箱 30 cm 内播放,取录音起点到冲激峰的延迟(含刻意的 250 ms 预滚),建议测 2–3 次——最近 3 次读数散布 < 5 ms 判高置信、< 20 ms 判中置信。延迟值绑定当前「录音输入 + 播放路由」,任一端变化即自动作废;远场测量显示自动扣除后的传播延迟。

6.5 时间参考与测量质量

  • 声学时间参考:扫频前置一个 chirp 作为时间锚点,每次测量重新检测;检出失败时回退并明确标注相位可信度,不能据此宣称跨测量的绝对对齐。
  • 时钟漂移:估算播放与录音通路的时钟差,满足条件时校正。
  • 电气回环参考:多输入 USB 接口可用第二通道做 loopback 参考;不满足条件时回退声学参考。Mac 播放助手路径不使用本机电气回环。
  • 质量字段:每条记录保存可获得的 SNR、噪声底、剪波状态、IR 时间偏移、实际输入与采样率;无法确定的字段保留为空,不编造。
  • 剪波处理:扫频检出剪波即作废并提示重测;拍手记录标记剪波并提示。
  • 模拟与实测对照:把房间最近一次测量与几何模拟 RT60 并排比较,辅助评估模型吻合度(阈值见 6.3)。

6.6 USB 测量麦与输出路由

测量页的输入选择器列出内置麦与 class-compliant USB 输入(如 miniDSP UMIK-1 / UMIK-2);热插拔监听 routeChangeNotification,外置麦消失自动退回内置麦。录音与扫频采样率跟随会话实际值(UMIK-1 = 48 kHz)。支持导入 REW / UMIK 风格 .txt 频率校准文件(解析 Sens Factor 与序列号元数据,对数频率域插值;房间测量建议用 90° 文件),校准按输入端口 UID 绑定——切换到不匹配的输入时不套用原校准。

一次性 SPL 参考标定:把声级校准器(默认 94 dB @ 1 kHz)套在麦克风上,App 采 3 s 电平求 dBFS → SPL 偏移;只有输入匹配且存在 SPL 标定时才显示 dB SPL,未标定保持 dBFS。测量时校准快照:新扫频 / 拍手记录保存当时的校准曲线、名称、序列号、Sens Factor、SPL 偏移与输入 UID,此后替换、清空或重新绑定校准都不会改变这些记录的读数;测量详情、IR 窗后频响预览、频响文本导出与 PDF 使用同一保存快照。校准本身按输入端口 UID 持久化到 ~/Library/Application Support/mic_calibration.json。

播放侧走系统路由选择器(AVRoutePickerView 封装,放在扫频 / 近场校准卡上),session 放开 AirPlay / 蓝牙 A2DP / HFP,可经外置音响播放测试音;无外置输出时强制扬声器。录音输入总是显式钉住用户所选(USB 麦或内置麦),防止带麦蓝牙设备在播放时抢走输入、污染测量。Mac 播放助手:通过 Bonjour 发现局域网内的 AcouveroMacSpeaker,先把扫频 WAV 传到 Mac 再发送播放命令,iPhone 负责录音——适用于不能直接承接测量会话音频的 Mac 输出路径(该路径不使用本机电气回环)。

6.7 REW 与文件互操作

  • 频响文本导入 / 导出:兼容常见分隔符、注释行、科学计数法与小数格式,导入时校验频率轴;文件没有相位列时不生成相位数据。
  • 校准口径导出:存在有效 SPL 标定快照时导出 dB SPL,否则导出 dBFS,文件头如实标注单位。
  • IR 音频导入:支持 WAV / AIFF 脉冲响应;多声道文件必须显式选择所用通道。
  • 离线扫频分析:导出激励信号文件供外部播放,导入录音后须明确起止频率与时长再解卷积——不猜测扫频参数。
  • 音频分享导出:可把可用的 IR 或原始录音以 WAV 分享出去。
  • 导入结果可归档并进入适用的图表、叠加与分析流程;是否能参与测量组由数据类型与可信口径决定。目前不解析 REW .mdat 工程文件。
§ 07

测量图表与分析

测量详情页按记录实际具备的数据展示图表,不补造缺失曲线;图表支持深浅色、动态字体与无障碍摘要。

  • RT60:倍频段柱状图、目标线与状态色。
  • Schroeder 衰减:EDC 曲线与 T20 拟合区间。
  • 频率响应:对数频率轴、倍频程平滑、光标读数;校准快照有效时以 dB SPL 显示。
  • 脉冲响应:波形、时间零点与峰值标记;幅度为相对峰值。
  • 相位:wrapped / unwrapped 视图、极性反转、时间零点微调与参考可信度提示。
  • 群延迟:有效频段群延迟,可选最小相位 / 过剩相位分析。
  • IR 窗函数:peak 或 t=0 参考、左右窗宽,矩形 / Hann / Tukey / Blackman;原始与窗后频响并排预览,窗处理与相位微调只作用于预览,不改写原始测量。
  • 频谱图:IR 时频衰减,时间范围与动态范围可调。
  • 瀑布图与 RT60 Decay:低频衰减可视化,窗长 / 时间 / 动态范围可调;质量不足的拟合不显示。
  • 实时频谱 RTA:1/1–1/24 倍频程显示,A / C / Z 计权,即时 / Fast / Slow 响应,峰值保持与清除,综合声级、峰值电平与主要频率。
  • RTA 使用匹配输入的校准,未完成 SPL 标定时标为 dBFS;与正式测量互斥(进入时释放测量页电平监听,关闭后恢复),停止或切换输入后旧回调不覆盖新状态。
数据门槛 · DATA GATING 相位、群延迟与窗函数需要合格的扫频与 IR 数据;时间参考不足时明确提示为相对相位,不能宣称可靠的跨测量绝对对齐。RTA 目前尚无 SPL Logger 长期记录功能。
§ 08

测量历史、多位置平均与叠加

  • V2 归档:测量保存元数据、可用的原始录音 / IR sidecar 与分析数据;旧格式记录继续只读兼容,没有原始数据的旧记录不补造。
  • 历史管理:按房间查看、删除测量,进入详情或选择记录做后续分析。
  • before / after 对比:任选两条记录,对比整体与倍频段 RT60、频响叠加与有效频段差异。
  • 2–6 条频响叠加:1/3–1/48 oct 平滑、逐条独立显隐、全频 / 低频等区间预设;电平可不对齐、中频归零或对齐首条,图例显示偏移;原始数据保持不变,不可叠加的记录给出原因。
  • 测量组:记录位置标签、权重与 before / after 阶段;可从历史建组、加入组,或测量新位置后直接归组。
  • 多位置平均:dB 算术平均、RMS 功率平均,以及具备可靠时间参考与复谱时的 vector 复数平均;显示平均线、成员曲线与逐频 min/max 空间范围。
  • 组对比:对比两组的平均频响、空间范围与 RT60 均值,给出空间一致性结论。
边界 · BOUNDARIES 分组平均与对比当前使用相对 dB;跨采样率 vector 平均暂不支持。频响叠加目前使用区间预设,尚无手势缩放、相位 / 瀑布 / 衰减叠加或叠加图 PDF 导出。
§ 09

PEQ 与低音炮对齐

通俗版 · PLAIN VERSION 这两个话题各有面向普通读者的详解:参数 EQ 与房间校正、低音炮摆位与对齐。

9.1 PEQ 目标匹配

  • 参数化目标曲线:目标电平、低频上扬、高频下倾与匹配频段。
  • 滤波器约束:滤波器数量、最大提升 / 衰减与 Q 范围。
  • 预测与理由:同图显示测量、目标、滤波器响应与预测结果曲线,给出改善指标与逐条滤波器推荐理由。
  • 深陷波排除:声学相消造成的深陷波区域自动排除,避免用大幅提升去填。
  • 导出:Generic 文本、Equalizer APO、miniDSP 系数与 CamillaDSP YAML——只提供计算与设置导出,不直接写入设备。

目前尚无手动滤波器编辑器、目标预设库或 EQ 结果归档。

9.2 两路与多低音炮对齐

  • 两路对齐:选择参考音箱与可调低音炮两条测量,预测复数求和,计算延迟、增益与极性;显示对齐前后的求和曲线。
  • 多炮多座位:1–4 个低音炮,按座位 × 声源选择独立测量;支持全座位目标、最差座位限制,也可显式仅优化主座位。
  • 结果与分享:逐炮设置、逐座位改善、平均及最差指标,支持设置文本分享。
  • 数据门控:缺少扫频配置、可靠时间参考或 IR 的记录会列出不可用原因,而不是静默排除。

多座位结果目前为数值表,尚无逐座位求和曲线叠加;对齐是预测,需实际应用设置后复测验证;跨采样率声源混用仍待验证。

§ 10

AI 声学助手

测量历史工具栏提供聊天入口,使用用户自己的 Anthropic API Key(保存在本机 Keychain);助手把请求所需的对话与工具数据发送给 Anthropic,API 费用由用户自己的账户承担。

  • 对话界面:流式回复、工具执行状态、停止与清空、用量 / 费用估算。
  • 测量数据读取:列出记录、摘要与局部频响、测量对比。
  • 计算工具:调用与手动界面完全相同的 PEQ 推荐与低音炮对齐算法。
  • 房间与布局评估:列出房间、读取音箱 / 听音位与模态信息,在项目副本上预测移动既有设备或调整装修吸声概况后的变化——不改写已保存项目。
  • 经确认发起测量:AI 提出用途与可选房间,用户确认后才启动扫频;拒绝或停止即取消请求。
  • 共享测量设置:AI 与手动测量复用同一工作区,继承输入、Mac 播放助手、扫频范围 / 时长、延迟与回环设置;聊天页显示实时电平 / 进度,支持取消,结束后恢复原房间与测量组上下文。
  • 会话恢复:保存并恢复一条当前会话,恢复时标记上次中断的工具执行;清空会话同时清除历史与用量。
边界 · BOUNDARIES 目前尚无多会话列表或端侧模型兜底;布局工具不支持增删设备、指定吸声板改动或实测校准预测。真实 API Key 链路与真机音频闭环仍待验收。
§ 11

可视化与输出

11.1 3D 视图

Room3DController 用 SceneKit 渲染:墙面 / 地面 / 顶面 / 音箱节点(薄板 cabinet + accent tick + channel pill)/ 听音位(FE glyph + drop stem)/ 障碍物(半透明 SCNBox)/ 推荐面板(按 wall 分布的吸音板 mockup)/ 多阶反射路径线段 / 反射能量热力图叠加。

设计 · TECHNICAL DRAWING 设计上走“技术图风格”(hairline 边线、constant lighting、无 PBR),跟传统照片级 3D 渲染区分。

11.2 反射能量热力图

ReflectionEnergyMapGenerator 把每条多阶反射路径的能量按经过的墙累加到该墙的 uCells × vCells 网格(默认 12×6)。每面墙一张能量图,3D 视图上叠加成能量色层(蓝 → 青 → 绿 → 黄 → 红)。

EnergyHeatmapRenderer 把网格转 UIImage:16 px/格 block 渲染(cell 间不插值,便于辨认网格边界;上墙平滑靠 SceneKit 纹理双线性过滤)+ 自绘 5 段色带(蓝→青→绿→黄→红)+ alpha 按能量在固定 −30…0 dB 标尺上的位置从 0.20 到 0.85 线性映射(−∞ 全透明)。

11.3 RIR 卷积预览

RIRPreviewPlayer 用 AVAudioEngine + AVAudioPlayerNode 把程序合成的干信号(拨弦 / 击掌 / 类元音语音,无内置采样)卷积模拟 RIR 后播放,让用户能听到“如果不装吸音板 / 装了之后”房间听感的差异。

时域卷积 RIRConvolver.convolve(dry:rir:) 直接做 O(N × M)(N = dry samples,M = RIR samples)。归一化按峰值 0.9 防止 clip。

11.4 PDF 安装手册

ReportExporter 用 UIGraphicsPDFRenderer 渲染 A4 PDF(595 × 842 pt):

  • 房间概览 + 3D 快照
  • 6 段 RT60 条形图:Sabine 估算 vs 目标,具备实测数据时叠加实测值
  • 反射点表 + 模态表 + 风险摘要
  • 推荐面板表(购物清单 BOM 在 App 内展示,不进 PDF)
  • 具备测量数据时加入 RT60 / EDC / 频响 / 频谱 / 瀑布 / 相位图表与多位置平均摘要;频响单位使用测量时保存的校准快照(dB SPL 或 dBFS 如实标注)
  • Geist 字体 + PingFangSC fallback(CoreText cascadeList,避免 CJK 渲染成 □□□)

11.5 项目持久化

ProjectStore(actor)写 ~/Library/Application Support/Acouvero/projects.json:[RoomProject],每条含完整 Room + speakers + listeners + recommendations + panelCountOverrides 等。首次启动自动从旧目录 FindEcho/ 迁移(FindEcho 是产品改名前的内部代号,代码符号仍沿用旧名)。

MeasurementStore(actor)写 ~/Library/Application Support/Acouvero/measurements.json:[MeasurementResult],按 roomId 关联到 project。

两者都有元素级 decode 恢复(Throwable<T> 包装)— 单条记录损坏不会让整个列表加载失败。

MicCalibrationStore 写 ~/Library/Application Support/mic_calibration.json(根目录,无子目录):REW 校准曲线 + SPL 偏移,按输入端口 UID 绑定,换输入需重新导入 / 标定。

§ 12

工程实现要点

12.1 SwiftUI + @Observable

ViewModel(FindEchoViewModel)用 Swift 5.9 @Observable macro,状态字段直接观测,没有 Combine。AcousticAnalysis 计算结果按 AcousticConfiguration Equatable 比较做缓存:

FindEchoViewModel.analysisswift
var analysis: AcousticAnalysis {
    let cfg = configuration
    if let cached = cachedAnalysis, cachedConfiguration == cfg {
        return cached
    }
    let result = analysisService.analyze(cfg)
    cachedConfiguration = cfg
    cachedAnalysis = result
    return result
}

12.2 Actor 隔离

ProjectStore 与 MeasurementStore 是 actor(IO / 异步逻辑天然串行化),RoomPlanService 是 @MainActor 类。UI 调用方用 async / await 拿结果,主线程不会被磁盘 IO 阻塞。

12.3 AVAudio 生命周期

AudioSessionManager 集中管理 session 类别(.playback for RIR preview,.playAndRecord for 测量)。打断保护两条路径都有:测量侧 AudioMeasurementService 内置 InterruptionMonitor 监听 AVAudioSession.interruptionNotification,扫频 / 拍手 / 环境噪音任一路被电话 / Siri 打断即作废结果并报错;RIR 预览侧 RIRPreviewPlayer 同样监听打断,自动停 player node 并清 isPlaying。测量中途音频路由变化也会作废本次测量。

12.4 Task 取消

播放卷积是后台任务,用户连点多个 button 时 pendingPlayTask?.cancel() + Task.isCancelled 双重 check 防止乱序回 MainActor 写错 state。

12.5 测试覆盖

AllShapesAndUseCasesTests 用 Swift Testing 框架跑全场景矩阵:每种房型 × 每种用例(单听音位;音箱按用例取立体声对或单只居中),验证:

  • analysis.reflectionPaths.count >= 1
  • analysis.warnings 包含对非矩形房型的近似说明
  • 推荐板数总计非负(totalPanelCount ≥ 0;无预算相符断言)
  • 自相交自定义多边形安全回退(不 crash,降级为矩形)
  • 顶点 &lt; 3 等边界情况的回退

12.6 平台与本地化

部署目标 iOS 17.0,iPhone + iPad;零第三方依赖(无 SPM / CocoaPods 包),只用系统框架(SwiftUI / SceneKit / ARKit / RoomPlan / AVFoundation / Accelerate)。本地化用 .xcstrings 字符串目录:源语言中文,另有 English / Français / Deutsch / Español / Português (Brasil) 共 6 种,App 内可跟随系统或手动切换。

§ 13

已知限制

  1. 多阶反射在非矩形房间用外接矩形近似 — 凹角附近 2-3 阶 flutter / slapback 风险评估可能偏差。1 阶反射点本身按真实多边形几何。
  2. 房间模态在非矩形房间按外接矩形估算 — 精确模态需 FEM 求解。
  3. iPhone 内置麦克风测量 — 非校准麦克风,频率响应 / 灵敏度不平直;可信度始终标为 .low,作为与几何估算的交叉参考用。接 miniDSP UMIK-1 / UMIK-2 等 USB 测量麦并导入其 REW 校准文件时,分带电平按校准曲线修正;再用 94 dB 参考源做一次 SPL 标定后,环境噪声与测量电平可显示为绝对 dB SPL(未标定时只显示 dBFS)。
  4. 单声源 ISM 假设 — 没考虑音箱箱体衍射、号筒指向性等真实音箱特性。
  5. 不模拟低频陷阱 — 80 Hz 以下低频问题在 Sabine 模型外,需要专门的低频处理。
  6. AR 扫描精度 — RoomPlan 端点典型误差 3-8 cm,12 段闭环可累积 5+ cm。墙厚未建模。
  7. 分析口径边界 — 跨采样率的 vector 复数平均暂不支持;多座位对齐结果目前是数值表,尚无逐座位求和曲线叠加;频响叠加图尚未进入 PDF 报告。
  8. 尚未实现的专业工具 — 无 SPL Logger 长期记录、STI 语言清晰度、失真(THD)测量;阻抗 / Thiele-Small 与 REST API 也未实现。
  9. 待真机验收 — AI 声学助手的真实 API 链路(真实 Key 的流式对话 / 确认测量 / 录音归档)与 UMIK 测量麦真机全链路(含 UMIK-2 96 kHz)仍待验收;模拟器通过不代表真机音频闭环。
§ 14

参考

  1. Sabine, W. C. (1922). Collected Papers on Acoustics. Harvard University Press.
  2. Allen, J. B., & Berkley, D. A. (1979). Image method for efficiently simulating small-room acoustics. JASA, 65(4), 943–950.
  3. Schroeder, M. R. (1965). New method of measuring reverberation time. JASA, 37(3), 409–412.
  4. Farina, A. (2000). Simultaneous measurement of impulse response and distortion with a swept-sine technique. Audio Engineering Society Convention 108.
  5. Scheibler, R., Bezzam, E., & Dokmanić, I. (2018). Pyroomacoustics: A Python package for audio room simulation and array processing algorithms. ICASSP 2018.
  6. EBU Tech 3276. Listening conditions for the assessment of sound programme material.
  7. ITU-R BS.1116. Methods for the subjective assessment of small impairments in audio systems.
  8. BB93 — Acoustic design of schools (UK).
  9. THX Pro Cinema Certification requirements.
想要更直白的版本?

《为什么你的房间会改写你听到的音乐》

读 Deep Read