搜索
bottom↓
回复: 9

在F3上实现IIR数字滤波器,求援

[复制链接]

出0入0汤圆

发表于 2013-4-17 19:49:03 | 显示全部楼层 |阅读模式
本帖最后由 max-men 于 2013-4-17 19:50 编辑

     这段时间被IIR摧残了千百遍,足足两个多星期一点进展都没有。心情很是不爽像大姨父来了般。其间几度要放弃了,但问题是存在的,有问题还是得去解决,无奈在此求助坛友。如有坛友帮忙解决愿以充话费形式答谢(注:本人学生党一枚,所涉问题无商业利益,少量话费以表谢意)。

   如果问题得到解决我会将源代码完整奉上,以供坛友学习研究之用。如果你不明白IIR数字滤波器,如果你想学习了解数字滤波器,麻烦将帖子顶上去让更多的人看到。

背景:平台是STM32F3DISCOVERY, 开发环境MDK。

目的:AD采集数据(正弦信号20<F<20K),用IIR在F3实现数字滤波,DA输出滤波后的结果。(AD、DA均为片内)

遇到的问题:我要实现的是一个带通滤波器,为验证程序的正确我先做了一个简单的低通滤波器,滤波器系数是在MATLAB fadtool中生成的(系数生成步骤如下图)。现在的问题是假如我要实现一个通带为200Hz的低通,实际出来的是在通带内就不断衰减,不到200Hz基本就滤完了的一个“低通”。滤波器代码如下。

  1. /*  这是一个四阶IIR滤波函数
  2.    *Src:是AD采样回的数据指针
  3.    *Dst:运算完要送给DA的数据指针
  4.   *coffs:滤波器系数指针
  5.    **State:运算中需要的状态量指针
  6.    Number:一次处理的数据量
  7. */
  8. void IIR_Filter(float32_t *Src,float32_t *Dst,float32_t *coffs,float32_t *State,uint8_t Number)
  9. {
  10.         float32_t b0,b1,b2,b3,b4,a1,a2,a3,a4;
  11.         float32_t x,y,x1,x2,x3,x4,y1,y2,y3,y4;
  12.         float32_t acc;
  13.        
  14.         b0 = *coffs++;  
  15.         b1 = *coffs++;
  16.         b2 = *coffs++;
  17.         b3 = *coffs++;
  18.         b4 = *coffs++;
  19.         a1 = *coffs++;
  20.         a2 = *coffs++;
  21.         a3 = *coffs++;
  22.         a4 = *coffs;
  23.        
  24.         x1 = State[0];
  25.         x2 = State[1];
  26.         x3 = State[2];
  27.         x4 = State[3];
  28.         y1 = State[4];
  29.         y2 = State[5];
  30.         y3 = State[6];
  31.         y4 = State[7];
  32.        
  33.         while(Number--)
  34.         {
  35.                  x = *Src++;
  36.                                
  37.                     acc = b0*x + b1*x1 + b2*x2 + b3*x3 + b4*x4;
  38.                  y = acc-a1*y1 - a2*y2 - a3*y3 - a4*y4;
  39.                 x1 = x;
  40.                 x2 = x1;
  41.                 x3 = x2;               
  42.                 x4 = x3;

  43.                 y1 = y;
  44.                 y2 = y1;               
  45.                 y4 = y3;
  46.                 y3 = y2;

  47.                 *Dst++ = y;
  48.         }
  49.        
  50.         *State++ = x1;
  51.         *State++ = x2;
  52.         *State++ = x3;
  53.         *State++ = x4;

  54.         *State++ = y1;
  55.         *State++ = y2;
  56.         *State++ = y3;
  57.         *State    = y4;
  58. }
