zouzhichao 发表于 2016-4-28 19:58:54

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

本帖最后由 zouzhichao 于 2016-4-28 22:14 编辑

常用于滤除工频干扰(以下代码有错误,请参看下面修改后的代码)
int filter(int data)
{
        #define filter_len 10
        static int buffer = {0};
        static int* buffer_p = (int*)buffer + (filter_len - 1);
        static int sum = (filter_len >> 1);
        sum -= *buffer_p;
        if (buffer_p == buffer)
        {
                buffer_p += filter_len;
        }
        *(--buffer_p) = data;
        sum += data;
        return sum / filter_len;
}

修正后的代码:
int filter(int data)
{
        #define filter_len 10
        static int buffer = {0};
        static int* buffer_p = (int*)buffer + (filter_len - 1);
        static int sum = (filter_len >> 1);
        sum -= *buffer_p;
        *buffer_p-- = data;
        sum += data;
        if (buffer_p < buffer)
        {
                buffer_p += filter_len;
        }
        return sum / filter_len;
}

a136498491 发表于 2016-4-28 20:30:37

没看懂哪里滑动了

EMC菜鸟 发表于 2016-4-28 20:42:37

保存9个历史数据,跟当前的一起平均!

Gline77 发表于 2016-4-28 20:47:44

历史数据和当前数据存放在   static int buffer里

冷月无声 发表于 2016-4-28 21:02:00

谢谢,也帮顶一下

Gline77 发表于 2016-4-28 21:05:55

本帖最后由 Gline77 于 2016-4-28 21:13 编辑

#define filter_len 10         
static int buffer = {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;
}
这样写会好理解一点!

johncoop 发表于 2016-4-28 21:23:27

本帖最后由 johncoop 于 2016-4-28 21:24 编辑

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

lcw_swust 发表于 2016-4-28 21:30:16

static int sum = (filter_len >> 1);
这里相当于以后的平均值都加了0.5,是算作四舍五入?
是个不错的办法。
不过,buffer和sum都是int型,不怕溢出么?
sum最好还是用long吧。

zouzhichao 发表于 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,如果真用到了,确实需要考虑溢出问题

zouzhichao 发表于 2016-4-28 21:36:26

johncoop 发表于 2016-4-28 21:23
mark,收藏了 讲解下程序就更好了

讲解看你的楼下

johncoop 发表于 2016-4-28 21:40:06

zouzhichao 发表于 2016-4-28 21:36
讲解看你的楼下

多谢大神们

zouzhichao 发表于 2016-4-28 21:50:41

不好意思,代码贴错了,回去再改回来

zouzhichao 发表于 2016-4-28 22:14:42

a136498491 发表于 2016-4-28 20:30
没看懂哪里滑动了

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

zouzhichao 发表于 2016-4-28 22:15:26

EMC菜鸟 发表于 2016-4-28 20:42
保存9个历史数据,跟当前的一起平均!

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

zouzhichao 发表于 2016-4-28 22:16:07

Gline77 发表于 2016-4-28 21:05
#define filter_len 10         
static int buffer = {0};         
static int* buffer_p =...

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

zouzhichao 发表于 2016-4-28 22:16:25

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

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

zouzhichao 发表于 2016-4-28 22:17:03

johncoop 发表于 2016-4-28 21:23
mark,收藏了 讲解下程序就更好了

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

zouzhichao 发表于 2016-4-28 22:17:24

冷月无声 发表于 2016-4-28 21:02
谢谢,也帮顶一下

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

zouzhichao 发表于 2016-4-28 22:18:04

摄氏零度 发表于 2016-4-28 21:48
谢谢分享

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

zcllom 发表于 2016-4-28 22:54:45

本帖最后由 zcllom 于 2016-4-28 22:58 编辑

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

heicnhei3 发表于 2016-4-28 23:05:12

这个存放位置由后面往前面推,不是很好理解,下面还有一个
http://www.amobbs.com/thread-5421239-1-1.html

zouzhichao 发表于 2016-4-29 08:13:28

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

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

mvip 发表于 2016-4-29 08:45:34

