开源一段小代码,滑动平均滤波(代码已经更正)
本帖最后由 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;
} 没看懂哪里滑动了 保存9个历史数据,跟当前的一起平均! 历史数据和当前数据存放在 static int buffer里 谢谢,也帮顶一下 本帖最后由 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:24 编辑
mark,收藏了 讲解下程序就更好了 static int sum = (filter_len >> 1);
这里相当于以后的平均值都加了0.5,是算作四舍五入?
是个不错的办法。
不过,buffer和sum都是int型,不怕溢出么?
sum最好还是用long吧。 lcw_swust 发表于 2016-4-28 21:30
static int sum = (filter_len >> 1);
这里相当于以后的平均值都加了0.5,是算作四舍五入?
是个不错的办法 ...
You get it
一般不会溢出,24bit的ad一般filter len不会使用超过100,如果真用到了,确实需要考虑溢出问题 johncoop 发表于 2016-4-28 21:23
mark,收藏了 讲解下程序就更好了
讲解看你的楼下 zouzhichao 发表于 2016-4-28 21:36
讲解看你的楼下
多谢大神们 不好意思,代码贴错了,回去再改回来 a136498491 发表于 2016-4-28 20:30
没看懂哪里滑动了
谢谢提醒,原来的代码确实没有滑动,现在已修正! EMC菜鸟 发表于 2016-4-28 20:42
保存9个历史数据,跟当前的一起平均!
代码已经更正,请参看楼主位 Gline77 发表于 2016-4-28 21:05
#define filter_len 10
static int buffer = {0};
static int* buffer_p =...
代码已经更正,请参看楼主位 lcw_swust 发表于 2016-4-28 21:30
static int sum = (filter_len >> 1);
这里相当于以后的平均值都加了0.5,是算作四舍五入?
是个不错的办法 ...
代码已经更正,请参看楼主位 johncoop 发表于 2016-4-28 21:23
mark,收藏了 讲解下程序就更好了
代码已经更正,请参看楼主位 冷月无声 发表于 2016-4-28 21:02
谢谢,也帮顶一下
代码已经更正,请参看楼主位 摄氏零度 发表于 2016-4-28 21:48
谢谢分享
代码已经更正,请参看楼主位 本帖最后由 zcllom 于 2016-4-28 22:58 编辑
刚才写错了,更正
这个代码没问题。
写的也比较简练。
这个存放位置由后面往前面推,不是很好理解,下面还有一个
http://www.amobbs.com/thread-5421239-1-1.html heicnhei3 发表于 2016-4-28 23:05
这个存放位置由后面往前面推,不是很好理解,下面还有一个
http://www.amobbs.com/thread-5421239-1-1.html ...
从后往前推和从前往后推都可以,主要是在那个if那里效率,所以选择从后往前 谢谢分享,测试下效果怎么样。 不错,拿来用用 一种节约内存的滤波方法:
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:10 编辑
移位代替除法,。。。。 eeant.net 发表于 2016-4-29 13:45
一种节约内存的滤波方法:
int filter(int data)
不错的iir一阶滤波器 mark滑动平均滤波 这个四舍五入很巧妙啊 #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转换
}
} 收藏备用 本帖最后由 moyanqd 于 2016-5-11 15:43 编辑
0.5的由来看懂了是和加了5然后除以10 收藏慢慢看 不错,软件滤波 谢谢分享,学习学习 各展神通啊,学习 这个小算法还不错,滑动平均相当于低通滤波,在重力勘探和测井的资料处理解释中常用此方法。 额,感觉楼主是不是把问题复杂化了?要用为什么不直接用数组下标循环判断,比这个要好用,好理解,还不会出错 楼主再加个去抖动才完美,也就是限幅。比如说现在对回来的是10,如果下次读回来的数值比10大5就丢掉。要小于5的才用。防止那些干扰。另外能改成多通道的才实用。 不错,目前都是用的去头去尾平均法 都是程序大牛啊 学习了,研究一下。 已阅,没有什么特别之处 这也叫开源 star_tale 发表于 2016-5-26 13:00
这也叫开源
呵呵 收藏,能共享就不错了 我来贴一个综合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;
}
记号。。。 看不懂!! 不错,有空去测试下 请教一下,这种滤波器的截至频率怎么计算 这里buffer有用处吗?
我一般就这样用
sum += data;
sum -= result;
result=sum / filter_len; dianyuan 发表于 2016-9-10 09:02
这里buffer有用处吗?
我一般就这样用
滤波器结构不一样,你这个属于iir滤波器,我的属于fir滤波器 谢谢分享~ 赞一个。要不要考虑重入性呢? 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 static int sum = (filter_len >> 1); static int sum = (filter_len >> 1);这句干啥的啊? wswh2o 发表于 2016-9-10 10:35
static int sum = (filter_len >> 1);这句干啥的啊?
四舍五入 zouzhichao 发表于 2016-9-10 16:42
四舍五入
楼主位的代码,好像至少要 采样次数为 filter_len 10 次后,取平均才会准确吧? ifus 发表于 2016-9-22 14:21
楼主位的代码,好像至少要 采样次数为 filter_len 10 次后,取平均才会准确吧? ...
是的,前9次的运算结果其实无效 确实,学习了,我以前AD采样都是计算2^n 次的平均值,感觉不怎么好,不带历史值,不怎么平滑,以后可以这么尝试下
zouzhichao 发表于 2016-9-22 14:22
是的,前9次的运算结果其实无效
谢谢回复,正好可以测试下 最近也在做一款产品,用了楼主的程序之后,在临界点(阀值)的跳动就没有这么频繁了{:lol:} MaRK.感谢分享~~ 顶楼主!!! 都是好东西。赞一个 学习了{:lol:}
顶楼主!!! 为什么是9个而不是其他的 呢 多通道AD如何处理? 滑动平均滤波,路过打酱油。。。
zouzhichao 发表于 2016-9-22 14:22
是的,前9次的运算结果其实无效
应该结合48楼的初始化算法,就可以避免前9次的运算结果无效的问题。
mark! fir滤波 滑动滤波收藏。 收藏了,有条件了测试下 mark一下 不错的滤波器,谢谢分享! 试了下效果不错,采集电源噪声小很多 滑动平均滤波{:lol:} jianplx 发表于 2016-4-29 21:41
#define SAMPLING 8 //采样次数(静态变量)
void GetADC(void)
{
你这个好理解点,多谢了哈 foxpro2005 发表于 2016-8-13 23:09
我来贴一个综合26楼改进: 由于一阶滤波是具体滞后性的,在有些应用中,可能在刚开始工作时就需要得出有效 ...
这个办法不错,感谢分享 我请教楼主和各位大侠,楼主位的程序用了除法,对于单片机来说还是有点慢了,如果我长度定义为8或者8的倍数,不是可以用移位代替除法了吗? jssd 发表于 2019-11-17 12:25
我请教楼主和各位大侠,楼主位的程序用了除法,对于单片机来说还是有点慢了,如果我长度定义为8或者8的倍数 ...
当然可以啊 jssd 发表于 2019-11-17 12:25
我请教楼主和各位大侠,楼主位的程序用了除法,对于单片机来说还是有点慢了,如果我长度定义为8或者8的倍数 ...
长度大小可以定义为2^N次方, 可以用右移N位来代替除法。
厉害厉害
页:
[1]