复制代码


  1.  /*中断处理函数**/
  2. #include "stm32f30x_it.h"
  3. #include "Mine_iir.h"

  4. #define BlockSize 100               /*每次处理数据块的大小*/
  5. #define NumberOfConvertedValue 200  /*ADC,DAC数组大小*/

  6. extern __IO uint16_t  ADC1ConvertedValue[NumberOfConvertedValue];
  7.             float32_t Float32_ADC1ConvertedValue[NumberOfConvertedValue];

  8.             float32_t Float32_DAC1ConvertedValue[NumberOfConvertedValue];
  9.       __IO  uint16_t  DAC1ConvertedValue[NumberOfConvertedValue];

  10.             /* 系数表*/
  11.             float32_t CoeffTable[9] = {0.0004, 0.0017, 0.0025, 0.0017,0.0004,
  12.                                       -3.1806,3.8612, -2.1122,0.4383};       
  13.             /*状态变量*/
  14.             float32_t State[8]={0};

  15. void DMA1_Channel1_IRQHandler(void)
  16. {
  17.       uint8_t j;
  18.        

  19.         if(DMA_GetITStatus(DMA1_IT_HT1))
  20.         {
  21.         DMA1->IFCR = DMA1_IT_GL1|DMA1_IT_HT1;  /*Clears the DMAy Channelx's interrupt pending bits*/       
  22.                
  23.         for(j=0;j<BlockSize;j++)      //将无符号数转换为浮点数
  24.           Float32_ADC1ConvertedValue[j]= ((float32_t)ADC1ConvertedValue[j])-683; //减直流分量
  25.                
  26.         IIR_Filter(Float32_ADC1ConvertedValue,Float32_DAC1ConvertedValue,CoeffTable,State,BlockSize);
  27.                
  28.          
  29.         for(j=0;j<BlockSize;j++)     //将浮点数转换为无符号数
  30.           DAC1ConvertedValue[j]=(uint16_t)(Float32_DAC1ConvertedValue[j]+683);//加直流分量
  31.         }
  32.         else
  33.         {
  34.           DMA1->IFCR = DMA1_IT_GL1|DMA1_IT_TC1; /*Clears the DMAy Channelx's interrupt pending bits*/       
  35.                
  36.           for(j=BlockSize;j<NumberOfConvertedValue;j++)   //将无符号数转换为浮点数
  37.              Float32_ADC1ConvertedValue[j]=((float32_t)ADC1ConvertedValue[j])-683;//减直流分量
  38.                
  39.           IIR_Filter(&Float32_ADC1ConvertedValue[BlockSize],&Float32_DAC1ConvertedValu[BlockSize],CoeffTable,State,BlockSize);           
  40.                
  41.           for(j=BlockSize;j<NumberOfConvertedValue;j++)  //将浮点数转换为无符号数
  42.              DAC1ConvertedValue[j]=(uint16_t)(Float32_DAC1ConvertedValue[j]+683);//加直流分量                        
  43.         }       

  44. }

复制代码


       我的滤波函数一次处理一个数据块,而不是一次只处理一个数据。这样做的目的是让内核少进中断提高效率。由于ADC、DAC速率要一致,而运算一个数据的时间要小于采样间隔,这就带来速度不一致的问题,解决的办法是为ADC到处理、处理到DAC之间构造缓冲区。我的方法是用DMA构造双缓冲区。实现如下
  1、先定义两个长度相同数组,一个数组内存放ADC转换所得到的数,另一个数组存放滤波完要送给DAC的数。
