目录

Lightweight Offline Audio Event Detection for OpenVela

离线端侧音频事件检测系统 — 面向 OpenVela/NuttX 嵌入式部署的轻量级音频分类与告警方案。

支持 3 类音频事件 检测:background(背景噪声)、cough(咳嗽)、glass_break(玻璃破碎),在端侧完成从音频采集到特征提取、模型推理、本地告警的全闭环流程。


系统架构

┌─────────────┐     ┌──────────────────┐     ┌─────────────┐     ┌──────────────┐
│  音频采集    │ ──▶ │  特征提取         │ ──▶ │  模型推理    │ ──▶ │  输出/告警    │
│  WAV / I2S  │     │  40维时域 + 58维  │     │  Tiny MLP   │     │  串口/LED/   │
│  16kHz mono │     │  MFCC = 98维     │     │  98→64→3    │     │  蜂鸣器       │
└─────────────┘     └──────────────────┘     └─────────────┘     └──────────────┘

完整闭环:采集 → 预处理/特征提取 → 模型识别 → 输出/告警,全部在端侧完成,不依赖云端或外部服务器。


目录结构

audio-event-detection/audio-event-openvela-src/audio-event-openvela/
├── requirements.txt                   # Python 依赖
├── .gitignore
│
├── python/                            # Python 训练与评估 Pipeline
│   ├── synthetic_data_generator.py    #   合成数据生成
│   ├── import_esc50.py                #   ESC-50 数据集导入
│   ├── prepare_data.py                #   数据预处理(重采样/分段/归一化)
│   ├── extract_features.py            #   特征提取(与 C 端对齐)
│   ├── model_np.py                    #   NumPy 实现的 Tiny MLP
│   ├── train.py                       #   模型训练
│   ├── evaluate.py                    #   模型评估
│   ├── export_to_c.py                 #   导出权重为 C 头文件
│   ├── predict_wav.py                 #   单文件推理
│   ├── realtime_demo.py               #   实时麦克风演示
│   └── audio_utils.py                 #   音频工具函数
│
├── openvela_app/audiodetect/          # OpenVela/NuttX 端侧应用
│   ├── audiodetect_main.c             #   主程序入口
│   ├── feature_extractor.c            #   特征提取(时域 + MFCC)
│   ├── feature_extractor.h
│   ├── model_infer.c                  #   MLP 推理引擎
│   ├── model_infer.h
│   ├── model_weights.h                #   模型权重(C 数组)
│   ├── wav_reader.c                   #   WAV 文件读取
│   ├── wav_reader.h
│   ├── mfcc_tables.h                  #   MFCC 预计算表
│   ├── Kconfig                        #   NuttX 构建配置
│   ├── Makefile
│   ├── Make.defs
│   └── CMakeLists.txt
│
├── embedded/audiodetect/              # Linux 便携 C 演示(独立编译)
│   ├── audiodetect_main.c
│   ├── feature_extractor.c
│   ├── model_infer.c
│   ├── model_weights.h
│   ├── wav_reader.c
│   ├── Makefile
│   └── README.md
│
├── models/                            # 训练好的模型
│   ├── tiny_mlp.npz                   #   合成数据训练(40维/32隐藏层)
│   ├── tiny_mlp_esc50.npz             #   ESC-50 训练(40维/32隐藏层)
│   └── tiny_mlp_esc50_mfcc.npz        #   ESC-50 训练(98维/128隐藏层,含MFCC)
│
├── data/                              # 数据目录
│   ├── datasets/                      #   外部数据集(ESC-50)
│   ├── processed/                     #   合成数据预处理结果
│   ├── processed_esc50/               #   ESC-50 预处理结果
│   ├── test_background.wav            #   测试 WAV(16kHz/mono/16bit)
│   ├── test_cough.wav
│   └── test_glass.wav
│
├── docs/                              # 文档
│   ├── deployment_openvela_sim.md     #   OpenVela 模拟器部署指南
│   ├── migration_to_devkit.md         #   硬件迁移方案
│   ├── dataset_esc50.md               #   数据集说明
│   ├── windows_setup.md               #   Windows 环境配置
│   └── linux_server_setup.md          #   Linux 服务器配置
│
├── scripts/                           # 辅助脚本
│   ├── setup_nuttx_sim.sh             #   NuttX 模拟器环境搭建
│   ├── try_openvela_goldfish.sh       #   OpenVela Goldfish 克隆
│   ├── integrate_nuttx_audiodetect.sh #   应用集成到 NuttX
│   ├── validate_linux_c.sh            #   Linux C 演示验证
│   ├── install_repo_tool.sh           #   repo 工具安装
│   ├── ubuntu_env_check.sh            #   Ubuntu 环境检查
│   ├── ubuntu_install_deps.sh         #   Ubuntu 依赖安装
│   └── vmware_stage_readme.md         #   VMware 阶段说明
│
├── openvela_build.log             #   OpenVela 构建日志
└── openvela_audiodetect_smoke.log #   模拟器推理验证日志

