Files
Dorm-Air-Conditioner-Smart-…/audio_model_esp32.h
2025-09-19 00:51:18 +08:00

355 lines
10 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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