在STM32F103RC上实现64阶FIR低通滤波器的步骤如下:
1. 生成滤波器系数
使用Python和SciPy生成归一化的64阶FIR低通滤波器系数,截止频率1kHz,采样频率134635Hz:
import numpy as np
from scipy.signal import firwin
fs = 134635 # 采样频率
fc = 1000 # 截止频率
num_taps = 65 # 64阶,65个系数
# 生成汉明窗FIR低通滤波器系数
taps = firwin(num_taps, fc, fs=fs, window='hamming')
# 归一化系数以确保直流增益为1
taps_normalized = taps / np.sum(taps)
# 转换为Q15格式(16位定点数)
q15_coeffs = np.round(taps_normalized * 32767).astype(np.int16)
print("Q15 Coefficients:")
print(q15_coeffs.tolist())
2. 在STM32中配置FIR滤波器
使用CMSIS-DSP库的Q15定点运算实现:
定义系数和状态变量
#include "arm_math.h"
#define NUM_TAPS 65
// Q15格式的滤波器系数
const q15_t firCoeffsQ15[NUM_TAPS] = { /* 粘贴生成的Q15系数 */ };
// 滤波器实例和状态缓冲区
static arm_fir_instance_q15 firInstance;
static q15_t firStateQ15[NUM_TAPS + 1 - 1]; // 块处理所需状态缓冲区
void FIR_Init(void) {
arm_fir_init_q15(&firInstance, NUM_TAPS, (q15_t*)firCoeffsQ15, firStateQ15, 1);
}
处理采样数据
q15_t FIR_ProcessSample(q15_t inputSample) {
q15_t outputSample;
arm_fir_q15(&firInstance, &inputSample, &outputSample, 1);
return outputSample;
}
3. 集成到ADC采样中
在ADC中断处理函数中调用滤波器:
void ADC_IRQHandler(void) {
if (ADC_GetITStatus(ADC1, ADC_IT_EOC) == SET) {
q15_t adcValue = (q15_t)(ADC_GetConversionValue(ADC1) - 2048) << 4; // 12位ADC转Q15
q15_t filtered = FIR_ProcessSample(adcValue);
// 使用filtered数据
ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);
}
}
4. 主函数初始化
int main(void) {
// 系统时钟和ADC初始化
SystemInit();
ADC_Init();
FIR_Init();
while (1) {
// 主循环
}
}
验证滤波器性能
使用Python生成系数后,绘制频率响应以验证截止频率和衰减特性:
import matplotlib.pyplot as plt
from scipy.signal import freqz
w, h = freqz(taps_normalized, fs=fs)
plt.plot(w, 20 * np.log10(np.abs(h)))
plt.axvline(fc, color='red', linestyle='--')
plt.xlim(0, fs/2)
plt.ylim(-60, 5)
plt.xlabel('Frequency (Hz)')
plt.ylabel('Gain (dB)')
plt.grid()
plt.show()
注意事项
- 实时性:STM32F103的72MHz主频足以处理134.635kHz的采样率,每个样本约有534个时钟周期,FIR滤波约需130周期(65阶)。
- 定点运算:使用Q15格式时,确保输入数据正确转换(如12位ADC值转换为有符号Q15)。
- 内存分配:状态缓冲区大小需足够(
NUM_TAPS + block_size - 1
),逐点处理时block_size=1
。
通过上述步骤,即可在STM32F103RC上实现所需的FIR低通滤波器。