跳转至

Lab 03:Q31 LMS 的数值契约与合成回声实验

范围与输入条件

这是纯 CPU 上的定点教学模型:32 抽头滤波器、固定合成 FIR 回声路径、固定算法的伪随机激励、2000 个样本、单讲环境。没有真实 RIR 采集、近端语音、双讲检测、非线性回声处理或目标 DSP 指令实现,不把 ERLE 结果称为产品级 AEC 测量。

运算核心为整数;ERLE 统计使用浮点。学习目标是验证数值边界、收敛和失败行为,不是宣称无 FPU 平台上的全部开销均已测得。

数值契约

Q31 的值域为 [-1, 1)。乘法使用 int64_t 保存 Q62 乘积,除以 2^31 时采用最近舍入,恰好半 LSB 时远离零,最后饱和到 INT32 范围。特别地,INT32_MIN × INT32_MIN 的数学结果 +1 不可用 Q31 表示,必须饱和为 INT32_MAX。

不能简单“加半 LSB 后右移”就称对称舍入;C99 对负数右移的行为依实现,负数左移更会触发未定义行为。当前实现使用带符号判断的除法,不依赖这些行为。

点积先将每个乘积舍入/饱和到 Q31,再用 int64_t 求和,最后饱和输出。32 项的和幅度上界是 32 × 2^31,可放入 int64_t。它不是完整 Q62 乘积累加,更不是 72-bit 累加器模拟;若目标硬件采用最后一次舍入,应建立另一份参考模型对拍,结果允许不同。

LMS 更新为 w[i] += mu × e × x,两个乘法各按上述契约舍入。mu 约 0.08 仅对本实验输入选择,稳定性受输入功率和相关性影响,不保证任意语音或满幅输入都收敛。

运行与验收

在本目录使用 GCC/Clang:

make test
make run

make test 开启 UBSan 且遇错终止,检查 81 组乘法边界、正负半 LSB、加减饱和、全幅点积和静音。make run 生成 erle_data.csv;重复执行会覆盖本目录同名文件,建议在独立实验副本或临时工作目录运行。

完整回归入口是仓库根目录的 python3 -B _scripts/check-audio-lms.py:编译产物和 CSV 放在临时目录,测试普通收敛、UBSan、重复运行、不可写输出及人为提高门限后的失败退出,不访问声卡。

结果如何阅读

参考路径是合成线性 FIR,麦克风输入只有回声,因此 ERLE = 10 log10(P_mic / P_error) 在本场景可用于看收敛。功率采用指数平滑,CSV 最后一行包含最终样本;真实双讲时不能用总麦克风功率直接当纯回声功率。

程序以 25 dB 为本教学用例门限,未达到、结果非有限值、输出文件写入失败均返回非零退出码。测试脚本还用 100 dB 门限验证失败分支。不得只解析终端出现过 PASS 或有 CSV 就判定成功。

原始样本数而非墙钟时间用于横轴;本模型未指定采样率,因此不能将“2000 样本”自动说成固定毫秒或某款 DSP 的实时性能。下一步应加入多输入功率、双讲、路径变化、延迟偏移与真实目标架构算术对拍。