基于ATS3089P 离线语音识别控制音乐算法 # ATS3089P 离线语音控制音乐MFCC DTW本功能在 ATS3089P 上本地处理 MIC 音频识别“暂停音乐”和“播放音乐”两个关键词优先暂停/恢复已启动的内置铃声没有活动铃声时向已有 lcmusic应用发送明确的暂停/播放消息。它采用传统 MFCC特征与 DTW 模板匹配适合先验证小词表、少量说话人的离线控制流程。固件默认 **关闭监听**避免开机占用 ADC没有真实语音模板时app asr on返回未训练错误不会用随机数据触发音乐动作。可以直接在板上录入语音模板也可以在电脑训练后通过 U 盘复制模型无需联网。## 首次使用在板上录入两条指令先停止其他 MIC 录音、MIC 直通和 USB 麦克风功能并暂停扬声器播放以免把外放音乐录成模板。每次录入命令只采集一次语音说完后等待约 300 ms 静音看到 enrolled 和 microphone OFF 日志再执行下一次录入。textapp asr offapp asr clearapp asr enroll pause说暂停音乐等待 [kws] enrolled pause ... 和 microphone OFFapp asr enroll pause再次说暂停音乐等待日志app asr enroll play说播放音乐等待日志app asr enroll play再次说播放音乐等待日志app asr statusapp asr saveapp asr on每个关键词至少录入 **2 次**最多 4 次建议录 4 次并变化说话音量和距离。语音建议 0.41.2 秒、发音完整避免把两个指令连成一句。超过约 1.6 秒的有效语音特征会被拒绝避免用截断语音误判。录入命令启动后 10 秒没有有效语音会超时。每类达到至少 2 个模板后固件会尝试自动保存/NAND:/kws_model.bin也可以手动执行 save。### 录入没有完成时看哪些日志mfcc-continuous-v3 包含采集诊断及连续识别修复。执行 app asr status 可确认运行版本并查看最后一次采集的统计关闭 MIC 后统计仍保留。录入正常顺序是text[kws] enrollment requested: pause_music; wait for microphone ON, then speak[kws] microphone ON ...[kws] voice START modeenroll[kws] voice END; extracting template[kws] enrolled ...[kws] microphone OFF在 microphone ON 后再说话说完整句后保持安静等自动结束。等待期间每秒输出 enroll progressdma 是 DMA 回调次数received是跳过启动稳定时间后收到的采样数read 是工作线程取走的采样数peak是最近一块 PCM 的绝对峰值032768zero/clipped 是该 256 点块中零值/满幅点数energy_nano、gate_nano 是当前预加重能量和 VAD 阈值乘 10^9。voice、blocks、silence 分别表示语音进行中、当前语句块数、连续静音块数。| 现象 | 定位方向 || --- | --- || 没有 enrollment requested | 检查是否烧录本版固件、串口命令是否到达查看 shell 返回码 || microphone start failed | ADC 被其他录音/通话/USB 麦克风占用或打开/启动失败 || dma0、received0 | ADC/DMA 没有产生采集回调 || received 增长、peak0、zero256 | 收到了全零 PCM检查 MIC/模拟输入通路 || peak 随说话变化但没有 voice START | 对照能量与阈值检查声音大小和采集噪声 || 有 voice START没有正常结束 | 环境/外放噪声持续触发 VAD或语句过长 || dropped 增长、capture error | 采集缓冲溢出检查 CPU 调度和持续处理速度 |录入的 10 秒截止时间按墙钟检查即使持续报溢出也会超时并释放 MIC。失败会明确输出 enrollment timeout、enrollment failed 或utterance too long/noisy不会把失败当作模板录入成功。监听开启后可先用 app ringtone play 1 启动内置铃声或打开本地音乐应用、选择一首曲目先确认音乐播放功能正常再说两个指令。识别成功日志类似text[kws] HIT seq1 keyword暂停音乐 commandpause_music frames... distance_milli... second_milli...[kws] ACTION seq1 commandpause_music result0 (accepted); listening continuesHIT 在调用播放器前打印表示关键词识别已成功与播放器日志相互独立。ACTION result0 表示已接受内置铃声控制或已把请求放入本地音乐消息队列本地音乐应用执行时会检查当前曲目状态入队成功不表示一定已有歌曲。内置铃声已经处于目标状态时返回 -EALREADY日志注明already_in_target_state仍打印本次 HIT 并增加识别计数。status 的 last_error 记录识别/采集结果last_action 单独记录播放器结果。已启动包括暂停状态的 **内置铃声优先**暂停冻结旋律/PCM 的播放位置恢复继续该首铃声停止铃声后则针对**lcmusic 的当前曲目**暂停保留播放位置播放从该曲目保存的位置继续。它不控制手机播放器或 USB 声卡流。### 连续说多条指令执行一次 app asr on 后持续监听逐句说“暂停音乐”“播放音乐”即可。每句说完留约 300 ms 静音用于断句同一指令也可重复说都会独立打印 HIT。v3 移除了旧版在命中、拒识及超长语句后丢弃 1200 ms PCM 的冷却逻辑避免下一条语音在这段空档被整个丢掉。拒识后立即继续检测下一句。每 5 秒的 listen progress / LISTEN active 显示监听仍在运行每次断句打印 voice START、voice END。拒识详细日志包括| REJECT reason | 含义 || --- | --- || short_or_no_voice | 有效语音不足 20 帧或未提取到有效语音 || duration_mismatch | 当前有效帧数与所有模板的差均超过 DTW 带宽 24 帧 || distance_threshold | 距最近模板的距离超出类别/全局阈值 || ambiguous_keywords | 两类距离差不足 margin无法可靠区分 || invalid_features_or_model / untrained | 特征或模型无效或训练未完成 |同时打印候选词、有效帧数、最近/第二距离、类别/全局阈值及 margin数值均乘1000 后输出无可达候选时距离用大值表示。utterance too long/noisy表示有效语音超过容量或持续未断句丢弃当前语句后继续监听。扫频信号 5 本身会被 MIC 收入不能把这类声音识别成控制词测试连续语音时先用低音量的普通铃声 1再逐步测试实际使用音量及环境。## 板端串口命令| 命令 | 用途 || --- | --- || app asr on | 开启 MIC 监听要求每个关键词已有至少 2 个模板 || app asr off | 关闭监听并等待释放 ADC之后可使用正常录音 || app asr status | 查看模式、ADC 状态、模板数量、识别/拒识计数、丢样和最后错误 || app asr enroll pause | 采集一次“暂停音乐”模板 || app asr enroll play | 采集一次“播放音乐”模板 || app asr clear | 清空当前内存模型重新录入前先执行 off || app asr save | 保存当前完整模型到 /NAND:/kws_model.bin || app asr load | 从 /NAND:/kws_model.bin 加载并验证模型 || app asr test pause | 不经过识别直接测试内置铃声/当前本地音乐的暂停控制 || app asr test play | 不经过识别直接测试内置铃声/当前本地音乐的继续播放控制 |模型的清除/保存/加载要求 ASR 已关闭、ADC 已释放、设备不处于 U 盘模式。clear 清空 RAM 模板不立即删除 NAND 文件若需要永久替换重新录入后保存新模型或通过 U 盘删除旧 kws_model.bin。重启后首次使用 ASR 命令会尝试加载已保存模型但监听仍保持关闭需手动 on。## 为什么需要训练MFCC 只是把短时声音变成频谱包络特征不理解词义。DTW 需要已有关键词的特征模板才能比较一段新语音是更接近“暂停音乐”还是“播放音乐”。这里的训练是模板录入、代表样本选择和距离阈值估计不是训练大型神经网络。建议用开发板实际 MIC 录音录入计划使用的说话人、距离和环境。电脑麦克风或合成语音可以验证工具链但不能直接证明板上真人识别率。两词小模板方法更适合固定使用者若要覆盖很多人、方言、远场噪声需要扩大语料并评估后续可考虑 HMM 或小型神经网络分类器。## 算法原理与线程流程textMIC0 / ADC 16 kHz mono s16↓ DMA callback只复制 PCM 到私有环形缓冲KWS worker拼接连续 160 点10 ms块↓ 能量 VAD约 50 ms 前滚、约 300 ms 结束静音预加重 0.97 → Hamming 25 ms 窗/10 ms 步长↓ 512 点 FFT → 26 个 Mel 滤波器807600 Hz13 维特征c0 对数平均 Mel 能量 c1..c12 DCT-II↓ 按语句做 CMN每维减均值DTW 对齐与两类各 24 条模板比较24 帧带宽↓ 全局/类别距离门限 两类距离 margin通过异步音乐消息未通过打印拒识不操作播放器采集回调不计算 MFCC、不访问文件、不调用播放器。工作线程处理 VAD、特征、分类和音乐消息模型保存/加载在互斥保护下执行。约 300 ms 结束静音界定每句识别或拒识后不额外丢弃 PCM。录音丢样、超长语音、静音、坏模型会拒绝当前语句。MFCC 与 DTW 的具体参数、模型数组布局和误差测试见[tools/asr/README.md](tools/asr/README.md) 和[src/asr/README.md](src/asr/README.md)。## 电脑训练和 NAND 模型更新准备 WAV 目录文件必须是单声道、16-bit PCM、16000 Hz每类至少 2 条。训练集、未知词校准集和最终测试集应分别采集textdataset_train/pause/*.wav “暂停音乐”dataset_train/play/*.wav “播放音乐”dataset_unknown/*.wav 其他词、环境噪声dataset_test/pause/*.wav 未参与训练的“暂停音乐”dataset_test/play/*.wav 未参与训练的“播放音乐”dataset_unknown_test/*.wav 未参与校准的其他词、噪声在 目录运行下列单行命令Python 标准库即可不要求 NumPytextpython application/bt_watch/tools/asr/kws_tool.py train --data D:\data\dataset_train --unknown D:\data\dataset_unknown --output D:\data\kws_model.json --binary D:\data\kws_model.bin --header D:\data\kws_model_data.hpython application/bt_watch/tools/asr/kws_tool.py inspect D:\data\kws_model.binpython application/bt_watch/tools/asr/kws_tool.py eval --model D:\data\kws_model.json --data D:\data\dataset_test --unknown D:\data\dataset_unknown_test --report D:\data\kws_eval.json训练使用留一距离校准选为模板的样本在估计其得分时排除自己避免用零距离错误判断泛化能力。--unknown 给每类阈值加未知词得分上限出现calibration_conflicts 表示未知词和关键词得分重叠应补录数据并检查语句。评估打印关键词准确率、拒识率、未知词误接受率并生成混淆矩阵。更新板上模型时1. app asr off确认 microphone OFF。2. 使用已有 U 盘模式把 kws_model.bin 复制到 NAND 根目录。3. 从电脑安全退出 U 盘执行设备原有退出 U 盘命令等待文件系统恢复。4. app asr load、app asr status确认 trained1 和每类模板数。5. app asr on用未参与训练的真人语音测试。模型是固定 66640 字节、80 字节版本化头加 float32 模板数据含 CRC32。固件核对魔数、版本、特征参数、模板数量/帧数、有限浮点数和 CRC校验失败保留此前可用模型。默认关闭 CONFIG_APP_ASR_BUILTIN_MODEL若希望固化模型将生成的头放到 src/asr/kws_model_data.h 并开启该配置后重新编译。## 验证范围与现有限制训练、预测和主机测试只使用 Python 标准库。ARM 核心、模型存储和运行线程回归测试还需要 SDK 的 arm-none-eabi-gcc 在 PATH 中以及 pyelftools 和unicorn。脚本优先使用既有 outdir/ble_record_tests/deps新检出仓库可安装textpython -m pip install pyelftools unicorn也可安装到脚本优先搜索的 SDK 测试依赖目录textpython -m pip install --target application/bt_watch/outdir/ble_record_tests/deps pyelftools unicorn执行完整 5 组回归textpython application/bt_watch/tests/asr/run_tests.pypython application/bt_watch/tests/asr/run_core_tests.pypython application/bt_watch/tests/asr/run_model_tests.pypython application/bt_watch/tests/asr/run_runtime_tests.pypython application/bt_watch/tests/asr/run_capture_tests.py主机测试验证训练、导出、二进制布局、CRC 和坏文件拒绝核心测试执行实际ARM C 算法与 Python 的 MFCC 系数和 DTW 数值比对并覆盖分包、尾帧、静音和超长语音。模型测试覆盖主机导出与板端加载/保存的一致性及损坏文件拒绝线程测试覆盖短读累积、VAD、录入超时、连续三句、拒识后接合法指令、重复动作的独立命中日志、丢样后继续识别、音乐请求、ADC 清理失败重试和唤醒锁平衡。采集适配器测试还覆盖 DMA 半缓冲偏移、启动稳定、整数电平统计、溢出和资源关闭重试。交付前 5 组测试均已通过这些软件回归不代表已测得真人识别率尚需烧录开发板、录入实际 MIC 语音并在播放音乐的环境中验证漏检和误触发。本版没有 AEC 回声消除。大音量扬声器的音乐可能被 MIC 收入引起漏检或误识别首次训练时应关闭外放现场先用较低音量和较近距离验证。“暂停音乐”在音乐播放时的效果尤其依赖 MIC 信噪比。当前 ADC 为 MIC0、16 kHz、增益 20020 dB与其他 MIC 使用者互斥正常录音、通话或 USB 麦克风需要 ADC 时先执行 app asr off。本功能是两词离线 KWS不是自由语音转文字 ASR不会输出整句文本。后续增加关键词需同步扩大模型/动作映射并重新训练。关键代码用 //zk、Python 用# zk 标识编译和测试不会自动 Git 提交。