基于炬芯ATS3089X自研AEC声学回声消除算法

ATS3089P 自研 AEC 通话、PCM 导出与试听

对应 `app aec status` 版本 **261015-v4**。控制指令可用普通 UART;二进制音频通过板上 USB CDC 导出,或者保存到 NAND 后切换 USB U 盘复制。

本版根据真实双讲快照 `D:\logs\aec\aec_20261015_161145_793515` 修正:原版无条件 NLMS 出现输出增能和参考很弱时误消除近端。新增前后台滤波、弱参考门限、NLMS 正则项、双讲慢学与失配回退;优化 AEC 热点循环。原始数据保持不变,重放试听与中文分析在 `D:\logs\aec\aec_20261015_161145_793515_v4_review`。重放执行修改后的生产 ARM C,不能代替重新烧录后的真实通话验证。

1. 处理前后是什么声音

| 信号 | 获取位置 | 内容 |

| --- | --- | --- |

| MIC / before | ADC0,进入 CPU 算法前 | 近端人声 + 扬声器返回的远端回声 + 环境噪声 |

| REF / reference | 原厂 PA→ADC1 芯片内部回采 | 扬声器电气参考,不是第二个麦克风 |

| OUT / after | CPU AEC 输出,送原通话编码器前 | 目标是保留近端人声,抑制与 REF 相关的回声 |

**不能保证 OUT 只剩人声。** 基础线性 AEC 仍可能有残余回声、环境噪声和扬声器非线性失真。v4 加入启发式双讲保护和安全发布,但没有完整商业双讲检测、非线性回声抑制、时钟漂移补偿或长混响处理。参考弱时透传 MIC 是保护人声,不能当作强消回声。

三路按同一个输入样本索引保存,长度相同。OUT 是编码前 PCM;最终远端听感还受到蓝牙编码、手机与网络处理的影响。所有试听文件保持原始增益,没有分别归一化处理前后幅度。

2. 电脑现有试听样例

工程 `application/bt_watch/outdir/aec_listen_demo/` 下已生成 5 秒样例。进入其中本次的 `aec_...` 子目录,打开:

  • `mic_before.wav`:处理前。

  • `reference.wav`:参考。

  • `aec_after.wav`:处理后。

  • `before_then_after.wav`:先听完整处理前,静音半秒,再听完整处理后。

  • `before_L_after_R.wav`:左声道处理前,右声道处理后。

这组样例使用已有 MATLAB 合成数据与实际生产 C 内核的 ARM 仿真结果,前 3 秒模拟纯远端,后 2 秒加入模拟近端声音。**它是算法演示,不是开发板实录通话。**

3. 板端自检也能保存三路 PCM

先挂断电话。原来的 selftest 只在内存计算;带 `dump` 才预约快照:

```text

app aec selftest lms dump

app aec status

```

等待最终 `aec: CPU offline done result=0 algo=lms ...`,以及快照 `capturing=0 ready=1 frames=64000 source=2`,再按第 5/6 节导出。NLMS 对应:

```text

app aec dump clear

app aec selftest nlms dump

```

`selftest OK` 表示任务提交成功,完成以 `CPU offline done result=0` 为准。自检是 4 秒、16 kHz 的已知纯回声,不含真人近端讲话;可听到噪声被抵消。每路 PCM 为 128000 字节。

自检固定参数:NLMS 256 taps / mu=200‰,LMS 64 taps / mu=800‰。最后一秒纯回声 ERLE 超过 10 dB 且没有数值复位才通过。`selftest_erle_decidb=784` 表示合成模型 78.4 dB,不能作为实测通话指标。

4. 真实蓝牙通话与采集

先 `app aec stock` 验证原厂通话正常。建议挂断后选择 CPU NLMS:

```text

app aec livecfg nlms

app aec nlms

```

重新拨号,确认双方有声音,再执行 `app aec status`:

```text

aec: version=261015-v4 requested=nlms call_active=1 active=nlms ... custom_live=1

aec live: running=1 ... frames=持续增加 ... raw_drop=0 out_drop=0 fallback=0 error=0

```

