Files
2026-09-29 22:41:29 +08:00

5.9 KiB
Raw Permalink Blame History

离线麦克风增益校准

src/calibrate_from_recordings.py 按 Gain Self-Calibration Procedure for Microphone Arrays.pdf 的公式 (5)--(9) 处理已经录制的 8 路同步音频。由于 实验角度已知,目录名直接提供相对 CH0 的 DOA,不运行 DOA 估计器。

生成模拟数据

需要 pyroomacoustics(项目依赖已经声明)。从项目根目录执行:

uv run python calibration/src/generate_sim_data.py

默认在 calibration/data/sim/ 下生成 degree0、degree15、...、 degree345 共 24 组数据。每个目录包含:

ch0.wav ... ch7.wav       # 24 kHz,同步,单通道 float32 WAV
metadata.json             # 阵列、声源和注入增益信息

degree15 表示声源 DOA 比 CH0 逆时针旋转 15°,不是绝对坐标系中的 15°。 生成器默认注入一组通道增益,用来验证校准结果;可以用 --channel-gain-db 替换。

运行校准

uv run python calibration/src/calibrate_from_recordings.py \
  --data calibration/data/sim \
  --iterations 5 \
  --alpha 0.5 \
  --log calibration/data/calibration.log \
  --output calibration/data/calibration_result.json

日志对每个方向输出拟合斜率、截距、RMSE、相对误差、实测/预测能量和该方向 的候选修正量;最后输出跨所有方向汇总的 8 个线性校正系数和 dB 校正量。

脚本输出的系数是直接乘到音频样本上的补偿系数:

corrected[:, channel] = raw[:, channel] * correction[channel]

校准程序使用几何平均跨方向汇总增益,并在离线迭代中使用 alpha 平滑更新。 校正系数会归一化为平均值 1,因此只改变通道匹配,不改变整体音量。

calibration_result.json 字段说明

calibration_result.json 是校准程序生成的 JSON 结果文件。它保存了每个声源 方向的拟合信息、最终的 8 通道补偿系数以及迭代过程,不是新的音频文件。

顶层字段如下:

字段 类型 含义
directions 数组 使用最终收敛的补偿系数,对每个 degreeXX 方向重新计算的拟合结果。
correction_linear 长度为 8 的数组 最终线性补偿系数,对应 ch0~ch7;运行时直接乘到对应通道音频上。
correction_db 长度为 8 的数组 与 correction_linear 对应的 dB 补偿量,计算方式为 20 * log10(correction_linear)。
iterations 整数 离线迭代次数,由命令行参数 --iterations 指定。
alpha 浮点数 每轮迭代的更新权重,由 --alpha 指定。数值越大,更新越快,也越容易受单次拟合误差影响。
history 数组 每一轮、每一个方向的中间拟合记录,用于检查收敛过程。

correction_linear 和 correction_db

这两个数组是最重要的运行时结果,数组下标就是通道号:

correction_linear[0] / correction_db[0]  -> ch0
correction_linear[1] / correction_db[1]  -> ch1
...
correction_linear[7] / correction_db[7]  -> ch7

例如:

from scipy.io import wavfile
import numpy as np

result = ...  # 读取 calibration_result.json
audio = ...   # shape: [samples, 8]
correction = np.asarray(result["correction_linear"], dtype=float)
corrected_audio = audio * correction[np.newaxis, :]

补偿系数的平均值会被归一化为 1,所以它只负责平衡通道间增益,不负责改变 整体音量。若要查看某个通道需要增加还是衰减,可直接看 correction_db:

  • 正值:该通道需要放大;
  • 负值:该通道需要衰减;
  • 0 dB:该通道接近整体平均水平。

directions 中的字段

directions 数组每一项对应一个方向,例如 degree90:

字段 含义
folder 参与计算的数据目录名,例如 degree90。
angle_deg 相对于 CH0 的声源角度,单位为度;正方向为逆时针。
slope 能量拟合直线的斜率 (a_1)。
intercept 能量拟合直线的截距 (a_0)。
rmse 实测通道能量与拟合能量之间的均方根误差,越小通常表示拟合越好。
relative_error 相对拟合误差,程序内部以小数保存;例如 0.04 表示约 4%。

拟合直线来自论文中的公式:

E_predicted(d) = slope * d + intercept

其中 d 是麦克风坐标在已知 DOA 方向上的投影,slope 和 intercept 的数值单位取决于输入音频的幅值标度,因此主要用于比较拟合质量,不建议跨不同 录音音量直接比较其绝对大小。

history 中的字段

history 保存每次迭代、每个方向的中间结果。它的条目数量通常等于:

iterations × 方向数量

例如使用 5 轮、24 个方向时共有 120 条记录。除 iteration 外,其余字段与 directions 基本相同:

字段 含义
iteration 当前是第几轮迭代,从 1 开始。
angle_deg 当前方向,相对于 CH0 的角度。
slope、intercept 当前轮的能量直线拟合参数。
rmse 当前轮的拟合均方根误差。
relative_error 当前轮的相对拟合误差。

通常可以观察到:随着迭代进行,relative_error 和 rmse 整体下降,最终的 correction_linear 或 correction_db 逐渐稳定。如果某几个方向的误差明显高于 其他方向,应检查对应录音是否存在噪声、削波、混响、声源移动或通道异常。

使用结果时的注意事项

  1. correction_linear 的顺序必须与录音文件的 ch0.wav~ch7.wav 顺序一致。
  2. 这些系数是针对当前麦克风、前置放大器、采样增益和采样率条件得到的;更换硬件 或改变模拟前端后应重新校准。
  3. 模拟数据中的 correction_db 主要用于验证算法是否找回生成时注入的通道增益, 实际录音时应以真实校准结果为准。