搜索
bottom↓
回复: 84

开源一段小代码,滑动平均滤波(代码已经更正)

  [复制链接]

出10入23汤圆

发表于 2016-4-28 19:58:54 | 显示全部楼层 |阅读模式
本帖最后由 zouzhichao 于 2016-4-28 22:14 编辑

常用于滤除工频干扰(以下代码有错误,请参看下面修改后的代码)
  1. int filter(int data)
  2. {
  3.         #define filter_len 10
  4.         static int buffer[filter_len] = {0};
  5.         static int* buffer_p = (int*)buffer + (filter_len - 1);
  6.         static int sum = (filter_len >> 1);
  7.         sum -= *buffer_p;
  8.         if (buffer_p == buffer)
  9.         {
  10.                 buffer_p += filter_len;
  11.         }
  12.         *(--buffer_p) = data;
  13.         sum += data;
  14.         return sum / filter_len;
  15. }
复制代码


修正后的代码:
  1. int filter(int data)
  2. {
  3.         #define filter_len 10
  4.         static int buffer[filter_len] = {0};
  5.         static int* buffer_p = (int*)buffer + (filter_len - 1);
  6.         static int sum = (filter_len >> 1);
  7.         sum -= *buffer_p;
  8.         *buffer_p-- = data;
  9.         sum += data;
  10.         if (buffer_p < buffer)
  11.         {
  12.                 buffer_p += filter_len;
  13.         }
  14.         return sum / filter_len;
  15. }
复制代码

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

如果想吃一顿饺子,就得从冰箱里取出肉,剁馅儿,倒面粉、揉面、醒面,擀成皮儿,下锅……
一整个繁琐流程,就是为了出锅时那一嘴滚烫流油的热饺子。

如果这个过程,禁不住饿,零食下肚了,饺子出锅时也就不香了……《非诚勿扰3》

出0入0汤圆

发表于 2016-4-28 20:30:37 | 显示全部楼层
没看懂哪里滑动了

出5入14汤圆

发表于 2016-4-28 20:42:37 | 显示全部楼层
保存9个历史数据,跟当前的一起平均!

出0入0汤圆

发表于 2016-4-28 20:47:44 来自手机 | 显示全部楼层
历史数据和当前数据存放在   static int buffer[filter_len]里

出0入0汤圆

发表于 2016-4-28 21:02:00 | 显示全部楼层
谢谢,也帮顶一下

出0入0汤圆

发表于 2016-4-28 21:05:55 来自手机 | 显示全部楼层
本帖最后由 Gline77 于 2016-4-28 21:13 编辑

#define filter_len 10         
static int buffer[filter_len] = {0};         
static int* buffer_p = (int*)buffer + (filter_len - 1);        
static int sum = (filter_len >> 1);         

int filter(int data)
{         
sum -= *buffer_p;      
  if (buffer_p == buffer)        
{   
             buffer_p += filter_len;      
   }      
  *(--buffer_p) = data;        
sum += data;      
   return sum / filter_len;
}
这样写会好理解一点!

出0入0汤圆

发表于 2016-4-28 21:23:27 | 显示全部楼层
本帖最后由 johncoop 于 2016-4-28 21:24 编辑

mark,收藏了 讲解下程序就更好了

出0入0汤圆

发表于 2016-4-28 21:30:16 | 显示全部楼层
static int sum = (filter_len >> 1);
这里相当于以后的平均值都加了0.5,是算作四舍五入?
是个不错的办法。
不过,buffer和sum都是int型,不怕溢出么?
sum最好还是用long吧。

出10入23汤圆

 楼主| 发表于 2016-4-28 21:35:56 来自手机 | 显示全部楼层
lcw_swust 发表于 2016-4-28 21:30
static int sum = (filter_len >> 1);
这里相当于以后的平均值都加了0.5,是算作四舍五入?
是个不错的办法 ...

You get it
一般不会溢出,24bit的ad一般filter len不会使用超过100,如果真用到了,确实需要考虑溢出问题

出10入23汤圆

 楼主| 发表于 2016-4-28 21:36:26 来自手机 | 显示全部楼层