`custom_live=1` 表示固件包含能力;只有 `active=nlms/lms` 且 `running=1` 才是当前实际运行自研通话。也支持通话中切换 stock/off/nlms/lms:由原通话线程重开本地媒体,出现短暂中断,复用原 SCO,不发送音源切换 AT 命令。以最终 `AEC mode=... restart=1 error=0` 和 status 为准。

各指令是否关闭原厂 AEC

| 指令 | 原厂 DSP AEC 的 SDK 开关 | CPU 自研 AEC |

| --- | --- | --- |

| `app aec stock` | 开启 | 不启用 |

| `app aec off` | 关闭 | 不启用 |

| `app aec nlms` | 关闭 | NLMS 加当前保护层 |

| `app aec lms` | 关闭 | LMS 加当前保护层 |

`app aec livecfg ...` 只设置下次自研通话参数,不切换运行模式。`app aec freeze off` 只恢复自研系数学习;`freeze on` 冻结学习,但已有系数仍用于抵消回声。`app aec dump start 10` 只采集当前三路数据,不切换原厂/自研算法。

实现链路:`src/btcall/btcall_aec.c` 中仅 stock 将 `owner_enabled` 设为 true,媒体打开前调用 `audio_policy_set_voice_aec_enabled()`;`framework/audio/audio_policy.c:audio_policy_get_record_channel_support_aec()` 将该值返回给 SDK 初始化。nlms/lms 同时注册 `aec_live` 钩子,CPU 处理后再交给原 DSP 编码器。DSP 仍承担原编解码任务,PA→ADC1 硬件回采仍保留,`adc_aec_config 1` 表示回采开启,不能据此认定原厂 DSP AEC 也开启。关闭范围是 SDK 暴露的 AEC 通路;不能由此断言闭源 DSP 内所有 ANS/AGC 等模块均关闭。

保持通话,先将需要保留的上一组快照导出,再开始新的一组:

```text

app aec freeze off

app aec dump clear

app aec dump start 10

```

必须确认 start 返回"请求已接收"。若返回 `请求失败 (-17)`,表示已有快照且新采集被拒绝;此时执行电脑 export 会重新导出旧快照。电脑目录名是导出保存时间,不能证明录音已经更新。`clear` 后再 start 才会建立新快照。

建议正式验证用 `app aec dump start 20`:0~8 秒仅远端讲话、板旁安静;8~14 秒仅板旁讲话、远端安静;14~20 秒双方同时讲话。前几秒供滤波器收敛。这样可分别判断消回声、保留近端和双讲表现。

10 秒采满自动停止快照,通话和算法继续。也可提前停止:

```text

app aec dump stop

app aec status

```

`capturing=0 ready=1` 表示可导出。时长范围 1~20 秒;最长三路占 PSRAM 1920000 字节。通话实时线程不写 NAND 或 USB。挂断、切 stock/off 或关闭媒体,会结束未采满快照,保留已处理部分。

下一通电话不自动覆盖快照。导出后准备下一组时显式执行 `app aec dump clear`。

实录核对示例:2026-10-15 18:21:17 的 start 返回 -17,18:22 保存目录 `aec_20261015_182224_788514` 的三路 PCM 及 metadata 与 17:59 的 `aec_20261015_175903_397023` 逐字节完全相同。这是同一快照重复导出,不能当成新一次 AEC 实验。

5. USB CDC 一条电脑命令导出

插板上 USB 数据线。如果当前是 U 盘模式,先在 Windows 安全弹出,再用普通 UART 发送:

```text

app udisk off

app usbserial on

```

已有 USB 自动监听模式的设备,插线后确认 CDC 枚举即可。CDC/U 盘/USB 声卡共享一个 USB 控制器。普通 UART 可以继续观察日志;电脑工具要用板上 **USB CDC COM 口**。

PowerShell 安装依赖、查询端口:

```powershell

python -m pip install pyserial

python -m serial.tools.list_ports

```

在工程 `` 根目录执行,COM14 改为实际端口:

```powershell

python .\application\bt_watch\tools\aec\aec_dump.py export --port COM14 --output-dir D:\logs\aec

```