开启ADC的DMA传输一半中断、传输完中断。

  2、用定时器去触发ADC单次采样以实现采样率的控制。一次采样转换完后触发DMA将数据传到上面所定义的采样数组内。当传输完采样数组一半的数据后进入半传输完中断,在中断中处理前一半的数据,处理完的数据保存在1)中定义的DAC数组前半段内。在处理前一半数据的同时,ADC、DMA并没有停止,而是同时进行采样传送,因为DMA传送并不会打断内核的运行。当采样数组被填满后进入DMA传输完中断,同样在中断中处理后一半的采样数据,并把数据送到滤波完数组的后半段。因为前半段的采样数据已经处理完,在处理采后半段数据的同时新的数据可以覆盖旧的数据。

     3、把DAC同样设置成定时器触发,并且和ADC用同一定时器。开启DAC的DMA,将滤波完的数据输出。只要处理一半数据的时间小于采样一半数据的时间就可以实现ADC连续采样的同时DAC以相同速率连续输出。

   我不知道我的问题是不是出在滤波函数上,这里我也把我的工程传上来,一来可以给各位一点点参考,二来是让高人帮我找到问题的所在。(DMA构造双缓冲区,这个方法应该是没有错的),在此先行谢过!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

阿莫论坛才是最爱国的,关心国家的经济、社会的发展、担心国家被别国牵连卷入战争、知道珍惜来之不易的和平发展,知道师夷之长,关注世界的先进文化与技术,也探讨中国文化的博大精深,也懂得警惕民粹主义的祸国殃民等等等等,无不是爱国忧民的表现。(坛友:tianxian)

出215入169汤圆

发表于 2013-4-17 20:03:00 | 显示全部楼层
http://www.amobbs.com/thread-4165021-1-1.html
请看这个帖的1楼,代码在40楼下载

出0入442汤圆

发表于 2013-4-17 20:05:01 | 显示全部楼层
所谓的低通滤波,并不是说超过200Hz才会衰减,而是指到200Hz时衰减达到k个dB,具体多少我忘了,反正就是衰减到70.7%。即,200Hz的低通指200Hz频率时衰减到原始信号的70.7%(或者是衰减70.7%,我也忘了),因此信号确实是一直衰减的,先缓后急。

出0入0汤圆

 楼主| 发表于 2013-4-17 20:26:16 | 显示全部楼层
wye11083 发表于 2013-4-17 20:05
所谓的低通滤波,并不是说超过200Hz才会衰减,而是指到200Hz时衰减达到k个dB,具体多少我忘了,反正就是衰 ...

我设置的是-3dB通带,不会出现从一开始10Hz就衰减吧??

出0入0汤圆

 楼主| 发表于 2013-4-17 20:34:32 | 显示全部楼层
monkeynav 发表于 2013-4-17 20:03
http://www.amobbs.com/thread-4165021-1-1.html
请看这个帖的1楼,代码在40楼下载

之前就翻过这个帖子,他的参照他的帖子我还是找不出我的问题

出215入169汤圆

发表于 2013-4-18 22:42:21 | 显示全部楼层
max-men 发表于 2013-4-17 20:34
之前就翻过这个帖子,他的参照他的帖子我还是找不出我的问题

那个帖子就是我发的,我换了一个帐号。
你可以使用那个验证过的代码,看看响应是否一样

出0入0汤圆

发表于 2013-5-14 17:54:30 | 显示全部楼层
max-men 发表于 2013-4-17 20:26
我设置的是-3dB通带,不会出现从一开始10Hz就衰减吧??

楼主能截图下用fdtool设计的时候的波形么,看看和实际的情况能否对得上,如果有偏差再找原因,没有偏差那就是参数设置问题

出0入0汤圆

发表于 2013-10-7 23:44:35 | 显示全部楼层
楼主滤波的数据要设置成static,不然会出现短暂不连续现象。

出0入0汤圆

发表于 2014-5-7 16:38:19 | 显示全部楼层
IIR滤波器

出0入0汤圆

发表于 2016-11-25 11:04:06 | 显示全部楼层
max-men 发表于 2013-4-17 20:34
之前就翻过这个帖子,他的参照他的帖子我还是找不出我的问题

楼主,我用F3定时触发采集SDADC,我的SDADC采集频率无论定时器设置多大都无法达到50K的采样频率,最高好像只有十几K采样频率,但是用连续转换采样就可以达到50K的频率,楼主遇到过没有?
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-16 15:57

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表