johncoop 发表于 2016-4-28 21:23
mark,收藏了 讲解下程序就更好了

讲解看你的楼下

出0入0汤圆

发表于 2016-4-28 21:40:06 | 显示全部楼层

多谢大神们

出10入23汤圆

 楼主| 发表于 2016-4-28 21:50:41 来自手机 | 显示全部楼层
不好意思,代码贴错了,回去再改回来

出10入23汤圆

 楼主| 发表于 2016-4-28 22:14:42 | 显示全部楼层
a136498491 发表于 2016-4-28 20:30
没看懂哪里滑动了

谢谢提醒,原来的代码确实没有滑动,现在已修正!

出10入23汤圆

 楼主| 发表于 2016-4-28 22:15:26 | 显示全部楼层
EMC菜鸟 发表于 2016-4-28 20:42
保存9个历史数据,跟当前的一起平均!

代码已经更正,请参看楼主位

出10入23汤圆

 楼主| 发表于 2016-4-28 22:16:07 | 显示全部楼层
Gline77 发表于 2016-4-28 21:05
#define filter_len 10         
static int buffer[filter_len] = {0};         
static int* buffer_p =  ...

代码已经更正,请参看楼主位

出10入23汤圆

 楼主| 发表于 2016-4-28 22:16:25 | 显示全部楼层
lcw_swust 发表于 2016-4-28 21:30
static int sum = (filter_len >> 1);
这里相当于以后的平均值都加了0.5,是算作四舍五入?
是个不错的办法 ...

代码已经更正,请参看楼主位

出10入23汤圆

 楼主| 发表于 2016-4-28 22:17:03 | 显示全部楼层
johncoop 发表于 2016-4-28 21:23
mark,收藏了 讲解下程序就更好了

代码已经更正,请参看楼主位

出10入23汤圆

 楼主| 发表于 2016-4-28 22:17:24 | 显示全部楼层

代码已经更正,请参看楼主位

出10入23汤圆

 楼主| 发表于 2016-4-28 22:18:04 | 显示全部楼层

代码已经更正,请参看楼主位

出330入0汤圆

发表于 2016-4-28 22:54:45 | 显示全部楼层
本帖最后由 zcllom 于 2016-4-28 22:58 编辑

刚才写错了,更正
这个代码没问题。
写的也比较简练。

出0入0汤圆

发表于 2016-4-28 23:05:12 | 显示全部楼层
这个存放位置由后面往前面推,不是很好理解,下面还有一个
http://www.amobbs.com/thread-5421239-1-1.html

出10入23汤圆

 楼主| 发表于 2016-4-29 08:13:28 来自手机 | 显示全部楼层
heicnhei3 发表于 2016-4-28 23:05
这个存放位置由后面往前面推,不是很好理解,下面还有一个
http://www.amobbs.com/thread-5421239-1-1.html ...

从后往前推和从前往后推都可以,主要是在那个if那里效率,所以选择从后往前

出0入0汤圆

发表于 2016-4-29 08:45:34 | 显示全部楼层
谢谢分享,测试下效果怎么样。

出0入0汤圆

发表于 2016-4-29 09:30:27 | 显示全部楼层
不错,拿来用用

出0入0汤圆

发表于 2016-4-29 13:45:26 | 显示全部楼层
一种节约内存的滤波方法:

int filter(int data)
{
        #define filter_len 10
       static long int total = 0;
       static per = 0;
      
      total += data;
      per = total / filter_len ;
      total  -= per ;
     return per ;
}

出0入0汤圆

发表于 2016-4-29 14:08:05 | 显示全部楼层
本帖最后由 Excellence 于 2016-4-29 14:10 编辑

移位代替除法,。。。。

出10入23汤圆

 楼主| 发表于 2016-4-29 14:50:57 | 显示全部楼层
eeant.net 发表于 2016-4-29 13:45
一种节约内存的滤波方法:

int filter(int data)

不错的iir一阶滤波器

出0入0汤圆

发表于 2016-4-29 15:13:44 | 显示全部楼层
mark  滑动平均滤波