工具自己发送 `app aec dump export`,不需要提前手动发送。它导出已有冻结快照,不重新采集;可在通话继续运行时导出,USB 线程优先级低于实时算法。关闭占用同一 CDC COM 口的串口助手,否则 Windows 拒绝访问;普通 UART 端口可保持打开。

长度和 CRC32 校验通过后,生成新的时间戳子目录:

| 电脑文件 | 用途 |

| --- | --- |

| `mic_before.pcm/.wav` | AEC 前 MIC |

| `reference.pcm/.wav` | 扬声器 REF |

| `aec_after.pcm/.wav` | CPU AEC 后 OUT |

| `before_then_after.wav` | 先前后后顺序试听 |

| `before_L_after_R.wav` | 左前右后对比 |

| `metadata.json` | 源类型、算法参数、采样数、丢样、数值复位、耗时、CRC |

| `试听说明.txt` | 试听方法 |

三路均为 16 kHz、16 bit、有符号小端、单声道。WAV 只添加文件头。CRC 错误、缺尾帧、导出失败时不发布成功音频;快照仍在板上,可重试。

确定 [1,3) 秒没有近端讲话时,可以额外计算 ERLE:

```powershell

python .\application\bt_watch\tools\aec\aec_dump.py export --port COM14 --output-dir D:\logs\aec --far-only 1 3

```

ERLE=`10*log10(MIC纯回声功率/OUT剩余功率)`。双讲时不能把近端声音当残余回声。本工具默认不猜纯远端区间。

6. 保存到 NAND,再通过 U 盘复制

先挂断,确保电脑没有接管 NAND:

```text

app aec dump save

app aec status

```

等待 `exporting=0 export_error=0` 及 `aec dump: saved ...` / `save done`,再 `app udisk on`。第一组根目录文件为:

| 文件 | 内容 |

| --- | --- |

| `AEC000M.PCM` | MIC,处理前 |

| `AEC000R.PCM` | REF,参考 |

| `AEC000O.PCM` | OUT,处理后 |

| `AEC000.TXT` | 参数、源类型、三路 CRC;完成后最后写入 |

后续依次 AEC001、AEC002。同组任一文件存在就跳过整组,避免覆盖。每路 `frames*2` 字节,10 秒为每路 320000 字节。

把 U 盘 PCM 转为可试听 WAV,例如 U 盘为 E:

```powershell

python .\application\bt_watch\tools\aec\aec_dump.py convert --mic E:\AEC000M.PCM --ref E:\AEC000R.PCM --out E:\AEC000O.PCM --output-dir D:\logs\aec

```

通话中保存 NAND 返回忙,避免慢速文件写影响通话。保存与原录音/LC3 共用预约及 FAT 锁;保存期间 USB U 盘切换和自动离线日志导出返回忙,完成后恢复可用。

7. 命令、参数与排查

| 命令 | 作用 |

| --- | --- |

| `app aec stock` | 原厂 DSP 前处理,开机默认 |

| `app aec off` | 旁路原厂前处理,单 MIC,不追加硬件 REF |

| `app aec nlms` / `app aec lms` | CPU 自研算法处理真实通话上行 |

| `app aec livecfg nlms` | 下次自研媒体默认 128 taps / mu=200‰ / delay=0 / swap=0 |

| `app aec livecfg lms` | 下次自研媒体默认 128 taps / mu=800‰ / delay=0 / swap=0 |

| `app aec livecfg nlms 128 200 32 0` | 自定义 taps、mu、delay、swap |

| `app aec freeze on/off` | 停止/恢复学习,已有回声估计仍参与抵消;也作用于离线任务 |

| `app aec dump start 10` | 实际自研通话的三路快照 |

| `app aec dump stop` | 结束快照,不停止通话算法 |

| `app aec dump export/save/clear` | CDC 导出 / NAND 保存 / 显式清空 RAM 快照 |

| `app aec stop` | 仅取消离线任务;退出自研通话应切 stock/off |

实时配置范围:taps 32~256,mu 1~1000‰,delay 0~4096 点,swap 0/1。运行时修改配置返回忙;先切 stock 并等完成,再 livecfg,最后切回 nlms/lms。切换会重置系数;不写 NVRAM,重启恢复 stock。

