Update README.md
离线端侧音频事件检测系统 — 面向 OpenVela/NuttX 嵌入式部署的轻量级音频分类与告警方案。
支持 3 类音频事件 检测:background(背景噪声)、cough(咳嗽)、glass_break(玻璃破碎),在端侧完成从音频采集到特征提取、模型推理、本地告警的全闭环流程。
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 # 模拟器推理验证日志
一条命令完成:源码同步 → 构建注册 → 编译 → WAV注入 → 启动模拟器 → 3类音频推理 → 结果汇总。
cd ~/project/qrs bash run_openvela_demo_fixed.sh
脚本自动执行 7 个步骤:
openvela_app/audiodetect/
apps/
apps/Kconfig
apps/Make.defs
defconfig
CONFIG_AE_AUDIODETECT=y
./build.sh ... --cmake -j4
mcopy
vela_data.bin
-no-window
输出日志保存到 results/openvela_audiodetect_smoke.log。
results/openvela_audiodetect_smoke.log
支持自定义路径:
OPENVELA_DIR=/path/to/openvela PROJECT_ROOT=/path/to/app bash run_openvela_demo_fixed.sh
无需 OpenVela,在任意 Linux 服务器上编译并运行 C 推理:
cd audio-event-openvela bash scripts/validate_linux_c.sh
脚本自动执行:make clean && make → 搜索 WAV 文件 → 运行推理 → 输出结果。
make clean && make
# 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
cd embedded/audiodetect make ./audiodetect ../../data/test_glass.wav # 预期输出: # Audio Event Detection Demo # Result: glass_break # [ALERT] Local alarm triggered
# 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
输入层: 98 维特征向量 ↓ 标准化 (z-score) 隐藏层: 64 维 (C 端部署) / 128 维 (Python 评估) + ReLU 激活 ↓ 线性变换 输出层: 3 维 logits ↓ Softmax 预测: argmax → 类别索引
math.h
三条测试音频均在端侧模拟器上完成全流程推理:
完整运行日志见 results/openvela_audiodetect_smoke.log。
在 ESC-50 预处理数据集上进行 7:1.5:1.5 训练/验证/测试划分,共 1600 个样本(background 1200 / cough 200 / glass_break 200),测试集 240 个样本。
训练采用类别加权交叉熵 + 少数类过采样以缓解数据不平衡问题:
各类别 Precision / Recall / F1:
混淆矩阵(行=真实类别,列=预测类别):
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 个背景)上评估不同阈值:
低阈值(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 的精确率仍偏低。改进方向:
C 端部署版(98→64→3):
Python 评估版(98→128→3):
特征提取阶段(MFCC FFT 等)计算量稍大,但使用预计算表(mfcc_tables.h)加速,总运算量仍在数十 KFLOPs 量级。
mfcc_tables.h
在服务器(Intel x86_64)上使用 Python/NumPy 测量全流程延迟,测试集 240 个样本:
Python/NumPy 延迟主要来自 MFCC FFT 计算(逐帧 256 点 FFT + Mel 滤波器组)。C 端使用预计算表(mfcc_tables.h)和定点优化,预期延迟更低。
模拟器环境下推理在 NSH 命令响应周期内完成(日志中命令输入后立即输出结果),实测无感知延迟。实际硬件延迟取决于 I2S/PDM 采集时间。
model_weights.h
tiny_mlp_esc50.npz
tiny_mlp_esc50_mfcc.npz
tiny_mlp.npz
当前模拟器版本使用 WAV 文件模拟麦克风输入、printf 输出告警。迁移到 DshanPixVela-DevKit V1 等硬件时,只需替换两个模块:
printf
wav_reader.c
mic_i2s_reader.c
mic_pdm_reader.c
printf("[ALERT]")
gpio_set_value(LED_PIN, 1)
buzzer_on()
以下核心模块保持不变:
feature_extractor.c
model_infer.c
详见 docs/migration_to_devkit.md。
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 │ │ │ └─────────────────────────────────────────────────┘
stdio.h
stdlib.h
本项目用于音频事件检测比赛,所有代码和文档可自由用于学习和竞赛目的。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
版权所有:中国计算机学会技术支持:开源发展技术委员会 京ICP备13000930号-9 京公网安备 11010802047560号
Lightweight Offline Audio Event Detection for OpenVela
离线端侧音频事件检测系统 — 面向 OpenVela/NuttX 嵌入式部署的轻量级音频分类与告警方案。
支持 3 类音频事件 检测:
background(背景噪声)、cough(咳嗽)、glass_break(玻璃破碎),在端侧完成从音频采集到特征提取、模型推理、本地告警的全闭环流程。系统架构
完整闭环:采集 → 预处理/特征提取 → 模型识别 → 输出/告警,全部在端侧完成,不依赖云端或外部服务器。
目录结构
快速开始
方式零:一键执行脚本(推荐)
0a. OpenVela 端侧全流程一键运行
一条命令完成:源码同步 → 构建注册 → 编译 → WAV注入 → 启动模拟器 → 3类音频推理 → 结果汇总。
脚本自动执行 7 个步骤:
openvela_app/audiodetect/下 13 个文件复制到 OpenVelaapps/树apps/Kconfig和apps/Make.defs中注册 audiodetectdefconfig中写入CONFIG_AE_AUDIODETECT=y./build.sh ... --cmake -j4,已构建则自动跳过mcopy将 3 个测试 WAV 写入vela_data.binFAT 镜像-no-window) 启动,自动执行 3 条推理命令输出日志保存到
results/openvela_audiodetect_smoke.log。支持自定义路径:
0b. Linux C 推理一键验证
无需 OpenVela,在任意 Linux 服务器上编译并运行 C 推理:
脚本自动执行:
make clean && make→ 搜索 WAV 文件 → 运行推理 → 输出结果。方式一:Python 训练 Pipeline(Windows / Linux)
方式二:Linux C 独立演示
方式三:OpenVela 模拟器端侧运行
模型设计
特征提取
网络结构
math.h类别定义与触发口径
backgroundcoughglass_break测试结果
OpenVela Goldfish ARM64 模拟器验证
三条测试音频均在端侧模拟器上完成全流程推理:
完整运行日志见
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 个样本。
训练采用类别加权交叉熵 + 少数类过采样以缓解数据不平衡问题:
各类别 Precision / Recall / F1:
混淆矩阵(行=真实类别,列=预测类别):
误报与漏报分析(多阈值)
告警触发条件:预测为 cough 或 glass_break 且 置信度 > 阈值。在测试集 240 个样本(60 个事件 + 180 个背景)上评估不同阈值:
主要瓶颈:训练数据不平衡(background:cough:glass = 6:1:1),尽管已使用类别加权和过采样,cough 和 glass_break 的精确率仍偏低。改进方向:
延迟与资源占用
计算量分析
C 端部署版(98→64→3):
Python 评估版(98→128→3):
内存占用
延迟测试
Python 离线测量(NumPy,单样本)
在服务器(Intel x86_64)上使用 Python/NumPy 测量全流程延迟,测试集 240 个样本:
端侧延迟(OpenVela Goldfish ARM64 模拟器)
模型体积
model_weights.htiny_mlp_esc50.npztiny_mlp_esc50_mfcc.npztiny_mlp.npz硬件迁移方案
当前模拟器版本使用 WAV 文件模拟麦克风输入、
printf输出告警。迁移到 DshanPixVela-DevKit V1 等硬件时,只需替换两个模块:wav_reader.cmic_i2s_reader.c或mic_pdm_reader.cprintf("[ALERT]")gpio_set_value(LED_PIN, 1)或buzzer_on()以下核心模块保持不变:
feature_extractor.c— 特征提取model_infer.c— 模型推理model_weights.h— 模型权重详见
docs/migration_to_devkit.md。端侧闭环流程
技术栈
math.h/stdio.h/stdlib.h)许可证
本项目用于音频事件检测比赛,所有代码和文档可自由用于学习和竞赛目的。ESC-50 数据集遵循其原始许可证(CC BY-NC-SA 3.0)。