谢谢分享,测试下效果怎么样。

donglaile 发表于 2016-4-29 09:30:27

不错,拿来用用

eeant.net 发表于 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 ;
}

Excellence 发表于 2016-4-29 14:08:05

本帖最后由 Excellence 于 2016-4-29 14:10 编辑

移位代替除法,。。。。

zouzhichao 发表于 2016-4-29 14:50:57

eeant.net 发表于 2016-4-29 13:45
一种节约内存的滤波方法:

int filter(int data)


不错的iir一阶滤波器

yat 发表于 2016-4-29 15:13:44

mark滑动平均滤波

caoxuerji 发表于 2016-4-29 16:10:32

这个四舍五入很巧妙啊

jianplx 发表于 2016-4-29 21:41:00

#define SAMPLING        8                //采样次数(静态变量)
void GetADC(void)
{
        static unsigned char pointer = 0;
        static unsigned intAN1_Data={0};                //AD转换结果
        static unsigned long AN1_sum = 0x00000000;
       
        static unsigned intAN2_Data={0};                //AD转换结果
        static unsigned long AN2_sum = 0x00000000;
       
        if(0 == adst)                        //AD转换结束
        {               
                pointer = (pointer +1) % SAMPLING;                        //滑动指针
                AN1_sum = AN1_sum - AN1_Data;                //累计值减去老数据
                AN1_Data = (unsigned int)(ad0);        //放人新采集的AN1通道数据
                AN1_sum = AN1_sum + AN1_Data;                //累计值添加新数据

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

自由飞儿 发表于 2016-5-11 13:15:16

收藏备用

moyanqd 发表于 2016-5-11 15:06:03

本帖最后由 moyanqd 于 2016-5-11 15:43 编辑

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

richie550 发表于 2016-5-11 15:06:39

收藏慢慢看

cumthe 发表于 2016-5-12 21:45:09

不错,软件滤波

19711972f 发表于 2016-5-12 22:39:27

谢谢分享,学习学习

xin 发表于 2016-5-12 23:46:35

各展神通啊,学习

gzhua20088ssj 发表于 2016-5-25 23:12:49

这个小算法还不错,滑动平均相当于低通滤波,在重力勘探和测井的资料处理解释中常用此方法。

longwu537 发表于 2016-5-26 07:15:28

额,感觉楼主是不是把问题复杂化了?要用为什么不直接用数组下标循环判断,比这个要好用,好理解,还不会出错

ycping 发表于 2016-5-26 08:25:16

楼主再加个去抖动才完美,也就是限幅。比如说现在对回来的是10,如果下次读回来的数值比10大5就丢掉。要小于5的才用。防止那些干扰。另外能改成多通道的才实用。

ITOP 发表于 2016-5-26 09:52:20

不错,目前都是用的去头去尾平均法

grash 发表于 2016-5-26 10:08:37

都是程序大牛啊

klxx68 发表于 2016-5-26 10:14:23

学习了,研究一下。

star_tale 发表于 2016-5-26 12:59:57

已阅,没有什么特别之处

star_tale 发表于 2016-5-26 13:00:12

这也叫开源

zouzhichao 发表于 2016-5-26 13:22:03

star_tale 发表于 2016-5-26 13:00
这也叫开源

呵呵         

wangyj173 发表于 2016-5-26 16:44:34

收藏,能共享就不错了

foxpro2005 发表于 2016-8-13 23:09:21

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

int filter(int data)
{
    #define filter_len 10
    static unsigned char state = 0;
    static long int total = (filter_len >> 1);
    int per;
   
    if (state) {
      total += data;
    }
    else {
      total += data * filter_len;
      state = 1;
    }
   
    per = total / filter_len;
    total -= per;
   
    return per;
}

ycping 发表于 2016-8-14 09:09:50

记号。。。

lufanshui 发表于 2016-8-19 10:14:50

看不懂!!

ccmj4708 发表于 2016-9-10 07:46:49

不错,有空去测试下

yanghuanchun 发表于 2016-9-10 08:59:29

请教一下,这种滤波器的截至频率怎么计算

dianyuan 发表于 2016-9-10 09:02:55

这里buffer有用处吗?

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

zouzhichao 发表于 2016-9-10 10:12:26

dianyuan 发表于 2016-9-10 09:02
这里buffer有用处吗?

我一般就这样用


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

569350810 发表于 2016-9-10 10:19:42

谢谢分享~

sigma318 发表于 2016-9-10 10:29:39

赞一个。要不要考虑重入性呢?

zouzhichao 发表于 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

wswh2o 发表于 2016-9-10 10:34:58

static int sum = (filter_len >> 1);

wswh2o 发表于 2016-9-10 10:35:28

static int sum = (filter_len >> 1);这句干啥的啊?

zouzhichao 发表于 2016-9-10 16:42:37

wswh2o 发表于 2016-9-10 10:35
static int sum = (filter_len >> 1);这句干啥的啊?

四舍五入

ifus 发表于 2016-9-22 14:21:11

zouzhichao 发表于 2016-9-10 16:42
四舍五入

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

zouzhichao 发表于 2016-9-22 14:22:49

ifus 发表于 2016-9-22 14:21
楼主位的代码,好像至少要 采样次数为 filter_len 10 次后,取平均才会准确吧? ...

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

duxingkei 发表于 2016-9-22 15:32:21

确实,学习了,我以前AD采样都是计算2^n 次的平均值,感觉不怎么好,不带历史值,不怎么平滑,以后可以这么尝试下

ifus 发表于 2016-9-22 16:48:10

zouzhichao 发表于 2016-9-22 14:22
是的,前9次的运算结果其实无效

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

luybpotter 发表于 2017-3-22 13:35:35

最近也在做一款产品,用了楼主的程序之后,在临界点(阀值)的跳动就没有这么频繁了{:lol:}

coslight_dt 发表于 2017-3-24 08:44:32

MaRK.感谢分享~~

didadida 发表于 2017-3-24 09:59:38

顶楼主!!!

cpholr1 发表于 2017-3-24 22:26:50

都是好东西。赞一个

chenl2017 发表于 2017-3-28 10:32:16

学习了{:lol:}

529063382 发表于 2017-3-28 18:22:40


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

vjcmain 发表于 2017-5-9 12:26:47

多通道AD如何处理?

kinsno 发表于 2017-5-9 12:41:53

滑动平均滤波,路过打酱油。。。


xizi 发表于 2017-5-17 10:54:08

zouzhichao 发表于 2016-9-22 14:22
是的,前9次的运算结果其实无效

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

tangguotaizi 发表于 2017-12-20 03:32:50

mark! fir滤波

32MCU 发表于 2017-12-20 08:07:33

滑动滤波收藏。

livekoko 发表于 2017-12-20 14:07:42

收藏了,有条件了测试下

书的那页 发表于 2017-12-21 09:30:59

mark一下

Wisen 发表于 2017-12-21 20:03:02

不错的滤波器,谢谢分享!

hkjabcd 发表于 2018-10-13 10:52:08

试了下效果不错,采集电源噪声小很多

mculjf 发表于 2018-10-13 12:29:57

滑动平均滤波{:lol:}

yayagepei 发表于 2018-10-13 15:33:43

jianplx 发表于 2016-4-29 21:41
#define SAMPLING        8                //采样次数(静态变量)
void GetADC(void)
{


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

yelong98 发表于 2018-10-19 14:29:01

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

这个办法不错,感谢分享

jssd 发表于 2019-11-17 12:25:14

我请教楼主和各位大侠,楼主位的程序用了除法,对于单片机来说还是有点慢了,如果我长度定义为8或者8的倍数,不是可以用移位代替除法了吗?

zouzhichao 发表于 2019-11-17 12:45:56

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

当然可以啊

foxpro2005 发表于 2019-11-17 13:24:21

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

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

liubiao6832170 发表于 2019-12-22 23:35:02

厉害厉害
页: [1]
查看完整版本: 开源一段小代码,滑动平均滤波(代码已经更正)