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