出0入0汤圆

发表于 2016-4-29 16:10:32 | 显示全部楼层
这个四舍五入很巧妙啊

出0入0汤圆

发表于 2016-4-29 21:41:00 | 显示全部楼层
#define SAMPLING        8                //采样次数(静态变量)
void GetADC(void)
{
        static unsigned char pointer = 0;
        static unsigned int  AN1_Data[SAMPLING]={0};                //AD转换结果
        static unsigned long AN1_sum = 0x00000000;
       
        static unsigned int  AN2_Data[SAMPLING]={0};                //AD转换结果
        static unsigned long AN2_sum = 0x00000000;
       
        if(0 == adst)                        //AD转换结束
        {               
                pointer = (pointer +1) % SAMPLING;                        //滑动指针
                AN1_sum = AN1_sum - AN1_Data[pointer];                //累计值减去老数据
                AN1_Data[pointer] = (unsigned int)(ad0);        //放人新采集的AN1通道数据
                AN1_sum = AN1_sum + AN1_Data[pointer];                //累计值添加新数据

                AN2_sum = AN2_sum - AN2_Data[pointer];                //累计值减去老数据
                AN2_Data[pointer] = (unsigned int)(ad1);        //放人新采集的AN2通道数据
                AN2_sum = AN2_sum + AN2_Data[pointer];                //累计值添加新数据
               
                CURRENT = (unsigned int)(AN2_sum / SAMPLING);
                VOLTAGE = (unsigned int)(AN1_sum / SAMPLING);
               
                adst = 1;//开始AD转换
        }       
}

出0入0汤圆

发表于 2016-5-11 13:15:16 | 显示全部楼层
收藏备用

出0入0汤圆

发表于 2016-5-11 15:06:03 | 显示全部楼层
本帖最后由 moyanqd 于 2016-5-11 15:43 编辑

0.5的由来看懂了是和加了5然后除以10

出0入0汤圆

发表于 2016-5-11 15:06:39 | 显示全部楼层
收藏慢慢看

出0入0汤圆

发表于 2016-5-12 21:45:09 来自手机 | 显示全部楼层
不错,软件滤波

出0入0汤圆

发表于 2016-5-12 22:39:27 | 显示全部楼层
谢谢分享,学习学习

出0入0汤圆

发表于 2016-5-12 23:46:35 来自手机 | 显示全部楼层
各展神通啊,学习

出0入0汤圆

发表于 2016-5-25 23:12:49 | 显示全部楼层
这个小算法还不错,滑动平均相当于低通滤波,在重力勘探和测井的资料处理解释中常用此方法。

出0入0汤圆

发表于 2016-5-26 07:15:28 来自手机 | 显示全部楼层
额,感觉楼主是不是把问题复杂化了?要用为什么不直接用数组下标循环判断,比这个要好用,好理解,还不会出错

出0入0汤圆

发表于 2016-5-26 08:25:16 | 显示全部楼层
楼主再加个去抖动才完美,也就是限幅。比如说现在对回来的是10,如果下次读回来的数值比10大5就丢掉。要小于5的才用。防止那些干扰。另外能改成多通道的才实用。

出0入0汤圆

发表于 2016-5-26 09:52:20 | 显示全部楼层
不错,目前都是用的去头去尾平均法

出0入0汤圆

发表于 2016-5-26 10:08:37 | 显示全部楼层
都是程序大牛啊

出0入0汤圆

发表于 2016-5-26 10:14:23 | 显示全部楼层
学习了,研究一下。

出0入0汤圆

发表于 2016-5-26 12:59:57 | 显示全部楼层
已阅,没有什么特别之处

出0入0汤圆

发表于 2016-5-26 13:00:12 | 显示全部楼层
这也叫开源

出10入23汤圆

 楼主| 发表于 2016-5-26 13:22:03 来自手机 | 显示全部楼层
star_tale 发表于 2016-5-26 13:00
这也叫开源

呵呵         

出0入0汤圆

发表于 2016-5-26 16:44:34 | 显示全部楼层
收藏,能共享就不错了

出0入76汤圆