快速开始

方式零:一键执行脚本(推荐)

0a. OpenVela 端侧全流程一键运行

一条命令完成:源码同步 → 构建注册 → 编译 → WAV注入 → 启动模拟器 → 3类音频推理 → 结果汇总。

cd ~/project/qrs
bash run_openvela_demo_fixed.sh

脚本自动执行 7 个步骤:

步骤 操作 说明
Step 1 同步源码 openvela_app/audiodetect/ 下 13 个文件复制到 OpenVela apps/
Step 2 注册构建 apps/Kconfigapps/Make.defs 中注册 audiodetect
Step 3 开启配置 defconfig 中写入 CONFIG_AE_AUDIODETECT=y
Step 4 编译构建 执行 ./build.sh ... --cmake -j4,已构建则自动跳过
Step 5 注入 WAV mcopy 将 3 个测试 WAV 写入 vela_data.bin FAT 镜像
Step 6 启动模拟器 无头模式 (-no-window) 启动,自动执行 3 条推理命令
Step 7 检查结果 汇总输出每条推理结果和告警触发次数

输出日志保存到 results/openvela_audiodetect_smoke.log

支持自定义路径:

OPENVELA_DIR=/path/to/openvela PROJECT_ROOT=/path/to/app bash run_openvela_demo_fixed.sh

0b. Linux C 推理一键验证

无需 OpenVela,在任意 Linux 服务器上编译并运行 C 推理:

cd audio-event-openvela
bash scripts/validate_linux_c.sh

脚本自动执行:make clean && make → 搜索 WAV 文件 → 运行推理 → 输出结果。


方式一:Python 训练 Pipeline(Windows / Linux)

# 1. 环境配置
conda create -n audioevent python=3.10 -y
conda activate audioevent
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121
pip install -r requirements.txt

# 2. 合成数据训练(快速验证代码路径)
python python/synthetic_data_generator.py --output_dir data/raw --count 30
python python/prepare_data.py --raw_dir data/raw --output_dir data/processed --overwrite
python python/train.py --labels data/processed/labels.csv --model_out models/tiny_mlp.npz --epochs 30

# 3. ESC-50 数据训练(更高质量)
python python/import_esc50.py --overwrite
python python/prepare_data.py --raw_dir data/raw_esc50 --output_dir data/processed_esc50 --overwrite
python python/train.py --labels data/processed_esc50/labels.csv --model_out models/tiny_mlp_esc50.npz --epochs 100

# 4. 单文件推理
python python/predict_wav.py --wav data/processed_esc50/glass_break/example.wav --model models/tiny_mlp_esc50.npz

# 5. 导出为 C 头文件
python python/export_to_c.py --model models/tiny_mlp_esc50.npz

方式二:Linux C 独立演示

cd embedded/audiodetect
make
./audiodetect ../../data/test_glass.wav
# 预期输出:
#   Audio Event Detection Demo
#   Result: glass_break
#   [ALERT] Local alarm triggered

