5.9 KiB
离线麦克风增益校准
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 逐渐稳定。如果某几个方向的误差明显高于
其他方向,应检查对应录音是否存在噪声、削波、混响、声源移动或通道异常。
使用结果时的注意事项
correction_linear的顺序必须与录音文件的ch0.wav~ch7.wav顺序一致。- 这些系数是针对当前麦克风、前置放大器、采样增益和采样率条件得到的;更换硬件 或改变模拟前端后应重新校准。
- 模拟数据中的
correction_db主要用于验证算法是否找回生成时注入的通道增益, 实际录音时应以真实校准结果为准。