发表于 2016-8-13 23:09:21 | 显示全部楼层
我来贴一个综合26楼改进: 由于一阶滤波是具体滞后性的,在有些应用中,可能在刚开始工作时就需要得出有效的滤波数据值, 如果滤波长度比较长的话,这种滞后会非常明显, 为了避免这种情况, 在这种应用中, 一般要对滤波进行初始化, 即让 sum = n * sample, 之后即可正常滤波处理了。
代码如下:

  1. int filter(int data)
  2. {
  3.     #define filter_len 10
  4.     static unsigned char state = 0;
  5.     static long int total = (filter_len >> 1);
  6.     int per;
  7.    
  8.     if (state) {
  9.         total += data;
  10.     }
  11.     else {
  12.         total += data * filter_len;
  13.         state = 1;
  14.     }
  15.    
  16.     per = total / filter_len;
  17.     total -= per;
  18.    
  19.     return per;
  20. }
复制代码


出0入0汤圆

发表于 2016-8-14 09:09:50 | 显示全部楼层
记号。。。

出0入0汤圆

发表于 2016-8-19 10:14:50 | 显示全部楼层
看不懂!!

出0入0汤圆

发表于 2016-9-10 07:46:49 | 显示全部楼层
不错,有空去测试下

出0入0汤圆

发表于 2016-9-10 08:59:29 | 显示全部楼层
请教一下,这种滤波器的截至频率怎么计算

出0入0汤圆

发表于 2016-9-10 09:02:55 | 显示全部楼层
这里buffer[filter_len]有用处吗?

我一般就这样用
sum += data;
sum -= result;
result=sum / filter_len;

出10入23汤圆

 楼主| 发表于 2016-9-10 10:12:26 来自手机 | 显示全部楼层
dianyuan 发表于 2016-9-10 09:02
这里buffer[filter_len]有用处吗?

我一般就这样用

滤波器结构不一样,你这个属于iir滤波器,我的属于fir滤波器

出0入0汤圆

发表于 2016-9-10 10:19:42 | 显示全部楼层
谢谢分享~

出0入0汤圆

发表于 2016-9-10 10:29:39 | 显示全部楼层
赞一个。要不要考虑重入性呢?

出10入23汤圆

 楼主| 发表于 2016-9-10 10:30:37 来自手机 | 显示全部楼层
yanghuanchun 发表于 2016-9-10 08:59
请教一下,这种滤波器的截至频率怎么计算

时域卷积等于频域相乘
所以把系数序列(len个1/len)做傅立叶变换就得到滤波器的幅频特性了,Sin(x)/x=0.717
X=1.3654
频率归一化,Fc=1.3654*Fsample/n/pi=0.4346*Fsample/n

出0入0汤圆

发表于 2016-9-10 10:34:58 | 显示全部楼层
static int sum = (filter_len >> 1);

出0入0汤圆

发表于 2016-9-10 10:35:28 | 显示全部楼层
static int sum = (filter_len >> 1);这句干啥的啊?

出10入23汤圆

 楼主| 发表于 2016-9-10 16:42:37 | 显示全部楼层
wswh2o 发表于 2016-9-10 10:35
static int sum = (filter_len >> 1);这句干啥的啊?

四舍五入

出0入0汤圆

发表于 2016-9-22 14:21:11 | 显示全部楼层

楼主位的代码,好像至少要 采样次数为 filter_len 10 次后,取平均才会准确吧?

出10入23汤圆

 楼主| 发表于 2016-9-22 14:22:49 来自手机 | 显示全部楼层
ifus 发表于 2016-9-22 14:21
楼主位的代码,好像至少要 采样次数为 filter_len 10 次后,取平均才会准确吧? ...

是的,前9次的运算结果其实无效

出0入0汤圆

发表于 2016-9-22 15:32:21 | 显示全部楼层
确实,学习了,我以前AD采样都是计算2^n 次的平均值,感觉不怎么好,不带历史值,不怎么平滑,以后可以这么尝试下

出0入0汤圆

发表于 2016-9-22 16:48:10 | 显示全部楼层
zouzhichao 发表于 2016-9-22 14:22
是的,前9次的运算结果其实无效

