






ATS3089P 音箱固定命令识别:原理、源码移植与使用
更新日期:2026-10-30。以下路径以 `/` 为工程根目录。本功能使用 `tools/soundbox_ASR_wakeup` 提供的音箱模型,在 ATS3089P 本机处理麦克风音频,屏幕显示固定命令中文,串口输出 ASCII 标签、ID 和解码分数。
本文中的“全源码编译”指 ATS3089P 使用移植后的 C/H、模型数组及当前工具链构建算法,参考 AC7016 SDK 的采集与应用流程,不链接其中的 `libetasr.a`。91 条词表限定了识别范围;本功能不提供任意句子转写或翻译。
触摸使用从“更多 → soundbox ASR”进入,点击“启动监听”;打开页面不自动开始,返回页面也不停止。触摸说明见第 16 节。第 1 节保留串口命令;第 13 节保留初版 PC 验证和构建记录,第 15 节记录随后实板实时超预算问题及修正。PC 测试、实板识别和新增页面验收分别记录。
1. 启动与最短验证流程
1.1 麦克风识别
先用默认原始音频前端,减少输入链路变量:
```text
app soundbox list
app soundbox mode all
app soundbox front raw
app soundbox start
app soundbox status
app soundbox stop
app soundbox status
```
`start` 和 `test` 成功返回只表示请求入队。麦克风正常监听期间 `busy=1 running=1 requested=1 capture=1`;`stop` 也是异步停止请求,需等 `busy=0` 后再切换 `mode`、`front` 或启动下一任务。运行中更改前端/模式会返回 `-EBUSY`;锁暂忙返回 `-EAGAIN`,稍后重试。开机默认 `mode=all front=raw`,没有显式 `start` 不开麦。
`list` 默认显示第 0 页,每页最多 10 条;`app soundbox list 0` 到 `app soundbox list 9` 可查看全部 91 条。串口仅打印 ASCII 英文标签,避免终端不支持中文而乱码。例如 ID 77 为 `increase_volume`,实际仍须说中文“增大音量”;英文标签只负责显示,不提供英语识别。第 12 节保留完整原中文词表,不能把列出词表当成所有词均通过实测。
`all` 是默认的事件观察模式。开启后说词表中的一句,例如“播放音乐”“暂停音乐”“增大音量”,观察中文命令、ID、分数及处理统计。当前接入以打印识别事件为目的,不直接执行关机、接听电话、关闭麦克风、调整灯效等动作。识别到“音箱关机”只表示产生对应事件。
CTC 命令的 `score` 保留原解码器分值;独立唤醒 ID 1 使用二分类分数映射到 0~255。两者都不是百分比正确率或经过校准的可信度。请同时核对命令文字与 ID;不能只看分数高低判断识别是否正确。
启动后新增明确的 `[soundbox] started MIC …` 日志,表示 ADC 已成功开启;随后每 5 秒输出一次 `listening` 和累计输入/耗时诊断。只有出现 `event id=… text=…` 才表示接受了识别事件。若提示 `realtime overrun`,须先处理吞吐不足;启动成功和输入有波形不能保证网络已经赶上连续音频。详细日志及验收流程见第 15 节。
其他占用麦克风的功能需要先停止,包括旧模板识别、原神经网络唤醒、独立 VAD、DOA、语音翻译、录音和 USB 麦克风。启动失败时先查看采集所有者及错误码,避免多个线程读走同一个 PCM ring。
1.2 先唤醒再识别命令
```text
app soundbox stop
等待 app soundbox status 显示 busy=0
app soundbox mode wake
app soundbox start
```
移植层使用 ID 1、2 开启 8 秒命令窗口;ID 5~8 在窗口内被接受后结束窗口,超时后回到等待唤醒。中文名称保留原词表的“”“嗨”。窗口内每个被接受的有效事件会将截止时间刷新为当前时刻加 8 秒;窗口外的其他事件增加 `suppressed`,不更新最后接受的事件。停止或采集溢出会关闭窗口。
这是本轮 ATS3089P 应用层的规则,不能与旧 SDK 的短时计算抑制计数混为一谈。最终 PC 合成音频回归中“”“嗨”均已产生对应 ID;第 11 节说明独立唤醒事件的适配,第 13 节列出测试范围,实板拾音效果仍需验证。
1.3 U 盘音频文件测试
文件回放可将模型问题与麦克风采集问题分开定位。将音频复制到开发板 U 盘后,先在 Windows 安全弹出,再关闭板端 U 盘模式:
```text
app udisk off
app soundbox stop
等待 app soundbox status 显示 busy=0
app soundbox mode all
app soundbox front raw
app soundbox test /NAND:/sample.wav
app soundbox status
```
文件要求如下:
– 小写 `.wav`:RIFF/WAVE、PCM 编码 1、16 kHz、16 bit、1 或 2 声道;`fmt ` 必须在 `data` 前,帧对齐、字节率和长度必须一致。支持跳过额外 RIFF chunk,不支持浮点或压缩 WAV。
– 小写 `.pcm`:无头的 16 kHz 单声道 S16LE,文件长度为偶数。
– 文件大小 2 B~32 MiB;路径长度小于 64 字节,接受 `/NAND:/`、`/SD:/`、`/USB:/`,使用不含空格的 ASCII 路径,禁止反斜线和 `..`。
– `raw/ns/agc` 可使用单声道 WAV/PCM;双声道 WAV 的第一路作为 MIC,第二路不参与这些模式的回声消除。
– `aec/3a` 必须使用双声道 WAV,交织顺序明确为 MIC、真实播放 REF。单声道和裸 PCM 返回 `-ENODATA`。当前没有单独的参考文件参数。
MP3、AAC、浮点 WAV 或修改后缀的压缩音频均不适用。文件任务不打开 ADC;文件读取期间持有板端存储租约,U 盘仍被 PC 占用时会拒绝读取。任务结束或失败会关闭文件并释放租约。
文件尾部额外输入 84 个 192 采样的零块,约 1.008 秒,用于冲刷网络前看帧与词尾。当前 `samples`、`blocks` 和核心音频时间包含这部分冲刷;不能直接将它们当成源文件真实时长。文件回放没有按真实采样速度等待,因此它也不能代替实板实时采集验证。
本机已有验证音频 `out/soundbox_asr_261030/labelled_tts_v1/play.wav`(16kHz、单声道、16bit、“播放音乐”)。可将其复制到板端 U 盘根目录,安全弹出并 `app udisk off` 后,执行 `app soundbox test /NAND:/play.wav`;预期打印 ID 72。目录名 v1 表示音频首次生成的位置,最终事件结果使用第 13 节 v2 可执行文件回归报告。
1.4 状态字段与故障定位
| 字段 | 含义与判断方法 |
| — | — |
| `busy/requested/running/capture/file` | 请求生命周期;文件任务不打开 ADC,`capture=0` 属正常情况;停止后应最终回到 `busy=0` |
| `last` | 最近任务的最终错误码;返回 0 的启动请求仍须检查任务是否成功运行 |
| `samples/blocks/core_frames` | 已推进的时间采样、192 采样调用次数、768 采样核心帧数;文件末尾部分块可能短于 192 |
| `gaps/dropped/queue_peak` | 不连续次数、丢失的 s16 元素及 ring 高水位;双路时 s16 元素数是时间采样数的两倍 |
| `process_us/peak_us` | 一次前端和核心调用的当前/峰值墙钟耗时,单位微秒,包含这段时间内的抢占 |
| `batch48_us/batch48_peak_us/over48ms` | 累计至少 768 个采样的多次调用耗时及峰值;超出同量音频时长时增加 `over48ms`,见第 9 节 |
| `seq/id/score/text/suppressed` | 应用接受事件序号、最后命令、原分值、文字及被窗口/停止状态过滤的事件数 |
| `mic_peak/ref_peak/speech` | 最近块输入峰值、参考峰值及外部 WebRTC VAD 状态;单路模式 `ref_peak=0` 正常 |
| `input_peak_max/input_rms/input_rms_max` | 当前会话最大输入峰值、最近块RMS、当前会话最大RMS;最近静音不会覆盖最大值 |
| `speech_blocks/zero_samples/clipped_samples` | 外部VAD判为人声的调用块数、MIC恰为零的时间采样数及正负满幅采样数;双路REF不计入MIC统计 |
| `model/private/scratch/ready` | 模型字节、核心私有区、临时区和初始化状态;不包含前端、采集 ring 和线程栈 |
| `raw_events/trial_count/trial_limit` | 核心回调事件数、原试用事件计数及其限制,不能用应用 `seq` 替代试用计数 |
| `vendor_ns/vendor_vad/vendor_aec` | 厂商核心内部开关,当前全部为 0;外部前端由 `front` 单独显示 |
`mic_peak` 长期为 0 时先查麦克风路由、其他采集所有者及硬件输入;有采样但 `gaps/dropped` 持续增加时先查处理速度。`last=-ENOMEM` 查资源堆与申请大小,`-ETIMEDOUT` 表示麦克风超过 1.5 秒未提供新 PCM,`-EBUSY` 常见于 ADC 或 U 盘存储占用。先用 `mode all/front raw` 和同一文件回放建立基线,再增加前端处理。
2. 原工程与实际配套 SDK
原 Linux C 推理工程位于:
```text
application/bt_watch/tools/soundbox_ASR_wakeup/
README.md
代码使用指北.md
解码基本法.md
bsp_et_asr_ctrl.c
kws_detect.c
app/projects/libuser_proj/
et_config/
```
用户指定的实际 AC7016 SDK 位于:
```text
application/bt_watch/tools/soundbox_ASR_wakeup/
26-5-28-pixel_bar_7016/SDK/audio/smart_voice/yj/
yj_kws_algo.c
et_config/
libetasr.a
third_kws_event.h
et_keyword.c
et_weights.c
model_config.h
```
本次对照了实际 SDK 与根 `et_config/` 的关键词、阈值、权重、模型配置、算法配置、API、后处理、语言配置和模型信息等 11 个关键文件,内容逐字节一致。因此使用这些 C/H 资源有明确的配套来源。
实际 SDK 的 `yj_kws_algo.c` 提供了分帧、DAC 参考回采、算法初始化、UART 事件转发及短时计算抑制流程;这些是移植参考。AC7016 的设备驱动、时钟、内存地址、TWS 接口和预编译库不能直接用于 ATS3089P。
2.1 旧应用事件枚举与 91 词资源不一致
实际 SDK 的 `third_kws_event.h` 保留了另一版约 20 条事件枚举,其 ID 2 写“花花同学”、ID 3 写“嗨”;当前 91 词模型的 ID 2 是“嗨”、ID 3 是“音箱关机”。`yj_kws_algo.c` 中的旧 `switch` 不能原样作为 91 词的业务动作表。
本轮命令文字和 ID 以 `et_keyword.c` 与原 `keylist.txt` 的对应关系为准。后续接入电机、音乐或屏幕动作时应基于这份表建立显式映射,并单独验证每个动作,不能按旧枚举顺序推断含义。
根目录 `bsp_et_asr_ctrl.c` 的事件回调主要是空适配函数。实际 SDK 的回调会发送 UART 并设置 `set_yj_asr_cal_close(5)`,随后由计数递减控制暂停;这也不等于一个通用的“唤醒后 8 秒对话”状态机。
3. 一条语音的完整处理过程
```mermaid
flowchart LR
A[16 kHz 单路 MIC PCM] –> B[DMA 复制到独占 ring]
B –> C[工作线程拼接连续采样]
C –> D[可选前端处理]
D –> E[20ms 窗口 / 12ms 帧移]
E –> F[512点 FFT / 70维 Fbank / PCEN]
F –> G[每4帧形成48ms处理块]
G –> H[3层卷积 + 6层 DFSMN]
H –> I[66类音素 CTC / top-K路径]
I –> J[91条固定路径匹配 / 阈值 / 后检查]
G –> K[独立二分类唤醒网络]
K –> L[积分窗口 / 峰值 / 冷却]
J –> M[中文名称 + ID + 解码分数]
L –> M
M –> N[all模式观察或wake窗口筛选]
```
DMA 中断只搬运有限长度的 PCM、更新整数统计并唤醒线程。Fbank、网络前向、关键词解码、文件访问和日志输出均在普通线程执行,避免算法占用中断或系统公共工作队列。
“流式”表示持续处理短音频块并保留历史特征和网络状态。48 ms 是输入推进的基本块长度,不是最终识别延迟;实际触发还要等到必要音素、模型前看帧、关键词路径以及后处理条件满足。
4. 音频特征:Fbank 与 PCEN
4.1 时域到频域
当前配套模型配置为 16 kHz。每个特征窗口取 320 个采样,即 20 ms;相邻窗口前进 192 个采样,即 12 ms,窗口之间有重叠。FFT 长度为 512 点。滤波器组将频谱能量映射到 70 维特征,而非直接把原始波形输入网络。
这些参数来自 `model_config.h` 和 `et_alg_config.h`。改变采样率、FFT、滤波器组数量或帧移都会改变训练时的输入分布,不能仅修改一个宏后继续使用原权重。
4.2 PCEN 的作用
PCEN 使用每个频带的历史平滑能量,降低慢变化背景与输入增益变化的影响。其概念形式为:
```text
M[t,f] = (1-s) × M[t-1,f] + s × E[t,f]
PCEN[t,f] = (E[t,f] / (epsilon + M[t,f])^alpha + delta)^r – delta^r
```
`E` 为当前频带能量,`M` 是随时间更新的平滑状态。源码的 `simplified_pcen()` 采用定点近似和量化输出,实际数值处理以配套 C 实现及导出参数为准。PCEN 不等于回声消除,也不能恢复已削顶或丢失的音频。
特征阶段保留时间上下文。遇到采集溢出,不能把缺口前后的采样拼成连续一句;需要重置本段特征、网络缓存及解码路径,再从新的连续采样继续处理。
5. 两个网络及定点量化
当前模型不是只有一个“91 分类”输出层。资源中有一个中文音素网络和一个独立的唤醒二分类网络:
| 项目 | 中文音素主网络 | 独立唤醒网络 |
| — | — | — |
| 前端 | 共享配套声学特征 | 共享配套声学特征 |
| 卷积层 | 3 层,通道 8 / 16 / 32 | 3 层,通道 8 / 16 / 24 |
| DFSMN 层数 | 6 | 6 |
| 隐藏维度 | 192 | 192 |
| 投影维度 | 108 | 48 |
| 输出 | 66 类中文音素,含 blank | 2 类,唤醒/非唤醒 |
| 资源长度 | 332876 B | 140266 B |
合并 `weights.bin` 为 **473142 B**,即上述两段的总和。主网络段的模型配置标识为 `20260422064834`,量化配置写 `MixedPTSQ`。更换模型时必须同时核对两个模型段、配置头、量化参数和词表,不能用另一份 `.pt`、单段 `.bin` 或相似大小的文件替换。
5.1 卷积与 DFSMN
卷积层提取局部时间与频率结构,并逐步压缩特征。DFSMN 使用有限长度的历史/前看状态缓存,将相邻时刻信息加入当前判断;这比每次重新处理整句音频更适合持续输入。
源码的 DFSMN 单元包含投影到隐藏层、投影回低维空间、记忆滤波、残差以及配套归一化/激活处理。主网络配置的状态长度为 7、缓存长度为 6、前看参数为 1。缓存随语音流推进,启动、重置或丢帧后的冷启动阶段与正常稳态不同。
5.2 定点、混合精度与 Q 值
权重和激活使用配套整数表示,运算携带每层 Q 值及混合精度信息;累加通常需要更宽的整数,再通过移位、舍入、饱和和激活得到下一层输入。此处不应笼统写成“全 INT8”,也不能将权重字节直接当成浮点数。
移植保留原模型的量化比例与计算顺序。FFT、PCEN、矩阵计算和激活函数中平台相关的实现需要与参考代码核对,单纯“编译通过”不能证明输出相同。模型字节校验、PC 同音频回放、Cortex-M33 编译及实板采集验证分别解决不同问题。
独立唤醒网络最后由 sigmoid 产生唤醒分数,并构造非唤醒分数,不使用 66 类音素 CTC 输出。原积分后处理代码实际参数为 6 帧窗口、累计量阈值 2.0、峰值阈值 0.3、噪声/复位阈值 0.1、最小间隔 16 帧;冷启动前 5 帧不触发。原注释中的 1.5 / 0.4 与宏值不一致,说明以执行代码为准。移植将这一分支的成功事件显式映射为原词表 ID 1,仍经过原事件计数及试用条件,见第 11 节。
6. CTC、top-K 与固定命令匹配
主网络对连续音频输出音素分数。CTC 引入 blank,允许相同音素持续若干帧;通过合并重复并移除 blank,表达音素顺序,而不要求训练数据逐采样对齐。
当前算法保留每个时刻的高分音素候选,配置 `TOPK1=8`、`TOPK2=8`。解码器将声学路径与词表中的固定 `labels[]` 比较,进行路径搜索、对齐、分数检查以及配套后检查,最后给出词表事件 ID。
因此,修改中文显示字符串不会改变模型能听懂的音素序列;新增中文句子也不是往 `keylist.txt` 追加一行即可。新词需要有正确的音素路径、长度、阈值和配套后检查参数,还要用独立音频验证误接受与漏接受情况。
当前 91 项中,79 项主阈值为 70、1 项为 90、11 项为 255。后 11 项集中在灯光百分比命令,不能保证与其他命令同等容易触发。`prefix_flag=254` 的 4 项进入延迟关键词逻辑,用于等待路径是否继续延长;其余 87 项为 255。此字段不是“需要先唤醒”的开关。
`major` 在这份实际资源中逐项等于 `kws_value`,均为 1~91;`pad1` 全为 0。虽然旧头文件注释将 `major` 描述为主唤醒词布尔值,不能据该注释推断当前表的分类。
7. VAD、AEC、NS 和 AGC 分别是什么
| 处理 | 目的 | 此配套资源/参考源码的实际情况 |
| — | — | — |
| VAD | 判断是否有人声,辅助起止段/省算力 | `ET_ASR_UI_VAD_TYPE=0`,当前资源关闭;VAD bin 大小为 0 |
| AEC | 用扬声器播放参考估计并抵消回声 | 资源 `AEC_TYPE=1`;原 C 配置映射到 Speex AEC,NN3A 分支关闭 |
| NS | 降低环境噪声 | 资源 `NS_TYPE=0`,当前资源关闭;NS bin 大小为 0 |
| AGC | 调整输出响度/增益 | 原 C 配置 `ET_AGC_EN=0`,关闭 |
移植后的识别核心使用单声道输入,关闭厂商内部 AEC/VAD/NS,保留同一组声学模型;前端由独立 CPU 模块处理,避免把双路参考或不配套的前端状态送入网络。`status` 的 `vendor_ns/vendor_vad/vendor_aec` 描述的是核心内部开关,当前应为 0,不等于外部 CPU 前端选项。
可停止后选择以下前端,默认 `raw`:
| 命令 | 实际处理链 | 采集通道 |
| — | — | — |
| `app soundbox front raw` | 原始 MIC;WebRTC VAD 仅统计 | MIC0 单路 |
| `app soundbox front ns` | 经典 Wiener 频谱降噪 | MIC0 单路 |
| `app soundbox front agc` | 平滑增益控制及限幅 | MIC0 单路 |
| `app soundbox front aec` | 带保护的 NLMS 回声消除 | ADC0 MIC + ADC1 PA参考 |
| `app soundbox front 3a` | NLMS AEC → Wiener NS → AGC | ADC0 MIC + ADC1 PA参考 |
以上均不是原厂神经网络 NN3A/GTCRN。各模式同时运行 WebRTC VAD mode 1,以 160 个采样/10 ms 判断 `speech`;VAD 不裁去 PCM、不阻止网络推进,也不会因“非人声”直接停止识别。
当前 NLMS 默认 128 taps、步长 0.2、额外参考延迟 0;参考需与 MIC 同时钟,并按真实路径测量延迟。降噪使用 512 点 FFT、256 采样推进,固定增加 512 采样/32 ms 延迟,最小增益为 0.25。AGC 目标 RMS 为 4000、最大增益 4 倍,含平滑与削顶保护。弱参考、双讲或不合适的参考会限制滤波器更新;具体声学效果仍需板上验证。
原代码提供了 VAD 参数设置函数,但当前 VAD 宏为 0 时相关路径不编译。将其打开还需要正确的 VAD 资源和完整接口,不能只依赖“代码中存在参数函数”。同理,单独存在 `nn3a_weights.c` 或降噪源码不代表当前 473142 B 资源已包含匹配的神经网络 3A。
AEC 的第二路是**与扬声器实际播放同步的参考信号**。实际 AC7016 SDK 在 `yj_kws_algo.c` 中设置 master=0、AEC=1,并通过 `audio_dac_read()` 获取参考。板上的第二实体麦克风采到的是另一路声场,不能替代干净的播放参考;本轮单麦识别也不等同于 DOA、波束成形或双麦阵列降噪。
8. 应用状态机与事件输出
`all` 模式适合验证模型:每个通过词表匹配的事件都按统一 ID/文字输出,不依赖旧 AC7016 业务枚举,也不隐式控制设备。
`wake` 模式在识别核心上方增加应用过滤:
```mermaid
stateDiagram-v2
[*] –> 等待唤醒
等待唤醒 –> 命令窗口: ID 1 或 2
命令窗口 –> 等待唤醒: ID 5~8 或8秒超时
命令窗口 –> 命令窗口: 窗口内其他有效命令
等待唤醒 –> 等待唤醒: 其他命令被过滤
```
这是事件消费规则,模型仍需持续获得连续音频。不能在等待唤醒时随意停采样、清除网络状态或反复打开 ADC,否则会增加冷启动和漏掉开头音节的概率。
后续业务动作应由应用消息处理,不能在 DMA 中断或解码核心中直接执行耗时的音乐、文件、蓝牙或 GUI 操作。接入动作前先验证每条命令的 ID、重复抑制、当前业务状态和退出行为。
9. ATS3089P 采集、线程与资源
新运行时复用 `src/asr/kws_capture.c` 的独占采集仲裁。原默认单路路由为 MIC0、16 kHz、s16、20 dB 输入增益;DMA 缓冲为 512 个 s16,每次半缓冲搬运 256 个采样。单路启动丢弃 6 个半缓冲,约 96 ms,以避开模拟稳定阶段。
采集 ring 是单消费者队列,不会向多个算法广播。新业务使用 SOUNDBOX(6)与 SOUNDBOX_REF(7)所有者,不复用原 WAKE 或 LEGACY 身份读取/停止其他会话。普通旧所有者有效容量为 4096 个 s16,即单路 256 ms。soundbox 两个所有者复用 16384 个 s16 的 PSRAM ring:单路约 1.024 秒,MIC/REF 双路约 0.512 秒;没有扩大 1024 B 的 SRAM DMA 缓冲。
工作线程每次凑齐 192 个时间采样/12 ms,执行前端并交给核心;核心累计到 768 个采样/48 ms 后完成一次网络处理。8 KiB FPU 工作栈放在 PSRAM;初始化、文件读取和识别不占用 shell 栈。会话从资源堆申请前端工作区和核心工作区,核心使用显式 16 字节对齐申请,停止后释放;运行期间持有唤醒锁与高性能 DVFS 租约。
实时运行需要平均计算速度赶上输入;较大的 ring 只能吸收短时抖动,不能解决每 48 ms 输入都持续计算超过 48 ms 的情况。`process_us/peak_us` 是一次 192 采样调用的前端+核心耗时,其中通常 3 次只积累输入,另 1 次含 768 采样网络计算。
`batch48_us/batch48_peak_us` 将多次调用累计到至少 768 个时间采样,覆盖四次前端和一次网络计算。`over48ms` 比较该组耗时与其实际音频时长,严格超过才计数;例如四次各 12.1 ms,虽然单次均小于 48 ms,合计 48.4 ms 仍计一次超预算。麦克风溢出后丢弃尚未完成的累计组,文件尾部短块按实际采样数计算。
计时使用独立 32 MHz HOSC 的 TIMER2,经 `k_cycle_get_32()` / `k_cyc_to_ns_floor64()` 换算,与 187 MHz CPU 频率无关。结果是计时区间的墙钟耗时,包含期间的中断/其他线程抢占及核心事件回调;不包含区间之外的文件读取、输入拆通道、诊断更新和全部采集驱动开销。因此它不是线程独占 CPU 时间,仍须结合丢帧和 ring 高水位判断整条链是否实时。
出现 `-EOVERFLOW` 时应丢弃当前不连续片段并重置相关算法状态;不要继续发布跨缺口的识别结果。通话、录音和 USB 麦克风预留 ADC 后,采集读接口可能返回 `-EBUSY`,运行时应退出本方采集。关闭失败时保留本方所有权并重试,不能误关闭其他功能的 ADC。
模型、特征缓存、网络状态与 worker 栈分别占用内存。核心工作区为 78336 B。按 Cortex-M33 结构布局测得前端工作区:raw 1415 B、AEC 42831 B、NS 15783 B、完整 3A 57199 B,另有前端 context 116 B;各模式不是同时申请。473142 B 仅为权重资源长度,最终整机资源堆峰值、完整调用栈和板端处理时间仍须实测,不能把单函数静态栈数据当成总栈深度。
10. 数据集、训练与准确率的来源边界
当前移植使用用户已有资源,未在本轮重新训练主网络或独立唤醒网络。源码包中的 `tuning/works/wakeup/` 含部分 `.pt`、`.yml` 和版本信息,配置提到内部路径上的正负样本、TTS 数据、AISHELL 清单、DNS/WHAM 噪声以及数据增强。
这些路径和配置能说明部分训练思路,但本地没有配套完整的训练清单、实际音频集合、训练框架、全部日志及与交付两段模型一一对应的可复现训练记录。配置中出现某个公开数据集名称,也不能据此推断整个模型只用该公开数据集训练。
原 `run.sh` / `all_run.sh` / `outFactory/` 流程主要用于生成资源、编译 C 推理代码并对指定音频运行;执行成功不等同于完成模型训练。部分脚本还引用原开发机的 `/mnt/…` 或 `/home/…` 绝对路径,不能直接作为本机一键训练指令。
当前不能填写可靠的总体准确率、召回率、误唤醒/小时或全部 91 词通过率。需要固定独立测试集,覆盖所有词、不同说话人、距离、噪声、混响和长时间负样本,并记录:
– 每条命令的样本数、正确接受、漏接受及混淆 ID。
– 唤醒词召回率、误唤醒次数和有效负样本总时长。
– 相同音频在参考 C、移植 C 与板上文件回放中的事件/分数差异。
– 实板实时采集的丢样、峰值、削顶、ring 高水位和处理时长。
PC 参考音频通过只能证明这批文件上的行为;真实麦克风结果还受输入路由、增益、采样连续性、回声及噪声影响。第 13 节应逐项列出已做验证及未覆盖范围,不补写没有测试依据的百分比。
11. 原试用计数与源码许可说明
原 C 源码启用 `ET_TEST_VER_EN=1`,本轮保留原试用计数逻辑。`get_v_test_cnt()` 的默认结果为 306,事件计数递增后只有小于该值才进入正常回调;`get_v_test_cnt2()` 的默认结果为 798,另一路累计计数超过该值后停止继续处理。两个计数含义不同,不能将某个数字直接当成可长期运行的识别次数保证。
原代码会忽略事件 0,而主 CTC 解码器跳过第 1 条词路径,将其交给独立二分类唤醒网络。原独立分支触发后调用 `send_event(0)`,随后被事件入口丢弃,导致“”成功唤醒也不能传到应用层。本轮在该分支唯一的成功出口显式发送原词表 ID 1,并将当前唤醒分数映射到 0~255 的事件分值;仍进入原 `et_lib_asr_send_event()` 递增计数、检查原上限,不改模型、阈值或试用条件。最终合成音频回归中 ID 1 已正确输出一次。
诊断同时保留厂商事件计数与应用接受计数。长时间运行没有新事件时,应先检查这些计数和采集状态,不能只凭 `seq` 判断模型失效;应用窗口过滤也不会抵消核心已经发生的计数。
源包没有覆盖整个算法和模型的统一 LICENSE;其中 Speex、SHA 等第三方文件保留各自版权及许可注释。本文“全源码编译”只描述本轮移植方式,不代表为整包赋予新的开源许可。代码与模型仍保留其原有来源和现有声明。
12. 原始 91 词、音素及匹配参数
下表中文逐字保留原 `et_config/keylist.txt`,包括“”“条”等原字样;音素逐字保留 `et_keyword.c` 的注释,不据同音字猜测修改。真正参与解码的是每项 `labels[]` 数字序列,中文名称仅用于人阅读。部分中文描述与音素注释的长短并不完全相同,不能仅依据显示文字推断可说的任意变体。
| 类别 | ID |
| — | — |
| 唤醒 | 1~2 |
| 音箱关机 | 3~4 |
| 结束对话 | 5~8 |
| 壁纸 | 9 |
| 屏幕/亮度 | 10~26 |
| 灯效/灯光 | 27~45 |
| 音效 | 46~50 |
| 变声 | 51~52 |
| 麦克风 | 53~54 |
| 电话 | 55~56、66~71 |
| 音量 | 57~64、77~83 |
| 下一曲 | 65、88~91 |
| 播放/暂停/停止 | 72~76 |
| 上一曲 | 84~87 |
| ID | 原中文名称 | 原音素注释 | 阈值 | prefix |
| —: | — | — | —: | —: |
| 3 | 音箱关机 | ii in x iang g uan j i | 70 | 255 |
| 4 | 关闭音箱 | g uan b i ii in x iang | 70 | 255 |
| 5 | 对话结束 | d ui h ua j ie sh u | 70 | 255 |
| 6 | 结束对话 | j ie sh u d ui h ua | 70 | 255 |
| 7 | 退出对话 | t ui ch u d ui h ua | 70 | 255 |
| 8 | 终止对话 | zh ong zh ix d ui h ua | 70 | 255 |
| 9 | 切换壁纸 | q ie h uan b i zh ix | 70 | 255 |
| 10 | 条亮屏幕 | t iao l iang p ing m u | 70 | 255 |
| 11 | 条暗屏幕 | t iao aa an p ing m u | 70 | 255 |
| 12 | 屏幕条到最亮 | p ing m u t iao d ao z ui l iang | 70 | 255 |
| 13 | 屏幕条到最暗 | p ing m u t iao d ao z ui aa an | 70 | 255 |
| 14 | 屏幕条到百分之十 | b ai f en zh ix sh ix | 70 | 254 |
| 15 | 屏幕条到百分之二十 | b ai f en zh ix ee er sh ix | 70 | 255 |
| 16 | 屏幕条到百分之三十 | b ai f en zh ix s an sh ix | 70 | 255 |
| 17 | 屏幕条到百分之四十 | b ai f en zh ix s iy sh ix | 70 | 255 |
| 18 | 屏幕条到百分之五十 | b ai f en zh ix uu u sh ix | 70 | 255 |
| 19 | 屏幕条到百分之六十 | b ai f en zh ix l iu sh ix | 70 | 255 |
| 20 | 屏幕条到百分之七十 | b ai f en zh ix q i sh ix | 70 | 255 |
| 21 | 屏幕条到百分之八十 | b ai f en zh ix b a sh ix | 70 | 255 |
| 22 | 屏幕条到百分之九十 | b ai f en zh ix j iu sh ix | 70 | 255 |
| 23 | 屏幕条到百分之一百 | b ai f en zh ix ii i b ai | 70 | 255 |
| 24 | 屏幕条到百分之百 | b ai f en zh ix b ai | 70 | 254 |
| 25 | 打开屏幕 | d a k ai p ing m u | 70 | 255 |
| 26 | 关闭屏幕 | g uan b i p ing m u | 70 | 255 |
| 27 | 切换灯效 | q ie h uan d eng x iao | 70 | 255 |
| 28 | 切换氛围灯 | q ie h uan f en uu ui d eng | 70 | 255 |
| 29 | 打开氛围灯 | d a k ai f en uu ui d eng | 70 | 255 |
| 30 | 关闭氛围灯 | g uan b i f en uu ui d eng | 70 | 255 |
| 31 | 灯光条亮一点 | d eng g uang t iao l iang ii i d ian | 70 | 255 |
| 32 | 灯光条暗一点 | d eng g uang t iao aa an ii i d ian | 70 | 255 |
| 33 | 灯光条到最亮 | d eng g uang t iao d ao z ui l iang | 70 | 255 |
| 34 | 灯光条到最暗 | d eng g uang t iao d ao z ui aa an | 70 | 255 |
| 35 | 灯光条到百分之十 | d eng g uang sh ix | 255 | 254 |
| 36 | 灯光条到百分之二十 | d eng g uang ee er | 255 | 255 |
| 37 | 灯光条到百分之三十 | d eng g uang s an | 255 | 255 |
| 38 | 灯光条到百分之四十 | d eng g uang s iy | 255 | 255 |
| 39 | 灯光条到百分之五十 | d eng g uang uu u | 255 | 255 |
| 40 | 灯光条到百分之六十 | d eng g uang l iu | 255 | 255 |
| 41 | 灯光条到百分之七十 | d eng g uang q i | 255 | 255 |
| 42 | 灯光条到百分之八十 | d eng g uang b a | 255 | 255 |
| 43 | 灯光条到百分之九十 | d eng g uang j iu | 255 | 255 |
| 44 | 灯光条到百分之一百 | d eng g uang ii i | 255 | 255 |
| 45 | 灯光条到百分之百 | d eng g uang b ai | 255 | 254 |
| 46 | 换一个音效 | h uan ii i g e ii in x iao | 70 | 255 |
| 47 | 音效切换为音乐 | q ie h uan uu ui ii in vv ve | 70 | 255 |
| 48 | 音效切换为游戏 | q ie h uan uu ui ii iu x i | 70 | 255 |
| 49 | 音效切换为电影 | q ie h uan uu ui d ian ii ing | 70 | 255 |
| 50 | 音效切换为自定义 | q ie h uan uu ui z iy d ing ii i | 70 | 255 |
| 51 | 换一个变声 | h uan ii i g e b ian sh eng | 70 | 255 |
| 52 | 变声为原声 | b ian sh eng uu ui vv van sh eng | 70 | 255 |
| 53 | 打开麦克风 | d a k ai m ai k e f eng | 70 | 255 |
| 54 | 关闭麦克风 | g uan b i m ai k e f eng | 70 | 255 |
| 55 | 接听电话 | j ie t ing d ian h ua | 70 | 255 |
| 56 | 拒接电话 | j v j ie d ian h ua | 70 | 255 |
| 57 | 音量条大 | ii in l iang t iao d a | 70 | 255 |
| 58 | 大声一点 | d a sh eng ii i d ian | 70 | 255 |
| 59 | 提高音量 | t i g ao ii in l iang | 70 | 255 |
| 60 | 声音太小了 | sh eng ii in t ai x iao | 70 | 255 |
| 61 | 音量条小 | ii in l iang t iao x iao | 70 | 255 |
| 62 | 小声一点 | x iao sh eng ii i d ian | 70 | 255 |
| 63 | 降低音量 | j iang d i ii in l iang | 70 | 255 |
| 64 | 声音太大了 | sh eng ii in t ai d a | 70 | 255 |
| 65 | 播放下一个 | b o f ang x ia ii i g e | 70 | 255 |
| 66 | 接通电话 | j ie t ong d ian h ua | 70 | 255 |
| 67 | 接听来电 | j ie t ing l ai d ian | 70 | 255 |
| 68 | 接通来电 | j ie t ong l ai d ian | 70 | 255 |
| 69 | 挂掉来电 | g ua d iao l ai d ian | 70 | 255 |
| 70 | 挂掉电话 | g ua d iao d ian h ua | 70 | 255 |
| 71 | 挂断电话 | g ua d uan d ian h ua | 70 | 255 |
| 72 | 播放音乐 | b o f ang ii in vv ve | 70 | 255 |
| 73 | 暂停播放 | z an t ing b o f ang | 70 | 255 |
| 74 | 停止播放 | t ing zh ix b o f ang | 70 | 255 |
| 75 | 暂停音乐 | z an t ing ii in vv ve | 70 | 255 |
| 76 | 停止音乐 | t ing zh ix ii in vv ve | 70 | 255 |
| 77 | 增大音量 | z eng d a ii in l iang | 70 | 255 |
| 78 | 增加音量 | z eng j ia ii in l iang | 70 | 255 |
| 79 | 条高音量 | t iao g ao ii in l iang | 70 | 255 |
| 80 | 条大音量 | t iao d a ii in l iang | 70 | 255 |
| 81 | 减小音量 | j ian x iao ii in l iang | 70 | 255 |
| 82 | 条低音量 | t iao d i ii in l iang | 70 | 255 |
| 83 | 条小音量 | t iao x iao ii in l iang | 70 | 255 |
| 84 | 播放上一首 | b o f ang sh ang ii i sh ou | 70 | 255 |
| 85 | 播放上一曲 | b o f ang sh ang ii i q v | 70 | 255 |
| 86 | 切换上一首 | q ie h uan sh ang ii i sh ou | 70 | 255 |
| 87 | 切换上一曲 | q ie h uan sh ang ii i q v | 70 | 255 |
| 88 | 播放下一首 | b o f ang x ia ii i sh ou | 70 | 255 |
| 89 | 播放下一曲 | b o f ang x ia ii i q v | 70 | 255 |
| 90 | 切换下一首 | q ie h uan x ia ii i sh ou | 70 | 255 |
| 91 | 切换下一曲 | q ie h uan x ia ii i q v | 70 | 255 |
13. 初版移植验证记录
以下保留 2026-10-30 10:08 完成的初版移植、PC 测试与构建记录。报告保存于 `/out/`,绑定各自测试时的源码快照;后续修改后的验证另见第 15 节,不能将旧报告的源码哈希视为当前源码。PC 耗时不作为板端性能数据。
| 项目 | 当前记录 |
| — | — |
| shell 参数 | 已按代码核对:start / stop / status / list [0..9] / mode all或wake / front raw或ns或agc或aec或3a / test 路径;所有启动/停止异步 |
| WAV/PCM 文件格式与路径限制 | 已按代码核对:16k S16LE WAV/PCM、32MiB、路径<64字节、AEC要求MIC/REF双声道WAV,详见1.3 |
| ATS 默认前端 | raw;独立 WebRTC VAD 只报告状态。其他前端为CPU NLMS/Wiener/AGC,详见第7节 |
| 应用状态机 | ID1/2开8秒窗口、有效接受事件刷新、ID5~8关闭,窗口外事件只计 suppressed;未连接业务动作 |
| 固定资源校验 | 473142 B 内置数组与原 `et_config/weights.bin` 逐字节一致;实际 SDK 与根资源 11 个关键文件逐字节一致,哈希见下文 |
| PC 真实音频回放 | `out/soundbox_port/final_audio/report.json`:3个原包16k单路PCM完整运行;长文件9715118 B、303.597 s、110个事件,无逐句标签,不报准确率 |
| PC 有标签合成语音 | `out/soundbox_port/labelled_tts_v2/report.json`:9条正例各正确输出1次、1条负例无事件;单一Huihui合成声音,详见下表 |
| 有标签准确率/误唤醒率 | 未建立完整独立数据集,当前无可报告的总体指标 |
| runtime host 边界验证 | `out/soundbox_asr_261030/runtime_host_v2/report.json`:44场景、10788断言通过;执行冻结的生产runtime,RTOS/FS/ADC/core/frontend为边界替身 |
| 采集 adapter host 验证 | `out/soundbox_asr_261030/capture_host_v2/report.json`:41422断言通过;执行生产采集adapter,覆盖旧所有者和新owner6/7、单双路及溢出;HAL/RTOS为替身 |
| 前端 host 验证 | `out/soundbox_asr_261030/frontend_host_v3/report.json`:6场景、168854断言通过;执行真实WebRTC VAD、保护NLMS、NS和AGC,包含分块连续性/重置/合成声学信号 |
| Cortex-M33 核心编译 | `out/soundbox_port/m33/report.json`:text40556 B、rodata494470 B、data0、bss1943 B;32个源文件均以现有M33工具链编译,另需动态工作区78336 B |
| Cortex-M33 前端编译 | `out/soundbox_asr_261030/frontend_m33_v2/report.json`:使用实际Zephyr选项;最大单函数静态栈168 B,工作区见第9节,不代表完整调用栈 |
| 开发板实时测试 | 待用户实板运行:处理时长、丢帧、真实识别及前端效果 |
| 整机固件构建/归档 | `out/soundbox_asr_261030/fullbuild/report.json`:完整构建退出0、218.891秒,生产源码构建前后SHA一致;固件与链接占用见13.5 |
13.1 资源与构建边界
模型字节 SHA256:
```text
9af7dcddc576a3fda7dbd7b06dcb22396dbdf79932b337a97b5e7bbd0160ab3d
```
该值覆盖合计 473142 B 的两个模型段,不是文本 C 文件本身的哈希。`out/soundbox_port/core_release_report.json` 记录了核心 C/H 清单、两段大小、模型标识、工作区和试用限制。整机 CMake 为确保算法优化选项作用于实际 `app` 目标还做了集成调整,最终 CMake、编译命令和固件哈希以 `fullbuild` 报告为准。
`CONFIG_APP_SOUNDBOX_ASR` 在 `ats3089p_dev_watch` 默认启用,依赖 `APP_ASR_KWS`、`APP_VAD`、`APP_USB_SERIAL`、FPU/FPU_SHARING 和 DVFS,模拟器不启用。音箱模块以 C/H 和 const 权重编译,不链接实际 AC7016 SDK 的 `libetasr.a`。本轮没有新增运行时 bin 模型加载器;更换内置模型必须同步更新全部配套资源后重新编译。
采集 adapter 的 PA 回采验证目前限于源代码寄存器位语义与 host adapter。已将 ADC1 输入清除使用的位移常量修正为对应 MASK,避免先开 MIC 再切 PA 时留下另一路输入使能位;没有把这项检查当作硬件 PA 回采已经通过。
13.2 有标签合成语音回归
使用 Windows `Microsoft Huihui Desktop`、中文、rate 0 生成音频,转换为 16 kHz 单声道 S16LE,逐条用同一最终 host 可执行文件运行。没有用这些样本调整模型或门限。
| 预期文字 | 预期 ID | 最终输出 ID | 次数 | 分值 |
| — | —: | —: | —: | —: |
| | 1 | 1 | 1 | 254 |
| 嗨 | 2 | 2 | 1 | 155 |
| 播放音乐 | 72 | 72 | 1 | 254 |
| 暂停音乐 | 75 | 75 | 1 | 254 |
| 增大音量 | 77 | 77 | 1 | 248 |
| 减小音量 | 81 | 81 | 1 | 255 |
| 播放下一首 | 88 | 88 | 1 | 253 |
| 打开屏幕 | 25 | 25 | 1 | 254 |
| 对话结束 | 5 | 5 | 1 | 251 |
| 今天天气很好我们去公园散步 | 无命令 | 无事件 | 0 | — |
这些结果说明固定资源、移植计算、独立唤醒事件与词表映射在这 10 条合成输入上能连通。样本数量少且只有一个合成声音,不能将“9/9 正例”写成真人识别准确率或 91 词全量通过率;一条负例也不足以估计误唤醒/小时。
最终 host 可执行文件 SHA256 为 `2010f4894a51520083ae96da9189fd49f74a69213484a8d563b99b25c0dc4cc4`。每条输入的哈希、事件、分数及音频位置均在 `labelled_tts_v2/report.json`;其中 `audio_ms` 为处理到的音频位置,并非说完话后的墙钟等待时间。
13.3 前端数值结果及含义
理想合成回声用例的 AEC ERLE 为 82.59 dB;双讲用例的近端误差为 -26.27 dB。合成白噪声经 NS 衰减 4.26 dB,测试音调振幅比为 0.98975。它们用于检查算法计算与流式状态,没有覆盖实际扬声器非线性、参考延迟漂移、房间混响或真实噪声分布,不能作为开发板声学性能保证。
13.4 runtime 边界测试复现
在 `/` 下执行,输出目录使用未存在的新名称,防止覆盖旧报告:
```powershell
python application/bt_watch/tests/soundbox_runtime/run_tests.py –output-dir out/soundbox_asr_261030/runtime_host_rerun_01
```
脚本使用本工程 `out/offline_translate/board_paged_pretrained_route/pwb1_tools/ziglang/zig.exe`,冻结真实 runtime、头文件和测试源码后以 `-Wall -Wextra -Werror` 编译并执行。编译日志、输出、源哈希和报告均进入指定 out 目录。工具链不在时需先提供该 Zig 路径。
44 个场景覆盖请求取消、短锁冲突、正返回值不停止监听、停止后晚到事件、溢出重置、1.5秒无DMA超时、ADC被其他功能占用、释放失败重试、3处内存申请失败、16字节对齐申请、核心/前端错误、唤醒窗口与tick回绕、48ms分组预算、短读与错误WAV/PCM/路径、文件关闭和存储租约。它执行真实生产控制逻辑,但使用确定性调度与边界替身;未证明实际抢占时序、实板内存容量、神经网络准确率或物理PA路由。
13.5 初版整机构建与固件归档
本轮完整构建命令,在 `/` 下执行:
```powershell
cmd /c build.cmd -b ats3089p_dev_watch -a bt_watch
```
2026-10-30 10:05:19 开始、10:08:58 完成,共 218.891 秒,退出码 0;构建过程中生产源码哈希未变化,最终配置启用了 `CONFIG_APP_SOUNDBOX_ASR=y`。完整日志和源哈希清单位于 `out/soundbox_asr_261030/fullbuild/`。
| 链接区域 | 已占用 B | 区域容量 B |
| — | —: | —: |
| FLASH | 4489188 | 7041024 |
| SRAM | 932608 | 932864 |
| PSRAM | 16762144 | 16777216 |
| SHARE | 20948 | 20991 |
这些是整机链接区域占用,包含已配置的堆、栈和其他业务预留,不能用区域容量减占用来代表运行时资源堆可分配空间。本轮完成了构建,尚未在硬件上测得 soundbox 会话实际峰值内存和实时耗时。
`out/soundbox_port/firmware_elf_audit.json` 从最终 ELF 中提取 `et_lang1_weights_buf`,确认位于只读 Flash 地址 `0x1032d4b8`、长度 473142 B,字节哈希与第13.1节相同;最终链接没有原 `libetasr.a`。ELF SHA256:
```text
8903545acba7aded533b39378b3f1fc5953330195137b3d6d592a185a0c6ba81
```
初版构建产物当时统一放在 `application/bt_watch/outdir/ats3089p_dev_watch/_firmware/`;该目录中同日文件会随本次修正更新。初版固件、manifest 和源码已快照到 `out/soundbox_realtime_fix_261030/baseline_1008/`,以下为初版大小:
| 文件 | 大小 B | 用途 |
| — | —: | — |
| `ats3089p_dev_watch_261030.fw` | 26591232 | 当日普通固件包 |
| `ats3089p_dev_watch_261030_debug.fw` | 12157952 | 当日调试固件包 |
| `ota_firmware.bin` | 2868224 | 当前 OTA 镜像 |
| `ota_firmware_261030.bin` | 2868224 | 同一 OTA 镜像的日期归档 |
目录内同步保存本轮 manifest 与 SHA256 清单,校验时以清单中的完整哈希为准。本轮未自动烧录或升级开发板。
14. 文件职责与后续扩展
| 路径 | 职责 |
| — | — |
| `tools/soundbox_ASR_wakeup/` | 用户提供的原推理代码、导出资源及音频调试工具 |
| `tools/soundbox_ASR_wakeup/26-5-28-pixel_bar_7016/` | 实际配套 AC7016 SDK,参考采集、AEC参考与应用流程 |
| `src/soundbox_asr/vendor/` | 从原代码选取的 C/H 与配套资源,按 ATS 工具链源码编译 |
| `src/soundbox_asr/soundbox_core.h` | 单实例算法接口、事件、模型与性能诊断 |
| `src/soundbox_asr/soundbox_runtime.c/.h` | 异步线程、MIC/文件会话、前端、8秒窗口和资源生命周期 |
| `src/soundbox_asr/frontend/sb_frontend.c/.h` | CPU NLMS/Wiener/AGC及只报告状态的 WebRTC VAD |
| `tests/soundbox_runtime/run_tests.py` | 真实运行时源码的RTOS/文件/算法边界回归,日志与快照写入out |
| `src/asr/kws_capture.c/.h` | 共享 ADC 的所有权、DMA ring、溢出通知和采集统计 |
| `src/main/system_app_shell.c` | 板端命令入口,最终注册以集成源码为准 |
| `src/launcher/soundbox_asr_view.c/.h` | 触摸启停、按 ID 显示中文、异步页面请求及低频刷新 |
| `SOUNDBOX_ASR_README.md` | 使用、算法原理、来源、91词表及验证记录 |
后续优化先建立同音频基线和实板录音样本,再调整阈值、前端或计算内核。新增关键词、换模型、修改特征参数或接入新的降噪网络,都应重新验证识别与误触发情况。文件更换方式若后续增加外部 bin,需定义模型格式、版本、长度、校验和成套配置约束,不能将当前内置资源数组直接视为通用模型加载器。
15. 实板实时预算问题与本次修正
15.1 为什么启动成功、有波形,却没有识别事件
`log_26_10_26.txt` 中 2026-10-30 10:24:12 的状态显示:
```text
samples=508608 blocks=2649 gaps=15 dropped=4608
queue_peak=16384/16384
process_us=69556 peak_us=72051 over48ms=662
batch48_us=70389 batch48_peak_us=72778
seq=0 raw_events=0 trial_count=0 core_frames=662
mic_peak=157 speech=0 front=raw
```
当时 CPU 已在 187 MHz 档位。一组 48 ms 输入需要 70.389 ms 计算,处理时间是音频时间的 1.466 倍;只计算这部分,吞吐就至少需要提升约 46.6%,或耗时缩短约 31.8%,才刚好赶上输入,还没有给采集、调度等其他开销留余量。这是独立 HOSC TIMER2 的墙钟时间,不能再除以 CPU/HOSC 频率比,详见第 9 节。
`queue_peak=16384/16384` 说明 ring 曾经装满,`dropped=4608` 和 `gaps=15` 确认已经实际丢样并重置流式状态。持续积压会反复打断网络上下文与解码路径,所以“已启动、有输入”仍可能长期没有事件。扩大 ring 只能延迟溢出,不能补足持续吞吐差额;继续跨缺口解码也会把不连续波形当成同一句话。本次保留溢出后重置算法的规则。
这里 `trial_count=0`,没有证据表明本次零结果由原厂试用次数耗尽导致。`mic_peak=157` 只描述查询前最近 192 个采样、约 12 ms 的峰值,不能据此推断此前整句讲话都过小;`speech=0` 是该块外部 VAD 状态,在 `raw` 模式不会阻断模型推理。修正后增加会话累计峰值/RMS,避免用一次静音瞬间误判整段采集。
15.2 运算热点与位精确优化
基线矩阵调用统计保存在 `out/soundbox_realtime_fix_261030/matrix_profile_v1/report.json`。以原始静音输入运行 100 个网络帧,平均每 48 ms 调用矩阵函数 3568 次,执行其中的 INT8 MAC 共 643896 次;尚未计入 attention 标量点积、FFT、PCEN、混合精度补偿及其他操作。大量 `1×N` 调用和逐行权重拷贝是本次直接处理的热点。
本次改动保持原量化数值规则:
– Cortex-M33 路径用 `SXTB16` 扩展有符号 INT8,再用 `SMLAD` 一次累计两路乘积;四行矩阵共享输入向量的读取与扩展,减少重复加载和标量指令。
– linear 对 CPU 可寻址的只读 Flash 权重直接执行整块矩阵,去掉逐行预取、临时工作区申请及大量单行调用;卷积继续复用同一个矩阵内核。
– 保留原 INT32 累加、量化后处理、维度与尾部元素规则;模型权重、词表和阈值均未改变。非 M33 路径保留等价的可移植实现。
对当前源码使用同样 100 帧输入重新计数,`matrix_profile_v2/report.json` 记录每 48 ms 矩阵函数调用从 3568 次降至 132 次,INT8 MAC 仍为 643896 次。该结果确认了调用合并,没有减少原网络需要的运算;计数也不代表板端时间。
`matmul_tests/report.json` 记录 host 12481 个数值测试,以及 Unicorn 执行实际 Cortex-M33 机器码的 990 个测试,均与基线逐元素相同。覆盖的 8 类真实形状中,基线与优化后动态指令数量之比约为 1.88–2.05。这是执行指令数量的比较,没有模拟 Flash/PSRAM 等待、中断和整机调度,不能换算为相同比例的实板耗时或作为 48 ms 达标证明。
`audio_equivalence/report.json` 使用 15 段音频回归,包括前述 9 条有标签合成正例、负例及原包 PCM,共比较 120 个事件;ID、分值、音频位置与中文名称均与初版一致。加入下节 ASCII 标签后,当前 Cortex-M33 核心 text 为 40956 B、rodata 496562 B、data 0、bss 1943 B;核心工作区仍为 78336 B。以上报告均在 `out/soundbox_realtime_fix_261030/`。
15.3 输入诊断与 ASCII 串口输出
只有 ADC 领取成功后才打印 `started MIC`;单纯 `start` 请求入队不会打印该行。运行期间每约 5 秒打印一次采样进度及会话累计输入:
```text
[soundbox] started MIC rate=16000 channels=1 hop=192 batch=768 front=raw; say a listed command
[soundbox] listening samples=… queue_peak=…/… dropped=…
[soundbox] input peak_max=… rms_max=… speech_blocks=… gaps=… batch48_us=… peak_us=…
[soundbox] event id=77 score=… text=increase_volume audio_ms=…
```
上面带 `…` 的行只说明字段格式,不是实板测量结果。`peak_max` 是本次会话 MIC 最大绝对峰值,`rms_max` 是最大块 RMS;`status` 还保留最近块的 `input_rms`。静音块不会覆盖累计最大值。`speech_blocks` 统计外部 VAD 判为人声的块数,`zero_samples/clipped_samples` 统计 MIC 的零值和满幅采样;AEC 双路中的 REF 不混入 MIC 指标。
新会话启动时清零累计诊断,采集溢出只重置不连续的算法与未完成预算组,不清除此前输入峰值、人声块与零值/削顶计数。若最近完整计算组仍超过 48000 us,每 5 秒最多打印一次:
```text
[soundbox] realtime overrun: compute=… us > audio=48000 us; continuous recognition cannot keep up
```
该提示用于区分“算法未识别”与“处理持续跟不上”。`queue_peak` 是本次采集的历史最高占用,达到容量后不会自行下降;判断新固件是否仍在丢样,应比较多次 `gaps/dropped` 是否继续增加,并观察计算组耗时。
串口 `event`、`status` 的文字及 `list` 全部使用 `sb_core_phrase_ascii(id)` 的 91 项英文标签,例如 `play_music`、`increase_volume`。原 `sb_core_phrase(id)` 和核心事件的中文名称保持不变,用于 PC 回归或后续 UI;runtime 根据 ID 转成英文后再打印、保存公开状态。该改动不改变模型、命令 ID、音素、阈值或试用次数,也不代表模型能识别英文。中英文映射均由 `soundbox_commands.c` 提供,非法 ID 返回空字符串。
15.4 新增边界测试
本轮最终报告与源码快照位于:
| 报告 | 结果与范围 |
| — | — |
| `out/soundbox_realtime_fix_261030/runtime_ascii_v1/report.json` | 51 场景、13178 断言;执行真实 runtime,新增最大峰/RMS、静音/溢出保留、新会话清零、MIC/REF分离、启动提示及限频超预算日志;核心回调携带中文时,串口和公开状态仍为 ID 77 的 `increase_volume` |
| `out/soundbox_realtime_fix_261030/shell_ascii_v1/report.json` | 75 命令案例、1117 断言;执行真实 handler、注册行和生产词表;验证 91 项英文非空、ASCII、长度安全、非法 ID,以及全部分页、状态、错误提示的格式化结果无非 ASCII 字节 |
runtime 测试仍使用确定性 RTOS/文件/ADC/算法边界替身;shell 测试替换业务请求,仅验证真实参数分派与格式化输出。它们覆盖本次行为回归,不证明硬件实时性、真实采集音量、模型真人准确率或完整调用栈峰值。第 13 节保留的是初版历史,不能把旧报告中的源文件哈希视为当前源码。
15.5 升级后的实板验收
先停止其他麦克风功能,用默认 `raw/all` 模式逐项确认:
```text
app soundbox stop
等待 status 显示 busy=0
app soundbox mode all
app soundbox front raw
app soundbox start
app soundbox status
```
1. 必须先看到 `started MIC`,再连续观察 30–60 秒的 `listening`;若 ADC 启动失败,先解决该错误。
2. 保持常态 `batch48_us < 48000`,同时查看峰值与 `over48ms`,确认 `gaps/dropped` 不持续增长。单次恰好低于 48 ms 没有余量,不能作为稳定实时验收。
3. 对板说“增大音量”,预期为 `event id=77 … text=increase_volume`。比较讲话前后的累计 `peak_max/rms_max/speech_blocks`,避免只看查询瞬间的 `mic_peak/speech`;`score` 仍是原分值,不是百分比。
4. 若有输入但没有事件,先用第 1.3 节的 `play.wav` 回放检查模型路径,预期为 `id=72 … text=play_music`;文件通过后,再针对 MIC 录音、距离、噪声和口音排查。文件回放通过不能代替实时采集达标。
5. 停止并重新启动应重置本次输入统计。持续识别仍受第 11 节说明的原试用次数约束,不应通过反复重置规避限制。
只有新版实板日志才能确认优化后的实际时间预算与拾音结果。本次 PC 的 9 条合成正例回归及矩阵位精确测试不构成真人准确率,也不等于 91 条命令已逐条完成实板验收。
15.6 实时优化版固件与最终链接验证(触摸页前)
2026-10-30 10:44:12–10:45:13 完成整机构建,耗时 60.562 秒,退出码 0;版本为 **`1.00_2610301045`**。`out/soundbox_realtime_fix_261030/fullbuild/report.json` 记录构建前后生产源文件哈希一致,并保存编译日志。当前链接占用:
| 链接区域 | 已占用 B | 区域容量 B |
| — | —: | —: |
| FLASH | 4492156 | 7041024 |
| SRAM | 932608 | 932864 |
| PSRAM | 16762144 | 16777216 |
| SHARE | 20948 | 20991 |
这些是整机静态链接区域占用,包含预留池,不能将容量差额直接视为会话运行时可分配的全部内存;实板 soundbox 峰值内存和调度时间仍需验证。
`out/soundbox_realtime_fix_261030/firmware_elf_audit.json` 审计最终 `zephyr.elf`:`matrix_hw1` 的 646 B 机器码与执行过 990 个位精确测试的 Cortex-M33 测试 ELF 逐字节一致,包含 `SXTB16/SMLAD`;473142 B 模型位于只读 Flash `0x1032dec4`,模型字节 SHA256 与第 13.1 节一致,最终链接不依赖原 `libetasr.a`。当前 ELF SHA256:
```text
c8f0a107bf7aff97e766c4a161741d9adda5d70d472801525d9026cef0dcf116
```
该次构建文件统一归档到 `application/bt_watch/outdir/ats3089p_dev_watch/_firmware/`,当时同日文件对应上述版本;触摸页加入后同名文件会更新,最新版本见第 16 节:
| 文件 | 当前大小 B | 用途 |
| — | —: | — |
| `ats3089p_dev_watch_261030.fw` | 26594304 | 当前普通固件包 |
| `ats3089p_dev_watch_261030_debug.fw` | 12161024 | 当前调试固件包 |
| `ota_firmware.bin` | 2869760 | 当前 OTA 原名 |
| `ota_firmware_261030.bin` | 2869760 | 同一 OTA 内容的日期归档 |
第 13.5 节的 10:08 初版固件及清单已备份至 `out/soundbox_realtime_fix_261030/baseline_1008/`;本节 `1.00_2610301045` 版本在加入触摸页前备份至 `out/soundbox_ui_261030/baseline_1045/`。两版旧大小与旧 ELF 哈希只作历史记录,当前归档按第 16 节及同目录 manifest/SHA256 清单校验。升级由用户自行处理,没有自动烧录。
16. soundbox ASR 触摸页面
16.1 触摸入口与监听控制
在开发板打开 **更多 → soundbox ASR**,页面标题固定为 `soundbox ASR`。打开页面不会自动启动麦克风;点击“启动监听”后,先显示“正在启动,可点击取消”,ADC 成功开启后显示“正在监听,请说中文命令”。对板说“增大音量”,识别事件 ID 77 对应的中文“增大音量”会显示在页面中央。
点击“关闭监听”会异步请求停止,显示“正在关闭监听,请稍候”;等待资源释放完成后,可再次启动。启动尚未完成时也能点击“关闭监听”取消请求;停止期间按钮禁用,避免重复启动。若麦克风被 DOA、录音、通话等功能占用,页面提示关闭其他录音后重试;资源不足或音频超时同样显示可操作的中文提示,数值错误继续留在串口。
返回、隐藏、失焦或关闭页面都保持当前监听状态,页面底部明确显示“返回不停止监听”。需要停止时应点击“关闭监听”,或执行 `app soundbox stop`。页面重新打开后会显示现有服务状态和最近识别结果;停止后保留最后中文结果,下一次新会话启动后重新等待命令。
16.2 与串口模式和中文输出的关系
页面启动按钮只在服务空闲时设置 `mode=all`,无需先说唤醒词;保留用户原有 `front` 选择,不强行改成 raw。若服务已由串口以 `mode=wake` 启动,打开页面不会改变正在运行的模式,仍须按第 1.2 节先唤醒。需要改为页面默认的全部词模式,可先停止,再通过页面按钮重新启动。
屏幕用 `sb_core_phrase(event_id)` 按原 ID 查询中文;不会直接显示公开状态中供串口使用的 ASCII `phrase`。因此同一次 ID 77 事件,屏幕显示“增大音量”,串口继续输出 `text=increase_volume`。原 91 项中文、音素、阈值与模型均保持一致,屏幕中文显示不扩展识别范围。
串口也可以显示或隐藏页面:
```text
app soundbox show
app soundbox hide
```
这两个命令只提交 GUI 请求,不启动或停止监听;请求成功返回不代表页面已经获得焦点。来电、弹窗或其他前台应用会使显示请求被拒绝或等待超时,不应为了打开识别页而退出其他业务。触摸返回同样只退出本页。
16.3 刷新与线程边界
新增 `src/launcher/soundbox_asr_view.c/.h`。show/hide 通过异步 GUI 消息处理,页面栈与 LVGL 对象均由 GUI 线程操作。识别继续在原独立工作线程运行,页面不执行网络推理、不读取模型文件、不直接操作 ADC。
页面有焦点时每 200 ms 读取一次短状态快照,仅在文字或按钮状态变化时更新控件;失焦后暂停定时器,不重复重绘整页。布局按 466 圆屏安全区域安排,中文识别结果使用大字、长词自动换行,小屏按实际分辨率缩放;大字字体打开失败时回退普通中文字体。界面仅显示识别文字、状态和操作,不显示堆、模型大小、频率、丢帧等开发指标。
用户已确认前一版 soundbox 麦克风识别可用;本节新增的屏幕布局、真实触摸及页面打开时的实时余量仍需在新版实板验收,不能用 PC 边界测试或前一版识别结果替代。
16.4 页面、串口和中文字库验证
| 报告 | 结果与范围 |
| — | — |
| `out/soundbox_ui_261030/host_v2/report.json` | 33 场景、3283 断言;执行真实页面 C,覆盖异步 show/hide、过期消息和超时、来电/弹窗保护、启停与启动取消、停止中禁用、打开/返回不改监听、91 项中文 ID 映射、各分配/字体/定时器失败清理与大字回退;状态不变连续 1000 次 200 ms 定时回调,新增 label/style 写入均为 0 |
| `out/soundbox_ui_261030/font_coverage_final.json` | 检查实际板端 `/NAND:C/vfont.ttf` 与固件包字体,页面文案及原词表合计 155 个字符、其中 143 个中文字符均有字形,无缺字;32 px 结果字体最长原词名义宽约 288 px,容器宽 340 px |
| `out/soundbox_ui_261030/shell_host/report.json` | 含 UI 配置的实际 Shell handler/注册/词表:87 命令案例、1199 断言,包含 show/hide 分派 |
| `out/soundbox_ui_261030/shell_no_ui/report.json` | 无 UI 配置:79 命令案例、1141 断言,show/hide 不引用页面实现,返回不可用而不影响原监听命令 |
`out/soundbox_ui_261030/preview/` 保存 ID 77 和 ID 23 的软件预览,已检查中文结果与按钮布局没有溢出。这些图片按实际字体和页面坐标生成,不是实板 LCD 截图,也没有执行真实 LVGL 字体缓存和显示驱动。页面测试对 RTOS、LVGL 和服务快照使用边界替身;升级后仍应触摸测试启动、讲话显示“增大音量”、关闭、重新启动、返回保持监听,并确认新增页面不会使实时音频持续丢样。
16.5 当前触摸页固件与归档
2026-10-30 11:32:59–11:37:02 完成整机构建,耗时 242.5 秒,退出码 0,版本为 **`1.00_2610301137`**。`out/soundbox_ui_261030/fullbuild/report.json` 记录构建前后生产源文件哈希一致;当前静态链接区域占用如下:
| 链接区域 | 已占用 B | 区域容量 B |
| — | —: | —: |
| FLASH | 4495404 | 7041024 |
| SRAM | 932608 | 932864 |
| PSRAM | 16762272 | 16777216 |
| SHARE_RAM | 20948 | 20991 |
这些数字包含整机预留的资源池,不是 soundbox 页面运行时的堆余量,也不能直接用容量差额判断尚能分配多少内存。当前 `zephyr.elf` SHA256:
```text
bb85c967a580ba1e46f72827411af0370b1f164a382b9c772adb783040f81dfd
```
最新固件统一归档到 `application/bt_watch/outdir/ats3089p_dev_watch/_firmware/`:
| 文件 | 当前大小 B | 用途 |
| — | —: | — |
| `ats3089p_dev_watch_261030.fw` | 26597888 | 当前普通固件包 |
| `ats3089p_dev_watch_261030_debug.fw` | 12164608 | 当前调试固件包 |
| `ota_firmware.bin` | 2870784 | 当前 OTA 原名 |
| `ota_firmware_261030.bin` | 2870784 | 同一 OTA 内容的日期归档 |
同目录 `soundbox_asr_261030_manifest.json` 与 `soundbox_asr_261030_SHA256SUMS.txt` 已更新到本节版本;按清单中的实际哈希校验,不要套用第 13/15 节旧版本的 ELF 或固件大小。本次完成构建、归档与 PC 验证,没有自动烧录;升级后从“更多 → soundbox ASR”进入触摸验收。




