- UID
- 1023166
- 性别
- 男
- 来自
- 燕山大学
|
最近处理14位ad采集并显示的项目,在数据处理过程中的一点感悟给大家分享,给新手一点借鉴吧。
需求很简答,采集3路ad值并在12864液晶上显示即可。
1. 刚开始测试的时候,写完ad的驱动get_ad(ch),就拿来显示了,ok了。
2. 为了防止数据偶尔的波动,多采集N次,做个平均值吧
//求平均值
u16 get_average(u16* buf, u16 len)
{
u16 i;
u16 sum = 0;
for(i=0; i< len; i++)
{
sum += buf;
}
return (u16)(sum/len);
}这样处理后,效果好点,但是还是有波动。
3. 在想想办法把,每次采集20个数据,然后从小到大排序,丢弃最大的和最小的4个数据,然后对中间的12个数据求平均。
//排序
void rank_array(u16 *data, u8 len)
{
u8 i,j;
u16 temp;
for(i=0; i<len-1; i++)
{
for(j=i+1; j<len; j++)
{
if(*(data+i) > *(data+j))
{
temp = *(data+i);
*(data+i) = *(data+i);
*(data+j) = temp;
}
}
}
}
这样处理完后,自己感觉还可以,装上机器后调试,发现采集ad值还是有变化,而且变化很灵敏,老板说这样变化太快,客户会觉得我们这个机器不稳定的…
4. 这怎么搞,没办法做一个平滑处理吧,给每路ad分配一个buf[N]空间,保存最近采集的N次数据,每次保存的ad值保存到buf[SP]中,SP在0~N-1之间变化,输出的有效值为buf中所有数据的平均值。N值取得越大,平滑的效果越明显,
u16 filter(u16 data)
{
static u16 data_buf[N] = {0}; //保存N次采集的ad值
static u8 data_sp = 0; //需要替换数据的下标
static u8 data_len = 1; //记录当前数数的长度
u32 sum = 0;//求和
u16 avr;//求平均
u8 i;
data_buf[data_sp] = data;//替换旧的值
for(i=0; i<data_len; i++)
{
sum += data_buf;
}
avr = (u16)(sum/data_len);//递推平均值
return avr;
}
这样处理后,效果很明显了,比较平滑了,可是老板测试的时候又说啦,这个效果还可以,但是启动和关闭的时候,变化太慢了,这个效果可以不行啊。。。
4. 做了平滑处理,能不慢吗?不过老板的需要总是有道理的,就在想啊,怎么样解决这个问题了。。。啊,有了,变化慢的时候平滑处理就行了,单变化快,急促的时候,就让输出及时更新就行了!怎么处理了?
给每个ad设置一个变化差值,ADdet,当变化超过了这个ADdet值的时候,就把buf[N]中的数据给清空了,只保存这次采集到的AD值到buf中,重新开始做平滑处理。
//输出两个数据的差值
u16 absolute(u16 a, u16 b)
{
if(a > b) return a-b;
else return b-a;
}
//数据平滑处理
u16 filter(u16 data)
{
static u16 data_buf[N] = {0}; //保存N次采集的ad值
static u8 data_sp = 0; //需要替换数据的下标
static u8 data_len = 1; //记录当前数数的长度
static u16 old_avr = 0;//保存上次的平均值
u32 sum = 0;//求和
u16 avr;//求平均
u8 i;
if( absolute(old_avr, data) > ADdet)//这个数据是个异常
{
data_len = 1;
data_sp = 0;
}
data_buf[data_sp] = data;//替换旧的值
for(i=0; i<data_len; i++)
{
sum += data_buf;
}
avr = (u16)(sum/data_len);//递推平均值
old_avr = avr;
return avr;
}
修改后测试效果还是不错的,终于可以歇歇了。。。。
但是后来又有其他的数据需要处理了,老板说,这个突变,你还不能马上更新,数据上 有个情况会导致数据突然变为0,而且是没规律的,这个突变还不能马上显示。。。。
接着改问题吧。。。不过这个问题是工程中的特殊情况,解决方案就不写出来了。。。
在改方案的过程中参考了网上的一些数据滤波的方法 |
|