EN : 調(diào)用使能位
bType :采樣值類型,'W'=整型、'F'=浮點(diǎn)型、'D'(或其它)=長(zhǎng)整型,參數(shù)類型:字節(jié)
wHi : 采樣值高位字(采樣值為整型是,實(shí)參必須為0),參數(shù)類型,2字節(jié)
wLo : 采樣值低位字,參數(shù)類型,2字節(jié)
rDie : 濾波死區(qū),參數(shù)類型:浮點(diǎn)數(shù)
rMaxErr : 最大允許偏差,參數(shù)類型:浮點(diǎn)數(shù)
rLen :濾波隊(duì)列長(zhǎng)度,參數(shù)類型:浮點(diǎn)數(shù)
出/入口參數(shù):
rSum :累加和,參數(shù)類型:浮點(diǎn)數(shù)
rAve :濾波輸出平均值,參數(shù)類型:浮點(diǎn)數(shù)
命令行:CALL AveFilter, 'W', 0, SMW28, 640.0, 32000.0, 4.0, VD0, VD4
注意:本程序采樣值是參數(shù)類型可適應(yīng)的,用 wHi/wLo 的組合來(lái)適應(yīng)整型、長(zhǎng)整型、浮點(diǎn)型的參數(shù)類型輸入,避免使用多個(gè)相同的子程序來(lái)適應(yīng)不同類型的輸入?yún)?shù)。由 bType 來(lái)指定輸入的參數(shù)類型。
防脈沖干擾移動(dòng)平均值法數(shù)字濾波器的C語(yǔ)言算法及其實(shí)現(xiàn)
在許多的數(shù)據(jù)采集系統(tǒng)中,現(xiàn)場(chǎng)的強(qiáng)電設(shè)備較多,不可避免地會(huì)產(chǎn)生尖脈沖干擾,這種干擾一般持續(xù)時(shí)間短,峰值大,對(duì)這樣的數(shù)據(jù)進(jìn)行數(shù)字濾波處理時(shí),僅僅采用算術(shù)平均或移動(dòng)平均濾波時(shí),盡管對(duì)脈沖干擾進(jìn)行了1/n的處理,但,其剩余值仍然較大。
這種場(chǎng)合最好的策略是:將被認(rèn)為是受干擾的信號(hào)數(shù)據(jù)去掉,這就是防脈沖干擾平均值濾波法的原理。 防脈沖干擾平均值濾波法的算法是:對(duì)連續(xù)的n個(gè)數(shù)據(jù)進(jìn)行排序,去掉其中最大和最小的2個(gè)數(shù)據(jù),將剩余數(shù)據(jù)示平均值。
在一般8051單片機(jī)的應(yīng)用中為了加快數(shù)據(jù)處理速度,n可以取值6。 而對(duì)于具有較快速度的處理器,則n值可以適當(dāng)取大一些。但最好是 n=2^k+2, k為整數(shù),因?yàn)檫@樣在求平均值average=SUM/(n-2)=SUM/2^k時(shí),可以寫(xiě)成average=SUM>>k,用移位的方法,可以加快處理速度。
上述算法顯然還存在一個(gè)不足之處,就是每采集一個(gè)數(shù)據(jù)就要進(jìn)行一次排序,這樣會(huì)大量占用系統(tǒng)寶貴的時(shí)間。這可以通過(guò)存儲(chǔ)當(dāng)前數(shù)據(jù)中的最大值和最小值來(lái)改進(jìn)。具體做法是:系統(tǒng)中用兩個(gè)變量來(lái)存儲(chǔ)當(dāng)前n個(gè)數(shù)據(jù)的最大值和最小值在這個(gè)數(shù)組中的偏移量(也就是數(shù)組下標(biāo),存儲(chǔ)數(shù)組下標(biāo)而直接不存儲(chǔ)數(shù)據(jù)本身是因?yàn)椋涸谝话愕南到y(tǒng)中,n不會(huì)超無(wú)符號(hào)短整形的表示范圍,因此用一個(gè)char形變量就可以存儲(chǔ)了而如果直接存儲(chǔ)數(shù)據(jù)本身,則許多情況下要用int形變量,甚至更長(zhǎng)的類型)。這樣只要在當(dāng)前輸入的數(shù)據(jù)將要覆蓋的數(shù)據(jù)正好是當(dāng)前的最大值或最小值時(shí)才在下個(gè)數(shù)組中查找最大值或最小值,而其他情況下則只要將輸入的數(shù)據(jù)與最大值和最小值比較就可以修改下最大值和最小值了,而且不用進(jìn)行數(shù)據(jù)排序。
這個(gè)算法很簡(jiǎn)單,下面是對(duì)應(yīng)的C語(yǔ)言代碼實(shí)現(xiàn),可以很方便的應(yīng)用的具體的51單片機(jī)或其他處理器上,只須做少量的修改。
#include"stdio.h"
#define dtype unsigned int // 采集數(shù)據(jù)的數(shù)據(jù)類型
#define uint8 char
#define LEN 6 //移動(dòng)算術(shù)平均的個(gè)數(shù)+2=SHIFT<<2+2
#define SHIFT 2 //2^SHIFT
uint8 pdata; //移動(dòng)指針
uint8 pmax,pmin; //記錄數(shù)據(jù)表中最大值和最小值的位置,在一般的數(shù)據(jù)采集系統(tǒng)中,數(shù)據(jù)的長(zhǎng)度>=8,因此用指針記錄而不是直接記錄最大值和最小值
dtype datas[LEN];
dtype szlb(dtype _data)
{
/****************************/
/* 在調(diào)用此子程序前必須對(duì) pdata,datas[]數(shù)組, pmax,pmin進(jìn)行初始化 */
/****************************/
uint8 i;
dtype average=0; //清零,用來(lái)計(jì)算平均值
pdata=(pdata+1)%LEN; //指針下標(biāo)在0到LEN-1上滑動(dòng)
datas[pdata]=_data; //采樣所得數(shù)據(jù)存入數(shù)據(jù)表中
for(i=0;i<LEN;i++)
average+=datas[i]; //求所有數(shù)據(jù)總和
/*******去除被認(rèn)為是脈沖的數(shù)據(jù)******/
if(_data>datas[pmax])
pmax=pdata; //得到最大值的指針
else if(_data<datas[pmin])
pmin=pdata; //得到最小值的指針
if(pdata==pmax) //如果當(dāng)前輸入值將存入當(dāng)前最大值的位置時(shí)
{ //由以上方法將不可行,必須從其他位置中查找極值
for(i=0;i<LEN;i++)
if(datas[i]>datas[pmax])
pmax=i;
}
else if(pdata==pmin)//如果當(dāng)前輸入值將存入當(dāng)前最大值的位置時(shí)
{ //由以上方法將不可行,必須從其他位置中查找極值
for(i=0;i<LEN;i++)
if(datas[i]<datas[pmin])
pmin=i;
}
average=average-datas[pmax]-datas[pmin];//減去脈沖
return (average>>SHIFT); //求算術(shù)平均值
}
/******以下是在VC++6.0環(huán)境下運(yùn)行的測(cè)試程序**/
/***通過(guò)手動(dòng)輸入來(lái)模擬數(shù)據(jù)采集過(guò)程****/
void main()
{
uint8 i;
dtype _data;
pdata=0;
pmax=0;
pmin=0;
for(i=0;i<LEN;i++)
datas[i]=0;
printf("數(shù)據(jù): 最大 最小/n");
while(1)
{
scanf("%u",&_data);
szlb(_data);
for(i=0;i<LEN;i++)
printf("%-3u ",datas[i]);
printf(" %-3u %-3u",datas[pmax],datas[pmin]);
printf("/n");
}
}