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