欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 创投人物 > 音频识别优化(FFT)

音频识别优化(FFT)

2025/4/19 12:13:56 来源:https://blog.csdn.net/xu_wenming/article/details/147306765  浏览:    关键词:音频识别优化(FFT)

整合多频段检测、动态阈值调整和持续时长验证的完整代码实现,包含详细注释:

#include "esp_dsp.h"
#include "driver/i2s.h"
#include "esp_log.h"
#include "math.h"

static const char* TAG = "ADV_FREQ_DETECT";

/*======= 系统配置 =======*/
#define FFT_SIZE        1024          // FFT点数
#define SAMPLE_RATE     16000         // 采样率
#define NOISE_BINS      50            // 噪声基底计算区间
#define MIN_DURATION    5             // 最小持续帧数(50ms/帧)
#define THRESHOLD_OFFSET 20.0         // 阈值相对噪声基底的偏移量

/*======= 多频段配置 =======*/
typedef struct {
    int target_freq;    // 目标频率(Hz)
    float threshold_db; // 检测阈值(dB)
    int sustain_count;  // 持续计数
    bool triggered;     // 触发状态
} freq_band_t;

// 配置需要检测的三个频段
freq_band_t freq_bands[] = {
    {1000, 0, 0, false},  // 初始阈值设为0,实际运行时动态计算
    {2000, 0, 0, false},
    {3000, 0, 0, false}
};
const int BAND_COUNT = sizeof(freq_bands)/sizeof(freq_band_t);

/*======= 硬件配置 =======*/
__attribute__((aligned(16)))
float fft_input[FFT_SIZE*2];       // FFT输入缓冲
__attribute__((aligned(16)))
float fft_mag[FFT_SIZE/2];         // 幅度谱
__attribute__((aligned(16)))
float window[FFT_SIZE];            // 汉宁窗系数

// I2S配置(根据硬件调整)
#define I2S_CHANNEL     I2S_NUM_0
#define I2S_BUF_SIZE    1024
#define I2S_BCK_PIN     32
#define I2S_WS_PIN      25
#define I2S_DATA_PIN    33

/*======= 核心算法函数 =======*/

// 计算噪声基底(使用前NOISE_BINS个bin)
float calculate_noise_floor(float *spectrum) {
    float sum = 0;
    for(int i=1; i<=NOISE_BINS; i++) { // 从1开始避免DC分量
        sum += spectrum[i];
    }
    return 20 * log10f(sum / NOISE_BINS); // 转换为dB
}

// 检测指定频段是否激活
void check_frequency_band(freq_band_t *band, float *spectrum, float noise_floor) {
    const float freq_res = (float)SAMPLE_RATE / FFT_SIZE;
    const int target_bin = band->target_freq / freq_res;
    const int bin_range = (FREQ_TOLERANCE / freq_res) + 1;

    // 搜索目标区间峰值
    float peak_mag = 0;
    int start_bin = target_bin - bin_range;
    int end_bin = target_bin + bin_range;
    start_bin = start_bin < 1 ? 1 : start_bin; // 跳过DC
    end_bin = end_bin >= FFT_SIZE/2 ? FFT_SIZE/2-1 : end_bin;

    for(int i=start_bin; i<=end_bin; i++) {
        if(spectrum[i] > peak_mag) {
            peak_mag = spectrum[i];
        }
    }

    // 计算实际dB值
    float peak_db = 20 * log10f(peak_mag);
    bool current_detect = (peak_db > (noise_floor + THRESHOLD_OFFSET));

    // 持续时间验证
    if(current_detect) {
        if(++band->sustain_count >= MIN_DURATION) {
            if(!band->triggered) {
                band->triggered = true;
                ESP_LOGI(TAG, "频段%dHz触发! 强度:%.1fdB", 
                        band->target_freq, peak_db);
            }
        }
    } else {
        band->sustain_count = 0;
        if(band->triggered) {
            band->triggered = false;
            ESP_LOGI(TAG, "频段%dHz释放", band->target_freq);
        }
    }
}

/*======= 信号处理流水线 =======*/
void audio_processing_task(void *arg) {
    int16_t raw_data[FFT_SIZE]; // 原始采样缓冲

    while(1) {
        // 1. 采集音频数据
        size_t bytes_read = 0;
        i2s_read(I2S_CHANNEL, raw_data, sizeof(raw_data), &bytes_read, portMAX_DELAY);

        // 2. 预处理:加窗转换
        for(int i=0; i<FFT_SIZE; i++) {
            fft_input[i*2] = (float)raw_data[i] * window[i]; // 实部
            fft_input[i*2+1] = 0;                            // 虚部
        }

        // 3. 执行FFT
        dsps_fft2r_fc32(fft_input, FFT_SIZE);
        dsps_bit_rev_fc32(fft_input, FFT_SIZE);
        dsps_cplx2real_fc32(fft_input, FFT_SIZE);

        // 4. 计算幅度谱
        for(int i=0; i<FFT_SIZE/2; i++) {
            float real = fft_input[i*2];
            float imag = fft_input[i*2+1];
            fft_mag[i] = sqrtf(real*real + imag*imag);
        }

        // 5. 动态阈值计算
        float noise_floor = calculate_noise_floor(fft_mag);

        // 6. 多频段检测
        for(int i=0; i<BAND_COUNT; i++) {
            check_frequency_band(&freq_bands[i], fft_mag, noise_floor);
        }

        vTaskDelay(pdMS_TO_TICKS(10)); // 10ms周期
    }
}

/*======= 初始化函数 =======*/
void init_system() {
    // 初始化I2S
    i2s_config_t i2s_cfg = {
        .mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_PDM,
        .sample_rate = SAMPLE_RATE,
        .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
        .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
        .communication_format = I2S_COMM_FORMAT_STAND_I2S,
        .dma_buf_count = 4,
        .dma_buf_len = I2S_BUF_SIZE,
        .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1
    };
    i2s_pin_config_t pin_cfg = {
        .bck_io_num = I2S_BCK_PIN,
        .ws_io_num = I2S_WS_PIN,
        .data_in_num = I2S_DATA_PIN,
        .data_out_num = -1
    };
    i2s_driver_install(I2S_CHANNEL, &i2s_cfg, 0, NULL);
    i2s_set_pin(I2S_CHANNEL, &pin_cfg);

    // 初始化FFT
    dsps_fft2r_init_fc32(NULL, FFT_SIZE);
    dsps_wind_hann_f32(window, FFT_SIZE); // 生成窗函数

    ESP_LOGI(TAG, "系统初始化完成,开始运行...");
}

void app_main() {
    init_system();
    xTaskCreate(audio_processing_task, "audio_proc", 4096, NULL, 5, NULL);
}

关键增强功能说明

  1. 多频段独立检测

    • 使用freq_band_t结构体管理每个频段的参数

    • 并行检测多个频段,各频段独立维护触发状态

    • 示例配置检测1000Hz、2000Hz、3000Hz三个频段

  2. 自适应噪声基底

    // 噪声基底计算(排除直流分量)
    |[1-50] bins| --> 平均值 --> dB转换 --> 噪声基底
    // 动态阈值 = 噪声基底 + 固定偏移(20dB)
  3. 持续时长验证机制

    graph LR
    A[当前检测到信号] --> B{持续计数 >=5?}
    B -->|是| C[标记触发]
    B -->|否| D[计数+1]
    E[未检测到信号] --> F[复位计数器]
  4. 状态管理优化

    • 触发时记录时间戳,避免重复报警

    • 释放时明确状态变更

    • 提供完整的触发-保持-释放状态周期

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词