方式三:OpenVela 模拟器端侧运行

# 1. 克隆并构建 OpenVela
cd /path/to/openvela
./build.sh vendor/openvela/boards/vela/configs/goldfish-arm64-v8a-ap/ --cmake -j4

# 2. 将 WAV 测试文件写入数据分区镜像
mcopy -i cmake_out/vela_goldfish-arm64-v8a-ap/vela_data.bin \
    data/test_background.wav ::/test_background.wav
mcopy -i cmake_out/vela_goldfish-arm64-v8a-ap/vela_data.bin \
    data/test_cough.wav ::/test_cough.wav
mcopy -i cmake_out/vela_goldfish-arm64-v8a-ap/vela_data.bin \
    data/test_glass.wav ::/test_glass.wav

# 3. 启动模拟器(无头模式)
./emulator.sh cmake_out/vela_goldfish-arm64-v8a-ap -no-window

# 4. 在 NSH 中运行推理
nsh> audiodetect /data/test_background.wav
nsh> audiodetect /data/test_cough.wav
nsh> audiodetect /data/test_glass.wav

模型设计

特征提取

特征组 维度 说明
时域统计特征 40 5 种指标 × 8 种统计量(均值/标准差/最大/最小/分位数/趋势)
MFCC 特征 58 Mel 频率倒谱系数,使用预计算表加速
合计 98 输入到 MLP 的特征维度
  • 音频格式:16kHz / 单声道 / 16bit PCM
  • 帧长:400 采样点(25ms),帧移:160 采样点(10ms)
  • 短于 1 秒的音频自动零填充

网络结构

输入层:  98 维特征向量
         ↓ 标准化 (z-score)
隐藏层:  64 维 (C 端部署) / 128 维 (Python 评估) + ReLU 激活
         ↓ 线性变换
输出层:  3 维 logits
         ↓ Softmax
预测:    argmax → 类别索引
变体 隐藏层 参数量 权重大小 用途
C 端部署版 64 6,531 25.5 KB OpenVela 模拟器 / 嵌入式设备
Python 评估版 128 13,059 51.0 KB ESC-50 离线评估 / 模型选型
  • 无外部依赖,纯 C 实现,仅使用 math.h
  • 两版使用相同的 98 维特征提取管线,仅隐藏层宽度不同

类别定义与触发口径

索引 类别 说明 告警触发条件
0 background 背景噪声 / 无异常事件 不触发告警
1 cough 咳嗽声 置信度 > 0.80 时触发
2 glass_break 玻璃破碎声 置信度 > 0.80 时触发

测试结果

OpenVela Goldfish ARM64 模拟器验证

三条测试音频均在端侧模拟器上完成全流程推理:

测试音频 预测结果 置信度 告警 状态
test_background.wav background 1.000 ✓ 正确
test_cough.wav cough 1.000 [ALERT] 触发 ✓ 正确
test_glass.wav glass_break 0.992 [ALERT] 触发 ✓ 正确

完整运行日志见 results/openvela_audiodetect_smoke.log


模型性能

Python 离线评估(ESC-50 数据集,98 维 MFCC 模型)

在 ESC-50 预处理数据集上进行 7:1.5:1.5 训练/验证/测试划分,共 1600 个样本(background 1200 / cough 200 / glass_break 200),测试集 240 个样本。

训练采用类别加权交叉熵 + 少数类过采样以缓解数据不平衡问题:

指标 数值
总体准确率 **75.00%**(180/240)
训练准确率 83.0%
验证准确率 76.2%
验证宏 F1 0.656
模型架构 98 → 128 → 3(ReLU + Softmax)
训练轮次 800 epochs
优化器 NumPy SGD(LR=0.003, decay=0.997/epoch, L2=5e-4)
类别权重 background:0.44, cough:2.67, glass_break:2.67
训练集大小 2,520(过采样至均衡:840×3)

各类别 Precision / Recall / F1:

类别 Precision Recall F1 Support
background 0.9786 0.7611 0.8562 180
cough 0.4857 0.5667 0.5231 30
glass_break 0.4000 0.8667 0.5474 30

混淆矩阵(行=真实类别,列=预测类别):

                    pred_background  pred_cough  pred_glass_break
true_background          137             15              28
true_cough                 2             17              11
true_glass_break           1              3              26

误报与漏报分析(多阈值)

告警触发条件:预测为 cough 或 glass_break 置信度 > 阈值。在测试集 240 个样本(60 个事件 + 180 个背景)上评估不同阈值:

置信度阈值 TP FP FN TN 误报率 (FPR) 漏报率 (FNR) 告警精确率 告警召回率 F1
0.50 55 42 5 138 23.33% 8.33% 0.5670 0.9167 0.701
0.60 33 21 27 159 11.67% 45.00% 0.6111 0.5500 0.578
0.65 33 19 27 161 10.56% 45.00% 0.6346 0.5500 0.589
0.70 30 19 30 161 10.56% 50.00% 0.6122 0.5000 0.551
0.80 25 18 35 162 10.00% 58.33% 0.5814 0.4167 0.486
0.90 23 15 37 165 8.33% 61.67% 0.6053 0.3833 0.470
  • 低阈值(0.50):漏报率仅 8.33%,几乎不漏检事件,但误报率较高(23.33%),适合安全优先场景
  • 高阈值(0.80):误报率降至 10.00%,但漏报率上升至 58.33%,适合减少误打扰场景
  • 推荐阈值 0.65-0.70:误报率与漏报率较为均衡

主要瓶颈:训练数据不平衡(background:cough:glass = 6:1:1),尽管已使用类别加权和过采样,cough 和 glass_break 的精确率仍偏低。改进方向:

  • 增加咳嗽/玻璃破碎样本数量(至少 1:1:1)
  • 数据增强(时间拉伸、加噪、混响)
  • 尝试更深网络或 CNN 架构

延迟与资源占用

计算量分析

C 端部署版(98→64→3)

阶段 运算量 (MACs) 说明
特征标准化 98 98 次减法 + 除法
隐藏层 (98→64) 6,272 98×64 矩阵乘法
ReLU 激活 64 64 次比较
输出层 (64→3) 192 64×3 矩阵乘法
Softmax 3 3 次 exp + 归一化
推理总计 ~6,566 约 13K FLOPs

Python 评估版(98→128→3)

阶段 运算量 (MACs) 说明
隐藏层 (98→128) 12,544 98×128 矩阵乘法
输出层 (128→3) 384 128×3 矩阵乘法
推理总计 ~13,026 约 26K FLOPs

特征提取阶段(MFCC FFT 等)计算量稍大,但使用预计算表(mfcc_tables.h)加速,总运算量仍在数十 KFLOPs 量级。

内存占用

组件 C 端部署版 (64) Python 评估版 (128) 说明
模型权重 (W1+B1+W2+B2) 25.5 KB 51.0 KB float32 数组
标准化参数 (MEAN+STD) 784 B 784 B 98×2 × 4 bytes
PCM 输入缓冲 32 KB 32 KB 16,000 × 2 bytes (int16_t)
特征向量 392 B 392 B 98 × 4 bytes (float)
隐藏层缓冲 256 B 512 B 64/128 × 4 bytes
MFCC 预计算表 ~12 KB ~12 KB Mel 滤波器组 + DCT 矩阵
总内存 < 75 KB < 100 KB 适合 MCU 级部署

延迟测试

Python 离线测量(NumPy,单样本)

在服务器(Intel x86_64)上使用 Python/NumPy 测量全流程延迟,测试集 240 个样本:

阶段 平均延迟 中位数 P95 P99 说明
特征提取 (98维) 16.88 ms 16.88 ms 时域统计 + MFCC FFT + Delta
模型推理 (MLP) 0.029 ms 0.028 ms 98→128→3 矩阵乘法
全流程 17.65 ms 16.89 ms 25.50 ms 25.66 ms 特征提取 + 推理

