模型上线

This commit is contained in:
2025-09-19 00:51:18 +08:00
parent 701efacc2e
commit 71e8bd7532
2 changed files with 1292 additions and 0 deletions

355
audio_model_esp32.h Normal file
View File

@@ -0,0 +1,355 @@
#ifndef AUDIO_MODEL_ESP32_H
#define AUDIO_MODEL_ESP32_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include <math.h>
#include "audio_model_data.h"
// ==================== 模型配置参数 ====================
#define SAMPLE_RATE 16000 // 音频采样率 (Hz)
#define AUDIO_DURATION_MS 2000 // 音频片段时长 (毫秒)
#define N_MELS 32 // Mel频谱图频率bins数量
#define N_FFT 1024 // FFT窗口大小
#define HOP_LENGTH 512 // 跳跃长度
#define NUM_CLASSES 4 // 分类数量
// 计算得出的参数
#define AUDIO_BUFFER_SIZE (SAMPLE_RATE * AUDIO_DURATION_MS / 1000) // 32000 samples
#define MEL_FRAMES ((AUDIO_BUFFER_SIZE - N_FFT) / HOP_LENGTH + 1) // 约63帧
#define INPUT_SIZE (MEL_FRAMES * N_MELS) // 输入特征大小
// 预处理参数
#define MEL_FMIN 0.0f // Mel滤波器最低频率
#define MEL_FMAX 8000.0f // Mel滤波器最高频率
#define WINDOW_TYPE_HANN 1 // 汉宁窗
#define ENERGY_THRESHOLD 0.01f // 音频活动检测阈值
#define CONFIDENCE_THRESHOLD 0.6f // 预测置信度阈值
// ==================== 数据结构定义 ====================
// 音频分类枚举
typedef enum {
AUDIO_CLASS_PERSON_PRESENT = 0, // 室内有人
AUDIO_CLASS_DOOR_CLOSING = 1, // 关门
AUDIO_CLASS_KEY_JINGLING = 2, // 钥匙弹子声
AUDIO_CLASS_PERSON_ABSENT = 3 // 室内无人
} AudioClassType;
// 预测结果结构体
typedef struct {
AudioClassType predicted_class; // 预测的类别
float confidence; // 最高置信度 (0.0 - 1.0)
float class_probabilities[NUM_CLASSES]; // 各类别概率
bool is_valid; // 预测结果是否有效
uint32_t inference_time_us; // 推理耗时(微秒)
} AudioPredictionResult;
// 音频预处理状态
typedef struct {
float* mel_buffer; // Mel特征缓冲区
float* fft_buffer; // FFT计算缓冲区
float* window_buffer; // 窗函数缓冲区
bool is_initialized; // 是否已初始化
} AudioPreprocessor;
// ==================== 核心API函数 ====================
/**
* @brief 初始化音频模型
* @return 0: 成功, -1: 失败
* @note 必须在使用其他函数前调用
*/
int audio_model_init(void);
/**
* @brief 清理音频模型资源
* @note 程序结束时调用,释放内存
*/
void audio_model_cleanup(void);
/**
* @brief 音频预测函数(完整版)
* @param audio_data 输入音频数据指针
* @param audio_length 音频数据长度(样本数)
* @param result 预测结果输出指针
* @return 0: 成功, -1: 失败
*
* 音频数据格式要求:
* - 数据类型: int16_t (16位有符号整数)
* - 采样率: 16000 Hz
* - 声道数: 单声道
* - 数据长度: 32000 samples (2秒)
* - 数值范围: -32768 到 32767
* - 字节序: 小端序(Little Endian)
*
* 示例调用:
* int16_t audio_buffer[AUDIO_BUFFER_SIZE];
* AudioPredictionResult result;
* // ... 填充audio_buffer ...
* int ret = audio_model_predict(audio_buffer, AUDIO_BUFFER_SIZE, &result);
*/
int audio_model_predict(const int16_t* audio_data, int audio_length, AudioPredictionResult* result);
/**
* @brief 音频预测函数(简化版)
* @param audio_data 输入音频数据指针
* @param audio_length 音频数据长度
* @param predicted_class 预测类别输出
* @param confidence 置信度输出
* @return 0: 成功, -1: 失败
*/
int audio_model_predict_simple(const int16_t* audio_data, int audio_length,
AudioClassType* predicted_class, float* confidence);
// ==================== 数据预处理函数 ====================
/**
* @brief 音频数据预处理(完整流程)
* @param audio_data 原始音频数据 (int16_t格式)
* @param audio_length 音频长度
* @param mel_features 输出的Mel特征 (大小为INPUT_SIZE)
* @return 0: 成功, -1: 失败
*
* 预处理步骤:
* 1. 数据类型转换 (int16_t -> float)
* 2. 归一化处理 ([-1.0, 1.0])
* 3. 预加重滤波
* 4. 加窗处理 (汉宁窗)
* 5. FFT变换
* 6. 功率谱计算
* 7. Mel滤波器组
* 8. 对数变换
* 9. 特征归一化
*/
int preprocess_audio_to_mel(const int16_t* audio_data, int audio_length, float* mel_features);
/**
* @brief 音频数据归一化
* @param audio_data 输入音频数据
* @param length 数据长度
* @param normalized_data 归一化后的数据输出
* @return 0: 成功, -1: 失败
*/
int normalize_audio_data(const int16_t* audio_data, int length, float* normalized_data);
/**
* @brief 计算Mel频谱图
* @param audio_float 浮点音频数据
* @param length 数据长度
* @param mel_spectrogram 输出的Mel频谱图
* @return 0: 成功, -1: 失败
*/
int compute_mel_spectrogram(const float* audio_float, int length, float* mel_spectrogram);
/**
* @brief 应用汉宁窗
* @param data 输入数据
* @param length 数据长度
* @param windowed_data 加窗后的数据
* @return 0: 成功, -1: 失败
*/
int apply_hann_window(const float* data, int length, float* windowed_data);
// ==================== 辅助函数 ====================
/**
* @brief 检测音频活动
* @param audio_data 音频数据
* @param length 数据长度
* @param threshold 能量阈值
* @return true: 检测到音频活动, false: 静音
*/
bool detect_audio_activity(const int16_t* audio_data, int length, float threshold);
/**
* @brief 计算音频RMS能量
* @param audio_data 音频数据
* @param length 数据长度
* @return RMS能量值
*/
float calculate_rms_energy(const int16_t* audio_data, int length);
/**
* @brief 获取类别名称(英文)
* @param class_id 类别ID
* @return 类别名称字符串
*/
const char* get_class_name_en(AudioClassType class_id);
/**
* @brief 获取类别名称(中文)
* @param class_id 类别ID
* @return 类别名称字符串
*/
const char* get_class_name_cn(AudioClassType class_id);
/**
* @brief 验证音频数据格式
* @param audio_data 音频数据指针
* @param length 数据长度
* @return true: 格式正确, false: 格式错误
*/
bool validate_audio_format(const int16_t* audio_data, int length);
/**
* @brief 打印预测结果
* @param result 预测结果指针
*/
void print_prediction_result(const AudioPredictionResult* result);
// ==================== 性能监控函数 ====================
/**
* @brief 获取上次推理耗时
* @return 推理时间(微秒)
*/
uint32_t get_last_inference_time_us(void);
/**
* @brief 获取模型内存使用情况
* @param model_memory 模型占用内存(字节)
* @param buffer_memory 缓冲区占用内存(字节)
* @return 0: 成功, -1: 失败
*/
int get_memory_usage(size_t* model_memory, size_t* buffer_memory);
/**
* @brief 获取预测统计信息
* @param total_predictions 总预测次数
* @param successful_predictions 成功预测次数
* @param average_confidence 平均置信度
* @return 0: 成功, -1: 失败
*/
int get_prediction_statistics(uint32_t* total_predictions, uint32_t* successful_predictions,
float* average_confidence);
// ==================== 配置函数 ====================
/**
* @brief 设置置信度阈值
* @param threshold 新的阈值 (0.0 - 1.0)
* @return 0: 成功, -1: 失败
*/
int set_confidence_threshold(float threshold);
/**
* @brief 获取当前置信度阈值
* @return 当前阈值
*/
float get_confidence_threshold(void);
/**
* @brief 启用/禁用调试模式
* @param enable true: 启用, false: 禁用
*/
void set_debug_mode(bool enable);
/**
* @brief 检查调试模式状态
* @return true: 已启用, false: 已禁用
*/
bool is_debug_mode_enabled(void);
// ==================== 错误处理 ====================
/**
* @brief 获取最后一次错误信息
* @return 错误信息字符串
*/
const char* get_last_error_message(void);
/**
* @brief 清除错误状态
*/
void clear_error_status(void);
// ==================== 常量定义 ====================
// 类别名称数组(英文)
static const char* CLASS_NAMES_EN[NUM_CLASSES] = {
"person_present", // 室内有人
"door_closing", // 关门
"key_jingling", // 钥匙弹子声
"person_absent" // 室内无人
};
// 类别名称数组(中文)
static const char* CLASS_NAMES_CN[NUM_CLASSES] = {
"室内有人",
"关门声",
"钥匙声",
"室内无人"
};
// ==================== 模型数据访问函数 ====================
/**
* @brief 获取模型数据指针
* @return 模型数据指针
*/
const unsigned char* get_audio_model_data(void);
/**
* @brief 获取模型数据大小
* @return 模型数据大小(字节)
*/
size_t get_audio_model_size(void);
// ==================== 使用示例 ====================
/*
使用示例代码:
#include "audio_model_esp32.h"
void example_usage() {
// 1. 初始化模型
if (audio_model_init() != 0) {
printf("模型初始化失败\n");
return;
}
// 2. 准备音频数据
int16_t audio_buffer[AUDIO_BUFFER_SIZE];
// ... 从麦克风或其他源获取音频数据 ...
// 3. 验证音频格式
if (!validate_audio_format(audio_buffer, AUDIO_BUFFER_SIZE)) {
printf("音频格式不正确\n");
return;
}
// 4. 进行预测
AudioPredictionResult result;
if (audio_model_predict(audio_buffer, AUDIO_BUFFER_SIZE, &result) == 0) {
// 5. 处理预测结果
if (result.is_valid && result.confidence > 0.6f) {
printf("预测类别: %s (置信度: %.2f)\n",
get_class_name_cn(result.predicted_class),
result.confidence);
}
}
// 6. 清理资源
audio_model_cleanup();
}
音频数据获取示例ESP32 I2S
```c
#include "driver/i2s.h"
void get_audio_data(int16_t* buffer, size_t buffer_size) {
size_t bytes_read;
i2s_read(I2S_NUM_0, buffer, buffer_size * sizeof(int16_t), &bytes_read, portMAX_DELAY);
}
```
*/
#ifdef __cplusplus
}
#endif // AUDIO_MODEL_ESP32_H