单片机中IIR滤波器的应用

在这里插入代码片@[toc]

概要

直接I型IIR滤波器是基于二阶Biquad级联的方式来实现的。每个Biquad由一个二阶的滤波器组成:
y[n] = b0 * x[n] + b1 * x[n-1] + b2 * x[n-2] - a1 * y[n-1] - a2 * y[n-2]

Matlab相关参数获取
在matlab中运行

`Matlab相关参数获取
Fs = 40e3;    % 采样频率
Fcut = 1e3;     % 截止频率
N = 4;          % 滤波器阶数
% 计算归一化截止频率
Wn = Fcut / (Fs/2);
% 使用butter函数计算滤波器系数
[b, a] = butter(N, Wn, 'low');
disp('b coefficients:');
disp(b);
disp('a coefficients:');
disp(a);

`## 技术名词解释

提示:这里可以添加技术名词解释


```c
IIR滤波算法
#define NUM_TAPS 4 // 滤波器阶数
int input[200] = {}; // 输入信号(AD采集的数据)
float  output[200]; // 输出信号
float a[NUM_TAPS + 1] = {1, -3.5897, 4.8513, -2.9241, 0.663}; // 滤波器系数a
float  b[NUM_TAPS + 1] = {0.0000312, 0.000125,0.0001874, 0.000125, 0.0000312}; // 滤波器系数b
int  delayLine[NUM_TAPS + 1]; // 延迟线
void IIR_Filter(int * input, float* output, int numSamples)
{
    for (int j = 0; j < numSamples; j++)
    {
        // 更新延迟线
        for (int i = NUM_TAPS; i > 0; i--)
        {
            delayLine[i] = delayLine[i - 1];
        }
        delayLine[0] = input[j];

        // 计算输出
        float    sum = 0;
        for (int i = 0; i <= NUM_TAPS; i++)
        {
            sum += b[i] * delayLine[i];
            if (i > 0)
            {
                sum -= a[i] * output[j - i];
            }
        }
        output[j] = sum ;
    }
}

int main(void)

```c
{
	int m ;
	systick_config();
	USART0_init();
	timer1_config();
    // 初始化延迟线
    for (int i = 0; i <= NUM_TAPS; i++)
    {
        delayLine[i] = 0;
   }
    // 调用IIR滤波器
    IIR_Filter(input, output, 200);

    // 输出滤波后的数字
    for (int i = 0; i < 200; i++)
    {
        printf("%f,\r\n", output[i]);
    }
    while(1);
}

在这里插输入输出数据
入图片描述
输入输出数据对比
matlab输出输出对比程序

    y = A1;
    figure(1);
    plot(y);%画出输入信号图形
    title('输入信号');
    
    Hd = fir;%引入滤波器,Hd包含了fir_8滤波器的各项参数
    d = filter(Hd,y);%通过filter函数将信号y送入参数为Hd的滤波器,输出信号d
    figure(2);
    plot(d);%画出通过滤波器的信号d的波形
    title('输出信号');
    
    figure(3);
    plot(y,'r');%画出输入信号图形
    hold on;%保持画出的输入信号图形
    plot(d,'b');%画出输出信号波形
    title('输入/输出信号');
    legend('输入信号','输出信号');

matlabIIR滤波器设计方法
matlabIIR滤波器设计方法:对于不同类型的滤波器需要转化结构类型,FS的采样频率需要与AD的采样频率保持一致,它是滤波器的采样频率,FS越大在前面延时数据越多,可以通过调节FS来确定理想的滤波器。FC是截至频率。上述的IIR滤波算法是单节类型的结构。

在有DSP功能的单片机中可以使用DSP中的IIR库函数进行数据的实时处理****以下对DSP,iir库进行简单说明

/****************IIR滤波**********************/
#define numStages 2 /* 2阶IIR滤波的个数 */
#define TEST_LENGTH_SAMPLES 200 /* 采样点数 */
#define BLOCK_SIZE 200 /* 调用一次arm_biquad_cascade_df1_f32处理的采样点个数 */
uint32_t blockSize = BLOCK_SIZE;
uint32_t numBlocks = TEST_LENGTH_SAMPLES/BLOCK_SIZE; /* 需要调用arm_biquad_cascade_df1_f32的次数 */
float32_t testInput_f32_50Hz_200Hz[TEST_LENGTH_SAMPLES]={0}; /* 采样点 */
float32_t testOutput[TEST_LENGTH_SAMPLES]; /* 滤波后的输出 */
static float32_t IIRStateF32[4*numStages]; /* 状态缓存 */
arm_biquad_casd_df1_inst_f32 S;
static int  m=0 ;
static int  n=0 ;
 