128 taps 在 16 kHz 覆盖 8 ms,256 taps 覆盖 16 ms。delay 补偿固定延迟,不能替代更长滤波器覆盖混响。实时默认 128 taps,与离线 NLMS 自检的 256 taps 不同。必须实板观察最坏耗时和丢样,不能仅凭软件测试保证实时效果。

`swap=0` 按 ADC0=MIC、ADC1=REF 拆分,依据板配置 `CONFIG_AUDIO_ADC_0_AEC_SEL=1`。上板需核对:只有远端讲话时 REF 明显有声;远端安静、只在板旁讲话时 MIC 明显有声而 REF 接近安静。如果相反,先切 stock,再 `app aec livecfg nlms 64 200 0 1`,重新切 nlms 测试。文件等长不能证明实际通道顺序、极性、回采幅度和声学延迟都已正确。

状态重点:

  • `call_error=0 pending=0`:模式请求已处理且未报告错误。

  • `running=1 frames持续增长`:CPU 线程正在处理。

  • `aec guard: weak/doubletalk/reject/promote`:参考弱的块数、疑似双讲块数、前台失配回退块数、后台系数发布次数。`promote=0` 长期不增长可能未得到可用模型;计数增加本身不能证明消回声足够。

  • `rms_mic/rms_ref/rms_out`:最近一块 RMS,单位为 int16 原幅度,不做独立音量归一化。

  • `raw_drop=0 out_drop=0 resets=0 fallback=0 error=0`:未检测到队列/编码输入丢样、数值复位或降级。

  • 每块 160 点对应 10 ms,`overruns` 统计超过 10 ms 的算法块。平均值低不代表最坏情况下实时。

  • 原始队列溢出会停止快照并 MIC 透传降级,明确 `fallback=1`;恢复 stock、降低 taps 或检查负载后重试,不能把缺帧数据当成功对比。

  • 快照 source:1=合成 NLMS,2=合成 LMS,3=真实通话 NLMS,4=真实通话 LMS。

  • `-16`=忙;`-17`=已有快照,先导出再 clear;`-61`=无可导出数据;`-107`=CDC 未连接。

双讲学习实验可先让远端发声几秒,待系数学习后 `app aec freeze on`,再加入近端讲话观察。人工冻结不等于自动双讲检测。

8. 实现原理与 CPU/DSP 分工

```text

SCO下行 → 原DSP解码 → DAC/PA → 扬声器

└→ 内部PA→ADC1 REF ─┐

MIC → ADC0 ──────────────────────────────────┤

同一ADC FIFO / DMA交织 ┘

↓

DMA回调只复制到8KiB队列

↓

CPU FPU线程拆MIC/REF

↓

后台LMS/NLMS学习与验证

↓

前台固定滤波 + 保护 → OUT

↓

原录音stream → 原DSP编码 → SCO上行

MIC + REF + OUT → PSRAM快照 → USB CDC / NAND→U盘

```

没有再开一个 ADC 抢原厂设备,也没有修改闭源 DSP 参数。现有 `audio_record` 增加 VOICE 钩子,媒体服务仍管理 ADC 和编码器;CPU 消费双时隙输入后,将单声道结果写回原编码输入流。

stock:DSP AEC + 硬件回采;off:旁路 DSP AEC,无追加回采;lms/nlms:旁路 DSP AEC,保留硬件回采,由 CPU 拆分和处理。不能把原始 MIC/REF 交织数据当单声道上行。

实时线程优先级 8,栈 6144 字节、`K_FP_REGS`;打开自研采集期间持 PARTIAL 唤醒锁和高性能 DVFS,关闭释放。中断不做浮点、不等待算法、不操作 USB/FAT。停止先禁止新块,等待 worker 离开,再释放 stream/ADC,避免挂断后访问已销毁内存。

默认 stock 未注册钩子,继续原通话链路。切换失败尝试恢复旧模式,复用原 SCO/HFP 与 K1 音源策略。当前为单 MIC + REF,不等于双 MIC 降噪。

