# 声源定位 ***Copyright © Quectel Wireless Solutions Co., Ltd. 2026. All rights reserved.*** --- Sound Localization 是一套面向 **Quectel PI M2** 的本地人声方向与语音转写应用。项目通过 USB 接入 Sipeed 6+1 麦克风阵列和 MA-USB8 驱动板,在 Quectel PI M2 上完成八通道音频采集、人声活动检测、水平面声源定位、SenseVoice 离线语音识别和桌面可视化,适合开发板功能展示、阵列算法验证、边缘语音交互原型和现场调试。 本项目集中展示 Quectel PI M2 对 USB 多通道音频外设、Python/NumPy 信号处理、本地 ONNX 模型推理和桌面图形交互的整合能力。实时音频不会上传,转写结果默认仅保存在进程内存中。 ## **功能概览** - 通过 ALSA 的 `arecord` 接口采集 48 kHz、16 位、八通道 PCM。 - 使用六路原始麦克风和 GCC-PHAT/SRP 估计水平面声源方向。 - 在三个分散麦克风上执行 WebRTC VAD 投票,并结合自适应语音频段门限筛选人声。 - 在后台线程中切分语音,使用本地 SenseVoice INT8 模型进行离线识别。 - 为每段转写添加 `[Direction 060°]` 形式的方向标签;证据不足时显示 `[Direction unknown]`。 - 支持实时阵列输入、八通道 WAV 回放、合成方向演示、无界面诊断和独立 WAV 转写。 - 在界面内保留最近 20 段转写,并提供复制、清空和基础门限保存功能。 ## **开发配件清单** 以下配件用于完成 Quectel PI M2 上的完整实时演示。无界面诊断不需要显示器和输入设备,合成演示模式不需要麦克风阵列。 | **配件名称** | **

数量
** | **规格或要求** | | --- | --- | --- | | Quectel PI M2 智能开发板 |

1 块
| 作为 USB 音频接入、端侧算法、离线识别和界面显示的主控平台;仓库部署记录对应 aarch64、Debian 13。 | | Sipeed 6+1 麦克风阵列 |

1 个
| 六个外圈原始麦克风需按顺时针顺序映射到 `mic_channels`;当前配置使用 CH0–CH5,阵列半径为 0.04 m。 | | MA-USB8 驱动板 |

1 块
| 通过 ALSA 提供 48 kHz、`S16_LE`、八通道音频;默认设备名为 `hw:MicArray,0`。 | | USB 数据线 |

1 根
| 将 MA-USB8 接入 Quectel PI M2 的 USB Host;需要支持稳定的数据传输和供电。 | | 显示器 |