谢谢回复,正好可以测试下

出0入4汤圆

发表于 2017-3-22 13:35:35 | 显示全部楼层
最近也在做一款产品,用了楼主的程序之后,在临界点(阀值)的跳动就没有这么频繁了

出0入0汤圆

发表于 2017-3-24 08:44:32 | 显示全部楼层
MaRK.感谢分享~~

出0入0汤圆

发表于 2017-3-24 09:59:38 | 显示全部楼层
顶楼主!!!

出0入0汤圆

发表于 2017-3-24 22:26:50 | 显示全部楼层
都是好东西。赞一个

出0入0汤圆

发表于 2017-3-28 10:32:16 | 显示全部楼层
学习了

出0入0汤圆

发表于 2017-3-28 18:22:40 | 显示全部楼层

顶楼主!!!    为什么是9个而不是其他的 呢

出0入0汤圆

发表于 2017-5-9 12:26:47 | 显示全部楼层
多通道AD如何处理?

出0入0汤圆

发表于 2017-5-9 12:41:53 | 显示全部楼层
滑动平均滤波,路过打酱油。。。


出0入0汤圆

发表于 2017-5-17 10:54:08 | 显示全部楼层
zouzhichao 发表于 2016-9-22 14:22
是的,前9次的运算结果其实无效

应该结合48楼的初始化算法,就可以避免前9次的运算结果无效的问题。

出0入0汤圆

发表于 2017-12-20 03:32:50 来自手机 | 显示全部楼层
mark! fir滤波

出0入0汤圆

发表于 2017-12-20 08:07:33 来自手机 | 显示全部楼层
滑动滤波收藏。

出0入0汤圆

发表于 2017-12-20 14:07:42 | 显示全部楼层
收藏了,有条件了测试下

出0入0汤圆

发表于 2017-12-21 09:30:59 | 显示全部楼层
mark一下

出0入17汤圆

发表于 2017-12-21 20:03:02 | 显示全部楼层
不错的滤波器,谢谢分享!

出0入0汤圆

发表于 2018-10-13 10:52:08 来自手机 | 显示全部楼层
试了下效果不错,采集电源噪声小很多

出0入13汤圆

发表于 2018-10-13 12:29:57 | 显示全部楼层
滑动平均滤波

出0入0汤圆

发表于 2018-10-13 15:33:43 | 显示全部楼层
jianplx 发表于 2016-4-29 21:41
#define SAMPLING        8                //采样次数(静态变量)
void GetADC(void)
{

你这个好理解点,多谢了哈

出0入135汤圆

发表于 2018-10-19 14:29:01 | 显示全部楼层
foxpro2005 发表于 2016-8-13 23:09
我来贴一个综合26楼改进: 由于一阶滤波是具体滞后性的,在有些应用中,可能在刚开始工作时就需要得出有效 ...

这个办法不错,感谢分享

出0入55汤圆

发表于 2019-11-17 12:25:14 来自手机 | 显示全部楼层
我请教楼主和各位大侠,楼主位的程序用了除法,对于单片机来说还是有点慢了,如果我长度定义为8或者8的倍数,不是可以用移位代替除法了吗?

出10入23汤圆

 楼主| 发表于 2019-11-17 12:45:56 来自手机 | 显示全部楼层
jssd 发表于 2019-11-17 12:25
我请教楼主和各位大侠,楼主位的程序用了除法,对于单片机来说还是有点慢了,如果我长度定义为8或者8的倍数 ...

当然可以啊

出0入76汤圆

发表于 2019-11-17 13:24:21 | 显示全部楼层
jssd 发表于 2019-11-17 12:25
我请教楼主和各位大侠,楼主位的程序用了除法,对于单片机来说还是有点慢了,如果我长度定义为8或者8的倍数 ...

长度大小可以定义为2^N次方, 可以用右移N位来代替除法。

出0入0汤圆

发表于 2019-12-22 23:35:02 来自手机 | 显示全部楼层
厉害厉害
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

GMT+8, 2024-3-28 21:21

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

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