/* 巴特沃斯低通滤波器系数 */ 
const float32_t IIRCoeffs32LP[5*numStages] = { 
1.0f, 2.0f, 1.0f, 1.987804709796042512692793025053106248379f, 
-0.988049970587248416187264865584438666701f,
1.0f, 2.0f, 1.0f, 1.971148608851041927891856175847351551056f, 
-0.971391814566879729930803932802518829703f `在这里插入代码片`
};
uint16_t adc_dma_value[200];

static void arm_iir_f32_lp(void)
{
    uint32_t i;
 //   arm_biquad_casd_df1_inst_f32 S;
//    float32_t ScaleValue;
    float32_t  *inputF32, *outputF32;
    
    /* 初始化输入输出缓存指针 */
    inputF32 = &testInput_f32_50Hz_200Hz[0];
    outputF32 = &testOutput[0];
    
    
    /* 初始化 */
	if(m==0){
    arm_biquad_cascade_df1_init_f32(&S, numStages, (float32_t *)&IIRCoeffs32LP[0], 
(float32_t *)&IIRStateF32[0]);
		m=1;
    }
    /* 实现IIR滤波,这里每次处理1个点 */
	
    for(i=0; i < numBlocks; i++)
    {
        arm_biquad_cascade_df1_f32(&S, inputF32 + (i * blockSize),  outputF32 + (i * blockSize),
  blockSize);
    }
            
}

``

unsigned int GetAD (void)
{

	int i ;
	float32_t sum=0.f ;
	float32_t average ;
	float32_t ScaleValue;
	float32_t result;
	long AD_Value=0;
//	n++;
//标定值,arm_biquad_cascade_df1_f32();函数输出的out数据需要乘以标定值才是真实值
	ScaleValue = 0.000061315197801517181720731830552040265f * 0.000060801428959431312582222667328935017f ;
	
	//数据类型转化
	for (i = 0; i < TEST_LENGTH_SAMPLES; i++) {
        testInput_f32_50Hz_200Hz[i] = adc_dma_value[i];
    }
	arm_iir_f32_lp();
	if(n<3)
	{
		n++;
		return Threshold;
	}
	for (i = 0; i < 200; i++) {
        sum += testOutput[i]*ScaleValue;
    }
    average = (float)sum / 200;
	//result  = average*ScaleValue;
	AD_Value=(int)average;
	return (uint16_t )AD_Value;		  
}

上述代码实现ADC不停的采集数据,通过DMA传输,DMA每采集200个数据就触发中断,在DMA中断中运行getAD()函数进行滤波处理。实现了每采集两百个数据进行一次滤波的实时处理,可以对采集数据和处理数据进行修改。其中的n用来避免刚开始运行的时候产生的无效数据对整体功能的影响,m用来限制只初始化一次,然后持续运行出来函数。

arm_biquad_cascade_df1_init_f32();初始化函数
arm_biquad_cascade_df1_f32();处理函数

上述IIR滤波器的结构,和参数的获取可以参考[添加链接描述](https://img.anfulai.cn/bbs/94547/%E5%AE%89%E5%AF%8C%E8%8E%B1_STM32-V5%E5%BC%80%E5%8F%91%E6%9D%BF_%E7%AC%AC2%E7%89%88DSP%E6%95%B0%E5%AD%97%E4%BF%A1%E5%8F%B7%E5%A4%84%E7%90%86%E6%95%99%E7%A8%8B%EF%BC%88V2.7%EF%BC%89.pdf)

实时处理需要注意在DMA执行中断程序的时候,ADC还是会持续工作,表示DMA传输的地址中的值还是会持续的更新。




## 技术细节
` 提示:这里可以添加技术细节`

例如:
* API
* 支持模型类型

## 小结
` 提示:这里可以添加总结`

例如:

提供先进的推理,复杂的指令,更多的创造力。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值