1 台,可选
| 直接展示图形界面时使用;SSH 或无屏场景可运行 `--probe`。 | ```{image} images/image_HKzubSMegoM0a7xgBaccqanInEe.webp :width: 1040px :height: 778px :align: center ``` ## **快速上手** ### **环境要求** 本项目的主要部署平台是 Quectel PI M2。仓库中的板端部署记录确认了以下环境和外设链路: - Quectel PI M2,aarch64,Debian 13。 - Python 3、Tkinter、ALSA 工具和可用的图形桌面会话。 - MA-USB8 可被识别为 ALSA 八通道采集设备。 - 板端已有 NumPy 2.2.4 的部署记录。 - Python 依赖声明为 `numpy>=1.23,<3`、`webrtcvad-wheels==2.0.14` 和 `sherpa-onnx==1.13.8`。 - SenseVoice INT8 模型及词表;当前模型目录约占 230 MiB。 ### **安装基础依赖** 以下命令适用于部署记录中的 Debian 13 环境。它们会安装系统软件包、创建项目虚拟环境、安装 Python 依赖并准备本地模型: ```bash sudo apt install python3 python3-venv python3-numpy python3-tk alsa-utils fonts-noto-cjk python3 -m venv --system-site-packages .venv .venv/bin/python -m pip install -r requirements-asr.txt python3 setup_asr.py ``` `setup_asr.py` 需要访问脚本中记录的 GitHub Release 地址。它下载 SenseVoice INT8 模型,检查归档路径后写入: ```plaintext models/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17/ ``` 仓库当前已经包含模型文件时,脚本会直接报告模型可用,不重复下载。 ### **检查音频设备** 连接麦克风阵列和 MA-USB8 后,先确认 Quectel PI M2 能发现采集设备: ```bash arecord -l ``` 默认配置期望设备名为 `hw:MicArray,0`。如果实际名称不同,可以临时覆盖: ```bash bash run.sh --device '<实际 ALSA 设备名>' --probe --seconds 5 ``` 也可以修改 `[config.json](config.json)` 中的 `device`。 ### **运行板端诊断** 在启动界面前执行五秒无界面采集检查: ```bash bash run.sh --probe --seconds 5 ``` 成功时,终端会输出一个 JSON 对象,包括设备名、帧数、采集时长、八个通道的 RMS/dBFS、削波计数、人声帧数、有效方向帧数、最后角度、一致性、实际门限和信噪信息。 ### **构建项目** 项目没有独立编译步骤,直接在 Quectel PI M2 上运行 Python 源码。虚拟环境和 ONNX 模型均为运行时资产,不是业务代码的构建产物。 ### **启动应用** 在 Quectel PI M2 图形桌面的终端中,先进入项目目录。下面的 `/path/to` 需要替换为实际存放项目的父目录: ```bash cd /path/to/sound_loca_demo bash run.sh ``` 正常启动后,窗口左侧显示方向雷达,右侧显示角度、人声状态、电平和门限,下方显示离线转写。首次运行时先保持环境安静两到三秒,让程序学习稳定的背景噪声频谱。 仅通过 SSH 登录通常不会创建可用的图形桌面会话;这种情况下使用 `--probe`,或在开发板已登录的桌面终端中启动应用。 ## **应用使用方法** ### **主界面** - **VOICE DIRECTION**:以 MIC0 为 0°,角度顺时针增加。只有人声、方向一致性、语音频段电平和实际门限同时通过时才显示青色箭头。 - **SIGNAL STATUS**:显示当前方向、人声状态、启发式一致性、输入 dBFS、基础门限和自适应语音门限。 - **BASE GATE**:在 -65 至 -20 dBFS 之间调整 `gate_dbfs`,可使用滑块、方向键或 `−` / `+`;按钮每次调整 1 dB。 - **TRANSCRIPT + DIRECTION**:显示完成的识别结果。**Copy text** 复制全部当前条目,**Clear** 从内存中清除条目。 ```{image} images/image_EAEMbnQ5poHSgBxwRXhcP7mln2f.webp :width: 1140px :height: 855px :align: center ``` ### **校准并保存基础门限** 1. 保持环境安静两到三秒,观察输入电平。 2. 在预期距离以正常音量说话。 3. 将基础门限设置在大部分环境声音之上、正常说话电平之下。数值越负越容易触发。 4. 点击 **Save**,将 `gate_dbfs` 写回 `config.json`。 基础门限不是唯一的人声判断条件。VAD 确认人声后,程序会依据学习到的稳定噪声频谱计算自适应门限,界面会同时显示基础值和实际使用值。**Save** 只保存 `gate_dbfs`,其他配置项需要手动编辑。 ### **查看带方向的转写** 确认状态显示模型已经就绪后,面向阵列说完一句,并保持约一秒停顿。转写区会追加类似结果: ```plaintext [Direction 060°] 你好 [Direction unknown] Direction evidence is insufficient. ``` 方向来自该句话说话期间的有效定位结果,而不是识别完成时的箭头方向。程序按一致性和有效时长进行圆周平均;证据不足或方向冲突时保留文字,并将方向标记为未知。 识别结果最多保留最近 20 段,只存在于当前进程内存。程序不会自动保存实时录音或转写文本。 ### **运行无界面诊断** 在 SSH、无屏设备或现场设备排查场景中执行: ```bash bash run.sh --probe --seconds 5 ``` 此模式不加载 ASR 模型、不创建窗口,只检查采集、通道电平、人声检测和定位输出。 ```typescript b@HF-C-S:~/project/sound_loca_demo$ bash run.sh --probe --seconds 5 { "device": "hw:MicArray,0", "frames": 115, "audio_seconds": 4.906666666666666, "max_dbfs": -31.141714023559306, "channel_rms": [ 0.021183548958751082, 0.01586236610173023, 0.014955752892219268, 0.011623506850791492, 0.015094008244941195, 0.01610835825445783, 0.007044012766777389, 0.006146897185292454 ], "channel_dbfs": [ -33.480025583262275, -35.99264061744061, -36.50383438256843, -38.693256481639224, -36.42390834231644, -35.858974402494034, -43.04359731151728, -44.226881018967504 ], "channel_clipped_samples": [ 0, 0, 0, 0, 0, 0, 0, 0 ], "active_frames": 0, "last_angle": 330.0, "last_confidence": 0.6317844198638005, "vad_enabled": true, "speech_frames": 7, "sentence_direction_frames": 0, "effective_gate_dbfs": -58.0, "last_snr_db": -1.1870431568712974 } ``` ### **回放八通道录音** 通过与实时输入相同的定位、VAD、分句、识别和界面路径回放 WAV: ```bash bash run.sh --wav recording.wav ``` 文件必须是未压缩的八通道、48 kHz、16 位 PCM。文件中不足一个完整的 2048 样本块时回放结束,界面显示 `Playback ended`。 ### **运行合成方向演示** 没有连接麦克风阵列时,可以用内置合成信号展示 Quectel PI M2 上的方向算法和界面: ```bash bash run.sh --demo ``` 演示模式会明确显示 `DEMO / SYNTHETIC AUDIO`,并关闭 VAD 和 ASR。该模式用于界面与方向管线演示,不代表真实场景的声学精度。 ```{image} images/image_N9BdbJ7EvoBFgOxeLSOcYQ7Unfg.webp :width: 1140px :height: 855px :align: center ``` ### **独立转写 WAV** 短 PCM WAV 可以直接识别: ```bash .venv/bin/python transcribe.py --file recording.wav --channel 0 ``` 超过 30 秒的文件需要启用 VAD 分句: ```bash .venv/bin/python transcribe.py --file recording.wav --channel 0 --segment ``` 该工具接受单通道或多通道的未压缩 16 位 PCM,`--channel` 使用从零开始的索引。自动分句支持 8、16、32 和 48 kHz。识别 JSON 输出到标准输出,不写入文件。单独选择的一个通道不包含阵列几何信息,因此此入口不计算声源方向。 ## **配置** 应用启动时读取 `[config.json](config.json)`。除界面中实时调整的基础门限外,手动修改配置后需要重启。`--device` 只覆盖当前进程的设备名;应用还会根据实时、演示或诊断模式设置 `vad_enabled` 和 `asr_enabled`,因此不应把这两个 JSON 值当成功能切换按钮。 | **配置键** | **当前值或回退值** | **作用** | | --- | --- | --- | | `device` | `hw:MicArray,0` | Quectel PI M2 上的 ALSA 采集设备 | | `rate` | `48000` | 采样率;MA-USB8 校验要求该值 | | `channels` | `8` | 采集通道数;MA-USB8 校验要求该值 | | `mic_channels` | `[0, 1, 2, 3, 4, 5]` | 六个互不重复的原始定位通道;拒绝 CH6 | | `radius_m` | `0.04` | 外圈麦克风半径,单位为米;有效范围 0.01–0.15 | | `frame_size` | `2048` | 每个定位块的采样数;必须是 512–8192 之间的 2 次幂 | | `gate_dbfs` | `-35.0` | 基础显示门限;界面范围为 -65 至 -20 dBFS | | `min_confidence` | `0.2` | 0–1 的启发式方向一致性门限,不代表正确率 | | `angle_offset_deg` | `0.0` | 对显示和报告方向施加的旋转角 | | `mirror` | `false` | 在应用偏移前镜像估计方向 | | `hold_seconds` | `0.55` | 人声结束后保持最后方向的时间 | | `vad_mode` | `2` | WebRTC VAD 严格度,范围 0–3 | | `vad_channel` | `0` | 三路分散 VAD 通道的起始原始麦克风 | | `speech_floor_dbfs` | 回退值 `-58.0` | 最低语音频段分析电平;当前 JSON 未显式设置 | | `speech_snr_db` | 回退值 `2.0` | 相对学习噪声的自适应门限裕量;当前 JSON 未显式设置 | | `asr_language` | `auto` | SenseVoice 语言选择;也可设为 `zh` 或 `en` | | `asr_channel` | `0` | 送入语音识别的从零开始通道 | | `asr_threads` | `2` | CPU 推理线程数;有效范围 1–8 | | `asr_model_dir` | `models/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17` | 模型和词表目录 | | `asr_pre_roll_seconds` | `0.3` | 人声开始前保留的音频 | | `asr_silence_seconds` | `0.8` | 结束一个语句所需的尾部静音 | | `asr_min_speech_seconds` | `0.24` | 一个语句所需的最短人声时长 | | `asr_max_seconds` | `15.0` | 语句自动切段前的最长时长 | | `asr_direction_min_seconds` | 回退值 `0.12` | 一句话所需的最少有效方向时长;当前 JSON 未显式设置 | | `asr_direction_min_coverage` | 回退值 `0.2` | 有效方向对人声时长的最低覆盖率;当前 JSON 未显式设置 | | `asr_direction_min_consistency` | 回退值 `0.6` | 方向圆周集中程度的最低值;当前 JSON 未显式设置 | 无效值会在启动阶段被拒绝。校验覆盖音频格式、通道映射、阵列半径、块大小、方向门限、VAD 设置、ASR 通道与线程数、分句时长和方向汇总阈值。 ## **应用演示**
SLDEMO
## **常见问题排查** ### **出现`Audio capture timed out` 或 `Audio device disconnected`** 1. 检查设备发现情况和占用进程: ```bash arecord -l fuser /dev/snd/* ``` 2. 确认 MA-USB8 已连接 Quectel PI M2 的 USB Host,并且 `device` 与 ALSA 名称一致。 3. 关闭独占采集设备的其他程序,再运行 `bash run.sh --probe --seconds 5`。 4. 若问题仍存在,保留完整错误文本和脱敏后的诊断 JSON。 ### **出现`Unable to open window`** 1. 确认命令运行在 Quectel PI M2 已登录的图形桌面会话中。 2. 仅 SSH 登录时改用 `bash run.sh --probe --seconds 5`。 3. 确认已安装 `python3-tk`,并检查桌面显示环境是否可用。 4. 报告问题时提供 Debian 版本、桌面会话类型、Python 版本和完整错误文本。 ### **出现`WebRTC VAD missing` 或 `Recognition dependency missing`** 重新创建虚拟环境并安装已声明依赖: ```bash python3 -m venv --system-site-packages .venv .venv/bin/python -m pip install -r requirements-asr.txt ``` 随后使用 `bash run.sh` 启动。 ### **出现`Speech model missing`** 1. 检查 `asr_model_dir` 中是否同时存在 `model.int8.onnx` 和 `tokens.txt`。 2. 执行 `python3 setup_asr.py` 下载模型。 3. 确认 Quectel PI M2 能访问脚本中记录的模型下载地址,并有足够存储空间。 4. 保留完整下载或归档错误,但不要公开代理凭据。 ### **方向不稳定、镜像或发生旋转** 1. 确认 `mic_channels` 按顺时针列出六个外圈麦克风,且不包含 CH6。 2. 测试前保持环境安静两到三秒,让噪声模型完成初始学习。 3. 让一位说话者从已知方向测试,然后调整 `angle_offset_deg` 或 `mirror` 并重启。 4. 减少其他说话者、播放音频、强反射和阵列附近的稳定噪声。 ### **检测不到人声,或噪声触发箭头** 1. 观察输入电平、基础门限、自适应门限和人声状态。 2. 将 `gate_dbfs` 调整到环境电平与正常语音之间,点击 **Save**。 3. 必要时修改 `vad_mode`、`speech_floor_dbfs` 或 `speech_snr_db`,然后重启。 4. 播放的人声也可能触发 VAD,音乐和噪声仍可能造成误判。 ### **识别延迟或有片段被跳过** 1. 查看界面是否显示 `Transcribing…`、识别错误或繁忙提示。 2. ASR 在独立 CPU 线程中运行,队列最多等待两段语音;队列满时会跳过新片段,以保证采集继续运行。 3. 减少其他 CPU 负载,或适当缩短 `asr_max_seconds`。 4. 被跳过的片段不会写入磁盘,也不会自动重试。 ### **文字可以识别,但方向显示为未知** 1. 检查说话期间的一致性、语音频段电平和现场反射情况。 2. 确认阵列通道顺序、半径、镜像和角度偏移配置正确。 3. 当前默认至少需要 0.12 秒有效方向、20% 的语音覆盖率和 0.6 的方向集中程度。 4. 不建议仅为消除 `unknown` 而过度降低门限;这可能引入错误方向。 ## **测试与板端验证** 从项目根目录运行完整测试: ```bash bash test.sh ``` 测试覆盖合成声源定位、方向平滑与跳变抑制、VAD 分帧和三路投票、自适应门控、语句切分、句内方向汇总、有界 ASR 队列、错误上报和真实模型样例识别。完整测试集包含 35 项;在 Quectel PI M2 正式展示或交付前,应在板端运行全部测试并保留结果。 仓库中的 Quectel PI M2 部署记录确认:基础算法测试曾在板端通过,约五秒实时采集取得 115 帧、4.907 秒音频,八通道均有信号且未检测到削波。该记录证明了板端音频链路可运行,但不构成定位精度或性能指标。 板端部署记录确认定位和人声门控测试曾在 Quectel PI M2 上通过。由于最新版还增加了分句、句内方向汇总和 SenseVoice 识别测试,正式展示前仍需在开发板上重新执行: ```bash bash test.sh bash run.sh --probe --seconds 5 bash run.sh ``` 并现场检查人声触发、实物方向、转写和长时间运行状态。 ## **已知限制** - 应用只估计单一主声源的水平面方向,不估计距离或俯仰角,也不分离多个同时说话者。 - 方向质量受麦克风通道顺序、阵列安装朝向、反射、噪声和现场校准影响。 - `min_confidence` 是启发式一致性评分,不是定位正确率。 - 播放的人声可能触发 VAD,音乐或噪声也可能造成误判。 - 实时录音和转写不会持久化;剪贴板和最近 20 段记录只存在于当前桌面会话。 - ASR 队列已有两个任务等待时会跳过新的语句。 - USB 音频设备断开后不会自动重连,排除设备问题后需要重启应用。 ## **技术支持与贡献** 如在使用过程中遇到问题,欢迎在 [移远官方论坛]() 提交技术咨询,我们的技术支持团队将及时为您解答。