原厂回采依据:`CONFIG_AUDIO_VOICE_HARDWARE_REFERENCE=y`、`CONFIG_AUDIO_ADC_0_AEC_SEL=1`;`audio_record_create()` → `hal_ain_set_aec_record_back()` → `AIN_CMD_AEC_CONTROL` → `phy_audio_adc.c:adc_aec_config()`,开启 ADC1 `PAL2AD1_EN` 和 FIFO 时隙。MIC/REF 同属 ADC 采样域,无须外接回采线。

原厂前处理和 CVSD/MSBC 编解码沿用 `adMUSIC.dsp`。自研滤波在 CPU 上运行。闭源 DSP 内部 ANS/AGC/NLP 边界没有完全公开,stock/off 是 SDK AEC 前处理通路选择,不能保证只切一个内部线性模块。

v4 通话保护原理

`aec_guard.c` 在经典内核外维护前台与后台两个上下文。前台冻结系数,负责实际输出;后台学习。后台连续三个 10 ms 块的残差能量均小于前台和 MIC 的 75% 时,才将系数发布给前台,下一块使用新系数。短时能量判断有局限,不能等同完整商业双讲检测。

参考门限取 `max(0.00004, 最近参考峰值功率*0.01)`,信号归一化到 int16/32768;最低门限约为 207 LSB RMS,约 -44 dBFS。此值根据当前板采集的弱参考/串扰量级选择,参考增益变化后要重新核对。参考低于门限时保留 delay+taps 对应的短尾音,随后冻结学习并透传 MIC;历史仍连续推进。

通话 NLMS 分母改为 `sum(X^2)+1e-8+taps*参考门限功率`,避免参考暂停时很小的分母放大学习步长。已有模型解释不了 MIC 的明显增能时,后台步长降到原来的 1/16,允许慢速跟踪路径变化;不直接把后台残差输出到通话。前台残差功率超过 MIC 的 105% 时,该块返回原 MIC,防止失配产生额外声音。这里只限制异常增能,没有把整段音量压低来制造消回声效果。

`aec_lms.c` 将环形卷积拆成两个连续区间,旧状态每块检查一次,系数更新仍逐项检查 NaN/Inf/越界;AEC 内核与保护层单独 `-O3` 编译,不启用 fast-math。实时性仍以实板 `peak_us/overruns/raw_drop/out_drop` 为准,ARM 指令仿真耗时不是板端实时耗时。

9. 原离线文件与 MATLAB 功能

等长、单声道 S16LE 的 MIC.PCM/REF.PCM,8/16 kHz,根目录 ASCII 8.3 文件名;复制到 U 盘、安全弹出后:

```text

app udisk off

app aec config nlms 256 200 0

app aec run /NAND:/MIC.PCM /NAND:/REF.PCM /NAND:/OUT.PCM 16

app aec status

```

等待离线 `busy=0 result=0` 后 `app udisk on` 导出。已有输出拒绝覆盖。离线 config 支持 32~512 taps,与实时 livecfg 独立;离线任务不切通话算法,遇到电话会取消。

```text

MIC dn = sn + vn + h*xn

Xn = ref\[n-delay, ..., refn-delay-taps+1]

en = dn - Wn'*Xn

mu = mu_permille/1000

LMS: Wn+1 = Wn + (mu/taps)*en*Xn

NLMS: Wn+1 = Wn + mu/(sum(Xn^2)+1e-8)*en*Xn

```

内核 float32 运算,块间保留系数和历史;低参考能量停止学习,输出饱和 S16,数值异常复位并计数。LMS 步长额外除 taps,不能直接套教材中未缩放的 mu。

MATLAB R2021b 的生成、分析、逐样本核对说明见 tools/aec/README.md(tools/aec/README.md),只需基础 MATLAB。真实导出的数据可这样分析,`1 3` 必须确认为纯远端区间:

```matlab

addpath('D:/Master/6project/ATS3089C_to_ATS3089P//application/bt_watch/tools/aec');

d = 'D:/logs/aec/本次导出目录';

analyze_aec(fullfile(d,'mic_before.pcm'), fullfile(d,'reference.pcm'), ...

fullfile(d,'aec_after.pcm'), 16000, 1 3, d);

```

10. 代码位置、编译和验证

| 文件 | 职责 |

| --- | --- |

