monkeynav 发表于 2013-8-21 18:08:47

【炒冷饭】STM32实现IIR滤波器,可用matlab生成的头文件

本帖最后由 monkeynav 于 2013-8-21 18:09 编辑

原帖刊载于ourdev:http://www.amobbs.com/thread-4165021-1-1.html
原帖代码搞错,也无法编辑,很多人又找不到后面的更正,为了不误导更多人,就在这里重新发一遍。

这里提供用于AVR和STM32的IIR滤波器代码下载,保证可用,不需要额外修改:

------------------------------------------------------------------------------------------------------------------------------------------------------

放假实在无聊,即将到来的高三非常恐怖,先偷闲一把。

matlab的fdatool是好东西,不过很多人不知道该怎么使用它生成的C头文件。

该程序已经用于心电采集实验




不多说,切入正题

这里有个fdatool设计的IIR高通滤波器,采样率400Hz时截止频率1Hz。
设计定型之后,要做些调整。

以下说明中的英文名词有些可能对不上fdatool界面上的原文,请大家意会吧

第一步:
点击菜单中的Edit->Convert Structure 选择Direct Form I ,SOS,(必须是Direct Form I,II不行)
一般情况下,按照默认设置,fdatool设计都是由二阶部分串联组成的。
这种结构的滤波器稳定性比一个section的要好很多,其他方面的性能也好些。
如果不是的话,点击Convert to second order sections。
这时,滤波器的结构(structure)应该显示为 Direct Form I,second order sections

第二步:
选择quantize filter,精度选择single precision floating point (单精度浮点)
之所以不用定点是因为噪声太大,也不容易稳定。
点击菜单中的Targets -> generate c header ,选择export as:single precision floating point (单精度浮点)
填写变量名称时,把NUM改成IIR_B,DEN改成IIR_A,其他不用动,保存为iir_coefs.h

保存好的文件如下:
//一大堆注释
//然后:
/* General type conversion for MATLAB generated C-code*/
#include "tmwtypes.h"
/*
* Expected path to tmwtypes.h
* C:\Program Files\MATLAB\R2010a\extern\include\tmwtypes.h
*/
/*
* Warning - Filter coefficients were truncated to fit specified data type.
*   The resulting response may not match generated theoretical response.
*   Use the Filter Design & Analysis Tool to design accurate
*   single-precision filter coefficients.
*/
#define MWSPT_NSEC 9
const int NL = { 1,3,1,3,1,3,1,3,1 };
const real32_T IIR_B = {
{
   0.8641357422,            0,            0
},
{
                1,             -2,            1
},
{
   0.9949035645,            0,            0
},
{
                1,   -1.999938965,            1
},
{
   0.9985351563,            0,            0
},
{
                1,    -1.99987793,            1
},
{
   0.9996337891,            0,            0
},
{
               1,    -1.99987793,            1
},
{
                1,            0,            0
}
};
const int DL = { 1,3,1,3,1,3,1,3,1 };
const real32_T IIR_A = {
{
                1,            0,            0
},
{
                1,   -1.938049316,   0.9401855469
},
{
                1,            0,            0
},
{
                1,   -1.989501953,   0.9900512695
},
{
                1,            0,            0
},
{
                1,   -1.996887207,   0.9971923828
},
{
                1,            0,            0
},
{
                1,   -1.999084473,   0.9993286133
},
{
                1,            0,            0
}
};


第三步:
打开iir_coefs.h把MWSPT_NSEC替换成IIR_NSEC,
NL、DL数组删除掉,real32_T改成float ,
其中有一个#include "twmtypes.h",不要它了,删掉
改完的文件如下:

#define IIR_NSEC 9
//原来叫做MWSPT_NSEC


const float IIR_B = {
//为什么改为float很明显了吧
{
    0.8641357422,            0,            0
},
{
                1,            -2,            1
},
{
    0.9949035645,            0,            0
},
{
                1,-1.999938965,            1
},
{
    0.9985351563,            0,            0
},
{
                1,    -1.99987793,            1
},
{
   0.9996337891,            0,            0
},
{
                1,    -1.99987793,            1
},
{
                1,            0,            0
}
};
const float IIR_A = {
{
                1,            0,            0
},
{
                1,-1.938049316,0.9401855469
},
{
                1,            0,            0
},
{
                1,-1.989501953,0.9900512695
},
{
                1,            0,            0
},
{
                1,-1.996887207,0.9971923828
},
{
                1,            0,            0
},
{
                1,-1.999084473,0.9993286133
},
{
                1,            0,            0
}
};


保存文件,然后使用以下代码进行滤波
这段代码是根据Direct Form I 2阶IIR滤波的差分方程编写的
a0*y = b0*x + b1*x + b2*x - a1*y -a2*y;