Python/NumPy 延迟主要来自 MFCC FFT 计算(逐帧 256 点 FFT + Mel 滤波器组)。C 端使用预计算表(mfcc_tables.h)和定点优化,预期延迟更低。

端侧延迟(OpenVela Goldfish ARM64 模拟器)

阶段 延迟 说明
WAV 文件读取 < 5 ms 32 KB 文件,FAT 分区读取
特征提取 (98维) < 5 ms 时域统计 + MFCC(预计算表)
模型推理 (MLP) < 1 ms ~6.5K MACs,Cortex-A57 @ 1.5GHz
端到端总延迟 < 10 ms 从文件读取到告警输出
音频输入长度 0.5 s 8,000 采样点(零填充至 16,000)

模拟器环境下推理在 NSH 命令响应周期内完成(日志中命令输入后立即输出结果),实测无感知延迟。实际硬件延迟取决于 I2S/PDM 采集时间。

模型体积

文件 大小 说明
model_weights.h 126 KB C 源码(含格式化文本,64 隐藏层)
tiny_mlp_esc50.npz 62 KB Python 旧模型(40维/32隐藏层)
tiny_mlp_esc50_mfcc.npz 56 KB Python 新模型(98维/128隐藏层)
tiny_mlp.npz 9 KB 合成数据模型
编译后权重 (.rodata) 25.5 KB 二进制 float32 数组(64 隐藏层)

硬件迁移方案

当前模拟器版本使用 WAV 文件模拟麦克风输入、printf 输出告警。迁移到 DshanPixVela-DevKit V1 等硬件时,只需替换两个模块:

模块 模拟器版本 硬件版本
音频采集 wav_reader.c mic_i2s_reader.cmic_pdm_reader.c
告警输出 printf("[ALERT]") gpio_set_value(LED_PIN, 1)buzzer_on()

以下核心模块保持不变

  • feature_extractor.c — 特征提取
  • model_infer.c — 模型推理
  • model_weights.h — 模型权重

详见 docs/migration_to_devkit.md


端侧闭环流程

                    ┌─────────────────────────────────────────────────┐
                    │              OpenVela 端侧设备                    │
                    │                                                 │
  音频输入  ──────▶ │  wav_reader.c ──▶ feature_extractor.c ──▶       │
  (WAV/I2S)         │                       98维特征                  │
                    │                          │                      │
                    │                          ▼                      │
                    │                   model_infer.c                 │
                    │                   (Tiny MLP)                    │
                    │                          │                      │
                    │              ┌───────────┴───────────┐          │
                    │              │                       │          │
                    │         background              cough/glass     │
                    │         (无告警)              (置信度>0.80)     │
                    │                                      │          │
                    │                                      ▼          │
                    │                            [ALERT] 串口/LED     │
                    │                                                 │
                    └─────────────────────────────────────────────────┘

技术栈

技术
训练框架 Python 3.10 + PyTorch + NumPy
端侧推理 纯 C99(仅依赖 math.h / stdio.h / stdlib.h
嵌入式系统 OpenVela / NuttX(Goldfish ARM64 模拟器)
数据集 ESC-50(环境声音分类)
模型格式 C 头文件静态数组(零依赖部署)

许可证

本项目用于音频事件检测比赛,所有代码和文档可自由用于学习和竞赛目的。ESC-50 数据集遵循其原始许可证(CC BY-NC-SA 3.0)。

关于

Audio event detection on OpenVela NuttX RTOS - 3-class (background/cough/glass_break) with 98-dim MFCC features and MLP model

321.0 KB
邀请码
    Gitlink(确实开源)
  • 加入我们
  • 官网邮箱:gitlink@ccf.org.cn
  • QQ群
  • QQ群
  • 公众号
  • 公众号

版权所有:中国计算机学会技术支持:开源发展技术委员会
京ICP备13000930号-9 京公网安备 11010802047560号