| `src/main/aec_lms.c/.h` | 离线/实时共用 LMS/NLMS 内核 |

| `src/main/aec_guard.c/.h` | v4 前后台滤波、正则化、弱参考/双讲与失配保护 |

| `src/main/aec_live.c/.h` | 原始队列、FPU 线程、拆分、编码前回注、耗时与丢样 |

| `src/main/aec_capture.c/.h` | 三路快照、CDC 长度/CRC 协议、NAND 自动编号 |

| `src/main/aec_research.c/.h` | 自检、文件处理、自检推送快照 |

| `src/main/system_app_shell.c:shell_aec()` | 普通 UART/CDC 指令、USB 模式互斥 |

| `src/btcall/btcall_aec.c/.h` | owner 异步模式切换、状态、失败回滚 |

| `src/btcall/btcall_media.c`、`btcall_event.c` | 实际媒体生命周期和消息 |

| `framework/audio/audio_record.c/.h` | VOICE 钩子、回采和关闭同步,保持 SDK 结构体布局 |

| `framework/audio/audio_policy.c/.h` | 原厂 AEC 策略,默认 stock |

| `tools/aec/aec_dump.py` | Windows/Python 上位机:CDC 接收、CRC、分路、WAV、试听、ERLE |

| `tools/aec/analyze_capture.py` | 原始 CRC 校验、RMS/削波/相关峰、统一纵轴波形与中文报告,不把双讲能量差当作 ERLE |

| `tools/aec/inspect_capture.py` | 标准库检查三路实录、相同块比例、每秒电平与 MIC-OUT 差值试听;输出中文检查报告 |

| `tools/aec/*.m` | MATLAB 参考和分析 |

| `tests/aec_live/` | 生产实时/导出与电脑工具回归 |

重要修改有 `//zk+`、`//zk+-` 与中文注释,Python/Kconfig/CMake 用对应 `#zk+`、`#zk+-`。

软件测试直接执行生产 C 的 Cortex-M33/FPU 指令,检查 MIC/REF→CPU→编码输入、三路等长、不覆盖、CRC、冻结、静音、溢出降级和资源释放。硬件/RTOS/存储边界使用替身,不能替代实板 ADC、声学、手机兼容性和最坏负载测试。

```powershell

python application/bt_watch/tests/aec_live/run_tests.py

python application/bt_watch/tests/aec_live/run_guard_tests.py

python application/bt_watch/tests/aec_live/test_pc_tool.py

python application/bt_watch/tests/aec_btcall/run_tests.py

python application/bt_watch/tests/aec/run_research_tests.py

python application/bt_watch/tests/aec/run_shell_tests.py

python application/bt_watch/tests/hfp_route/run_tests.py

python application/bt_watch/tests/spp/run_usb_tests.py

```

编译并打包,在 `` 根目录:

```powershell

Push-Location .\zephyr

python build.py -n -b ats3089p_dev_watch -a bt_watch

Pop-Location

```

固件输出目录 `application/bt_watch/outdir/ats3089p_dev_watch/_firmware/`:`ats3089p_dev_watch_261015_aec_live_v4.fw` 与 `ats3089p_dev_watch_261015_aec_live_v4_debug.fw`。

烧录后先确认版本,再做 stock 通话、CPU NLMS 三阶段采样和导出。核对通道、raw_drop/out_drop、peak_us、第二/第三次通话;最后复查显示、录音、ASR/TTS、音乐/歌词、Find my、NTC 和离线日志等原有功能。

重放本次真实 MIC/REF,生成处理结果

以下需要 ARM GCC 与工程已有的 Unicorn/pyelftools 测试依赖;重放执行生产 C,不是 Python 算法替代。输出目录必须是新目录,拒绝覆盖录音。重放从零系数开始,不能恢复快照开始前的滤波器状态。

```powershell

python application/bt_watch/tests/aec_live/run_guard_tests.py --capture-dir D:\logs\aec\aec_20261015_161145_793515 --output-dir D:\logs\aec\本次新的重放目录

```

生成 `aec_after_v4_replay.pcm/.wav` 和 `replay.json`。分析图与中文报告需要额外安装分析依赖;日常 USB 导出仍只需要 pyserial:

```powershell

python -m pip install numpy scipy matplotlib

python application/bt_watch/tools/aec/analyze_capture.py --capture-dir D:\logs\aec\aec_20261015_161145_793515 --replay-dir D:\logs\aec\本次新的重放目录 --window 6 8

```

`--window 6 8` 是人工指定的参考较弱区间,不表示已知纯近端。打开 `v3_then_v4_replay.wav` 或 `mic_then_v3_then_v4_replay.wav` 比较;`分析报告.md` 与 `analysis.json` 记录数值和局限。原始快照长度只有 10 秒;直接打开 WAV,避免 Audacity 原始 PCM 导入采样率错误导致时长/音调变化。

检查"处理前后几乎一样"的实录

只检查板端实际输出、不运行重放时,使用标准库工具:

```powershell

python application/bt_watch/tools/aec/inspect_capture.py --capture-dir D:\logs\aec\aec_20261015_173655_821933 --output-dir D:\logs\aec\aec_20261015_173655_821933_check01

```

新目录生成中文 `实录检查.md`、`inspection.json` 和原增益差值 `mic_minus_after.wav`。差值表示实际减去的信号,可能包含误消除的人声,不能当作干净回声真值。工具验证三路 CRC/长度,按秒统计 MIC/REF/OUT RMS、总电平变化,以及 10 ms 块逐点相同的比例。

本次 17:36 导出的 10 秒数据中,74.8% 的块完全相同,总电平仅变化 -0.0447 dB。该结果确认处理变化很小,当前 v4 不能据此视为完成实录 AEC 效果验证。弱参考透传、失配回退和系数发布门限都可能导致相同块;音频文件没有保存逐块保护原因,不能反推出每一块的真实 guard 状态。128 抽头仅覆盖约 8 ms,且当前发布条件要求连续三个块至少降低 25% 能量,仍需检查对实际声学路径及双讲的适用性。

下一轮先单独采 10 秒纯远端:板端扬声器持续播放远端声音,板旁保持安静,记录该次 `app aec status`;再分别采纯近端、双讲。只有明确确认纯远端起止秒数,才使用 `--far-only START END` 计算能量法 ERLE。总电平变小、波形改变和去回声不是同一个判定,需同时验证近端人声保留。

2026-10-15 17:59 新快照 `aec_20261015_175903_397023` 经用户确认仍是双讲:拨打 10086,同时在板旁讲话。用户进一步确认扬声器背向 MIC、回声较小,录音以近端为主。该组处理前后总电平变化 -0.1247 dB,69.2% 的 10 ms 块相同,不能由此认定回声抑制不足或计算 ERLE。近端占主导时,AEC 保留近端会使整体波形接近;回声抑制与近端保留需分别验证。

检查工具新增 `--scenario doubletalk` 等用户声源标注,随中文报告及 JSON 保存;默认仍为 unknown,禁止仅凭波形自动判断纯远端。完整使用方法见 tools/aec/README.md(tools/aec/README.md)。本次更新检查工具与说明,不改变板端 AEC 系数和通话音量。

相关推荐
通问AI1 小时前
在两台 Mac Studio 上跑 800B 模型:MLX + RDMA over Thunderbolt 实测与四道门选型法
算法
ZywOo6231 小时前
《算法竞赛进阶指南》0x03 前缀和与差分
算法
Scintilla_y1 小时前
DAY2 滑动窗口
算法·leetcode·散列表
lvwangshu1 小时前
笛卡尔树
算法·图论
026d232 小时前
状态信号只知“其然”不知“其所以然”:变工况机械故障诊断的物理盲区
算法
姜鱼问生2 小时前
备份和服务器在同一台机器上,等于没备份
算法·架构
姜鱼问生2 小时前
别再 chmod 777 了,用 ACL 给它开一扇窗
后端·算法·架构
特立独行的猫a2 小时前
仓颉语言UI开发实战:我用仓颉写了个桌面版力扣
算法·leetcode·ui·tauri·仓颉·cj-tarui
y1su3 小时前
Leetcode 动态规划 模板
java·数据结构·算法·leetcode·动态规划