基于STM32单片机的声音定位

一、系统架构设计

1. 硬件组成

  • 主控芯片:STM32F407ZGT6(168MHz主频,1MB Flash,192KB RAM)
  • 麦克风阵列:4路驻极体话筒(INMP441 MEMS麦克风,I2S接口)
  • 信号调理:AD8429仪表放大器(增益100-1000倍) + 带通滤波器(500Hz-2kHz)
  • 无线传输:ESP8266 WiFi模块(数据上传至上位机)
  • 电源管理:TPS63060升降压芯片(3.3V/5V输出)

2. 系统框图

[声源] → [麦克风阵列] → [信号调理] → [STM32] → [WiFi] → [上位机]
               ↑               ↑
           硬件同步      TDOA计算

二、核心算法实现

1. 信号采集与同步

// 多通道ADC配置(STM32 HAL库)
ADC_HandleTypeDef hadc1;

void MX_ADC1_Init(void) {
    ADC_ChannelConfTypeDef sConfig = {0};
    
    hadc1.Instance = ADC1;
    hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV2;
    hadc1.Init.Resolution = ADC_RESOLUTION_12B;
    hadc1.Init.ScanConvMode = ENABLE;  // 启用扫描模式
    hadc1.Init.ContinuousConvMode = ENABLE;
    hadc1.Init.NbrOfConversion = 4;    // 4路麦克风
    HAL_ADC_Init(&hadc1);
    
    // 配置4个通道
    sConfig.Channel = ADC_CHANNEL_0;
    HAL_ADC_ConfigChannelAttenuation(&hadc1, ADC_CHANNEL_0, ADC_ATTENUATION_11DB);
    // 同理配置CH1-CH3
}

// 定时器触发采样(TIM2)
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
    if(htim->Instance == TIM2) {
        for(int i=0; i<4; i++) {
            mic_buffer[i][buffer_idx] = HAL_ADC_GetValue(&hadc1); 
        }
        buffer_idx++;
    }
}

2. TDOA计算(交叉相关法)

// 计算两路信号的时间差(单位:采样点)
int16_t calculate_tdoa(float *sig1, float *sig2, int len) {
    float max_corr = 0;
    int16_t lag = 0;
    
    for(int lag=-MAX_DELAY; lag<=MAX_DELAY; lag++) {
        float corr = 0;
        for(int i=0; i<len; i++) {
            int idx = i + lag;
            if(idx >=0 && idx < len) {
                corr += sig1[i] * sig2[idx];
            }
        }
        if(corr > max_corr) {
            max_corr = corr;
            if(lag < 0) lag_abs = -lag;
            else lag_abs = lag;
        }
    }
    return lag_abs;
}

// 四麦克风定位计算
void locate_source() {
    // 计算各麦克风间时延
    int16_t tdoa_12 = calculate_tdoa(mic1_buf, mic2_buf, FRAME_SIZE);
    int16_t tdoa_13 = calculate_tdoa(mic1_buf, mic3_buf, FRAME_SIZE);
    int16_t tdoa_14 = calculate_tdoa(mic1_buf, mic4_buf, FRAME_SIZE);
    
    // 声速343m/s,转换为距离差
    float d12 = tdoa_12 * 343.0 / SAMPLE_RATE;
    float d13 = tdoa_13 * 343.0 / SAMPLE_RATE;
    float d14 = tdoa_14 * 343.0 / SAMPLE_RATE;
    
    // 最小二乘法定位(参考)
    float A[3][3] = {
        {2*x2, 2*y2, 2},
        {2*x3, 2*y3, 2},
        {2*x4, 2*y4, 2}
    };
    float B[3] = {
        x2*x2 + y2*y2 - x1*x1 - y1*y1 + d12*d12,
        x3*x3 + y3*y3 - x1*x1 - y1*y1 + d13*d13,
        x4*x4 + y4*y4 - x1*x1 - y1*y1 + d14*d14
    };
    
    // 解线性方程组
    solve_linear_equations(A, B, 3, result);
}

三、硬件设计要点

1. 信号调理电路

麦克风 → 前置放大 → 带通滤波 → 电平转换 → STM32 ADC
           │         │          │
           ▼         ▼          ▼
        AD8429    Sallen-Key   INA128
        (增益100) (500Hz-2kHz)  (差分输入)

2. 时钟同步设计

  • 硬件同步:使用STM32的HCLK同步所有ADC采样时钟
  • 软件校准:通过参考信号(1kHz正弦波)校准时钟偏差
// 时钟校准函数
void calibrate_clock() {
    // 发送1kHz参考信号到所有麦克风
    generate_reference_signal();
    
    // 记录各通道过零点时间差
    for(int i=0; i<4; i++) {
        tdelays[i] = measure_zero_crossing();
    }
    
    // 计算时钟偏差
    float avg_delay = average(tdelays);
    adjust_adc_clock(avg_delay);
}

四、定位算法优化

1. 噪声抑制策略

  • 频域滤波:FFT后抑制非目标频段(如低于300Hz或高于5kHz)
  • 波束形成:延迟求和波束形成增强目标方向信号
// 波束形成算法
void beamforming(float *input, float *output) {
    static float weights[4] = {0.5, 0.5, 0.5, 0.5};
    for(int i=0; i<FRAME_SIZE; i++) {
        output[i] = 0;
        for(int j=0; j<4; j++) {
            output[i] += weights[j] * input[j*FRAME_SIZE + i];
        }
    }
}

2. 动态环境适应

  • 自适应滤波:LMS算法消除混响干扰
  • 多径抑制:基于到达时间分布的路径筛选

五、上位机软件设计

1. 数据可视化界面

  • 实时定位显示:2D/3D声源位置动态跟踪
  • 频谱分析:瀑布图显示声源频谱特征
  • 定位精度统计:误差分布直方图

2. 通信协议

{
    "header": "LOCATE",
    "data": {
        "x": 2.35,
        "y": 1.87,
        "z": 0.0,
        "confidence": 0.92,
        "timestamp": 1697798400
    }
}

参考代码 基于STM32单片机实现的声音定位系统 www.youwenfan.com/contentcnl/71225.html

建议结合STM32Cube.AI进行算法加速,使用HAL库优化中断响应时间。实际部署时需根据环境噪声特性调整滤波参数。

posted @ 2025-11-10 11:42  yes_go  阅读(25)  评论(0)    收藏  举报