#include "../platform.h"
//#include "iir_coefs.float.flat.h"
//#include "iir_coefs.float.sharp.h"
#include "iir_coefs_pass@2Hz_stop@0.8Hz.h"
#include "iir_filter.h"
static float y;
static float x;
//IIR_NSEC阶直接型II IIR滤波器
//IIR_NSEC个二阶biquad串联
int16 iir_filter(int16 in)
{
      uint16 i;
      
      x = in;
      
      for(i=0;i<IIR_NSEC;i++)
      {
      
      //y = x*IIR_B +x*IIR_B +x*IIR_B-y*IIR_A-y*IIR_A;
          y = 0;
         
          if(IIR_B == 1) y+=x;
          else if(IIR_B == -1) y-=x;
          else if(IIR_B == -2) y=y-x-x;
          else if(IIR_B == 0);   
          else y += x*IIR_B;
         
          if(IIR_B == 1) y+=x;
          else if(IIR_B == -1) y-=x;
          else if(IIR_B == -2) y=y-x-x;
          else if(IIR_B == 0);
          else y += x*IIR_B;
         
          if(IIR_B == 1) y+=x;
          else if(IIR_B == -1) y-=x;
          else if(IIR_B == -2) y=y-x-x;
          else if(IIR_B == 0);
          else y += x*IIR_B;
         
          if(IIR_A == 1) y-=y;
          else if(IIR_A == -1) y+=y;
          else if(IIR_A == -2) y=y+y+y;
          else if(IIR_A == 0);
          else y -= y*IIR_A;
         
          if(IIR_A == 1) y-=y;
          else if(IIR_A == -1) y+=y;
          else if(IIR_A == -2) y=y+y+y;
          else if(IIR_A == 0);
          else y -= y*IIR_A;
         
          if(IIR_A != 1) y /= IIR_A;
         
          y=y;y=y;
          x=x;x=x;
         
          x = y;
      }
      
      if( x>32767)x=32767;
      if( x<-32768) x=-32768;
      return((int16)x);   
      
}
//复位滤波器
void iir_reset(void)
{
    uint16 i,j;
   
    for(i=0;i<IIR_NSEC+1;i++)
    {
       for(j=0;j<3;j++)
       {
          x=0;
       }
    }
   
    for(i=0;i<IIR_NSEC;i++)
    {
       for(j=0;j<3;j++)
       {
          y=0;
       }
    }
}


//iir_filter.h
#ifndef _IIR_FILTER_H__
#define _IIR_FILTER_H__
int16 iir_filter(int16 x);
void iir_reset(void);
#endif


使用方法:
首先写好iir_coefs.h,然后调用iir_filter.c对数据流进行滤波
一个伪代码例子:
while(运行中)
{
保存到SD卡(iir_filter(读取ADC采样值()));
}

这个函数比STM32 DSP库中的函数要好很多,DSP库中的2个IIR滤波函数都不能连续处理数据流。
记得在开始滤波之前重置滤波器
iir_reset();

renpeng009 发表于 2013-8-21 18:12:39

好深奥的样子

dhbighead 发表于 2013-8-21 18:15:28

猴子好厉害

jlian168 发表于 2013-8-21 21:23:33

you are so good.

wns245249509 发表于 2013-8-21 23:02:00

楼主高三 就研究这样的技术。。给力啊。。。

fangchangqing 发表于 2013-8-28 12:28:14

来了看看

longfeix86 发表于 2013-8-28 12:49:39

楼主真心NB,不知道师从何处?

277955973 发表于 2013-8-28 13:26:26

才高三就做这个..厉害厉害

kalo425 发表于 2014-5-28 19:22:34

高三就这样···我高三还和(huo)尿泥呢````{:sweat:}···求方法指导··{:lol:}

clarkewayne 发表于 2014-5-29 10:35:50

這個不錯,多謝分享

凌晨一点 发表于 2014-6-11 00:34:39

请问你的心电50hz工频干扰如何除掉?

凌晨一点 发表于 2014-6-11 17:55:44

请问楼主,50hz陷波的代码是单独的吗在哪里?
楼主文件中这个代码干什么的
const int16 IIR_G = {
/*    14158,16301,16360,16378,*/15417,16384
      };
      

bbglx 发表于 2014-11-27 19:25:12

楼主啊,你这个貌似会误导人。{:sweat:}
贴的是高通滤波,Direct Form I,参数是浮点型。
但是附件是陷波,Direct Form II,参数是整形。

ddaitt999复活 发表于 2015-2-3 22:02:46

楼主您好!有急事儿找您,请联系我QQ:150496749,拜托

ddaitt999复活 发表于 2015-2-3 22:03:14

楼主您好!有急事儿找您,请联系我QQ:150496749,拜托

香橙批 发表于 2015-2-3 22:12:40

这个需要配合什么硬件吗?

love_zjb 发表于 2015-2-3 22:26:27

这个比较赞!

机器人天空 发表于 2015-2-4 17:09:33

一直都没搞懂50hz工频陷波{:mad:}

wszyjsw2 发表于 2015-2-4 22:30:35

IIR滤波器

sangmo2015 发表于 2015-2-10 08:43:15

无限脉冲响应滤波器

martin007 发表于 2015-2-10 08:48:44

牛掰!学习了,50Hz陷波,我一般都是电容电阻T陷波器,回头看看这个

tang0571 发表于 2015-2-10 08:51:35

高三同学nb!顶

jorry 发表于 2015-11-29 21:18:22

学习一下!!!

thyewfty 发表于 2017-9-8 15:57:07

学习下--------{:smile:}
页: [1]
查看完整版本: 【炒冷饭】STM32实现IIR滤波器,可用matlab生成的头文件