声源定位

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。

../../../_images/image_HKzubSMegoM0a7xgBaccqanInEe.webp

快速上手

环境要求

本项目的主要部署平台是 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 依赖并准备本地模型:

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 模型,检查归档路径后写入:

models/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2024-07-17/

仓库当前已经包含模型文件时,脚本会直接报告模型可用,不重复下载。

检查音频设备

连接麦克风阵列和 MA-USB8 后,先确认 Quectel PI M2 能发现采集设备:

arecord -l

默认配置期望设备名为 hw:MicArray,0。如果实际名称不同,可以临时覆盖:

bash run.sh --device '<实际 ALSA 设备名>' --probe --seconds 5

也可以修改 [config.json](config.json) 中的 device。

运行板端诊断

在启动界面前执行五秒无界面采集检查:

bash run.sh --probe --seconds 5

成功时,终端会输出一个 JSON 对象,包括设备名、帧数、采集时长、八个通道的 RMS/dBFS、削波计数、人声帧数、有效方向帧数、最后角度、一致性、实际门限和信噪信息。

构建项目

项目没有独立编译步骤,直接在 Quectel PI M2 上运行 Python 源码。虚拟环境和 ONNX 模型均为运行时资产,不是业务代码的构建产物。

启动应用

在 Quectel PI M2 图形桌面的终端中,先进入项目目录。下面的 /path/to 需要替换为实际存放项目的父目录:

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 从内存中清除条目。

../../../_images/image_EAEMbnQ5poHSgBxwRXhcP7mln2f.webp

校准并保存基础门限

  1. 保持环境安静两到三秒,观察输入电平。

  2. 在预期距离以正常音量说话。

  3. 将基础门限设置在大部分环境声音之上、正常说话电平之下。数值越负越容易触发。

  4. 点击 Save,将 gate_dbfs 写回 config.json。

基础门限不是唯一的人声判断条件。VAD 确认人声后,程序会依据学习到的稳定噪声频谱计算自适应门限,界面会同时显示基础值和实际使用值。Save 只保存 gate_dbfs,其他配置项需要手动编辑。

查看带方向的转写

确认状态显示模型已经就绪后,面向阵列说完一句,并保持约一秒停顿。转写区会追加类似结果:

[Direction 060°] 你好
[Direction unknown] Direction evidence is insufficient.

方向来自该句话说话期间的有效定位结果,而不是识别完成时的箭头方向。程序按一致性和有效时长进行圆周平均;证据不足或方向冲突时保留文字,并将方向标记为未知。

识别结果最多保留最近 20 段,只存在于当前进程内存。程序不会自动保存实时录音或转写文本。

运行无界面诊断

在 SSH、无屏设备或现场设备排查场景中执行:

bash run.sh --probe --seconds 5

此模式不加载 ASR 模型、不创建窗口,只检查采集、通道电平、人声检测和定位输出。

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 run.sh --wav recording.wav

文件必须是未压缩的八通道、48 kHz、16 位 PCM。文件中不足一个完整的 2048 样本块时回放结束,界面显示 Playback ended。

运行合成方向演示

没有连接麦克风阵列时,可以用内置合成信号展示 Quectel PI M2 上的方向算法和界面:

bash run.sh --demo

演示模式会明确显示 DEMO / SYNTHETIC AUDIO,并关闭 VAD 和 ASR。该模式用于界面与方向管线演示,不代表真实场景的声学精度。

../../../_images/image_N9BdbJ7EvoBFgOxeLSOcYQ7Unfg.webp

独立转写 WAV

短 PCM WAV 可以直接识别:

.venv/bin/python transcribe.py --file recording.wav --channel 0

超过 30 秒的文件需要启用 VAD 分句:

.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. 检查设备发现情况和占用进程:

arecord -l
fuser /dev/snd/*
  1. 确认 MA-USB8 已连接 Quectel PI M2 的 USB Host,并且 device 与 ALSA 名称一致。

  2. 关闭独占采集设备的其他程序,再运行 bash run.sh --probe --seconds 5。

  3. 若问题仍存在,保留完整错误文本和脱敏后的诊断 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

重新创建虚拟环境并安装已声明依赖:

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 test.sh

测试覆盖合成声源定位、方向平滑与跳变抑制、VAD 分帧和三路投票、自适应门控、语句切分、句内方向汇总、有界 ASR 队列、错误上报和真实模型样例识别。完整测试集包含 35 项;在 Quectel PI M2 正式展示或交付前,应在板端运行全部测试并保留结果。

仓库中的 Quectel PI M2 部署记录确认:基础算法测试曾在板端通过,约五秒实时采集取得 115 帧、4.907 秒音频,八通道均有信号且未检测到削波。该记录证明了板端音频链路可运行,但不构成定位精度或性能指标。

板端部署记录确认定位和人声门控测试曾在 Quectel PI M2 上通过。由于最新版还增加了分句、句内方向汇总和 SenseVoice 识别测试,正式展示前仍需在开发板上重新执行:

bash test.sh
bash run.sh --probe --seconds 5
bash run.sh

并现场检查人声触发、实物方向、转写和长时间运行状态。

已知限制

  • 应用只估计单一主声源的水平面方向,不估计距离或俯仰角,也不分离多个同时说话者。

  • 方向质量受麦克风通道顺序、阵列安装朝向、反射、噪声和现场校准影响。

  • min_confidence 是启发式一致性评分,不是定位正确率。

  • 播放的人声可能触发 VAD,音乐或噪声也可能造成误判。

  • 实时录音和转写不会持久化;剪贴板和最近 20 段记录只存在于当前桌面会话。

  • ASR 队列已有两个任务等待时会跳过新的语句。

  • USB 音频设备断开后不会自动重连,排除设备问题后需要重启应用。

技术支持与贡献

如在使用过程中遇到问题,欢迎在 移远官方论坛 提交技术咨询,我们的技术支持团队将及时为您解答。