1. 程式人生 > >幾種軟體濾波方法

幾種軟體濾波方法

幾種軟體濾波演算法的原理和比較

下面是自己這些年做專案並結合網上資料總結的幾種濾波演算法:

1種方法:限幅濾波法(又稱程式判斷濾波法)

A方法: 根據經驗判斷,確定兩次取樣允許的最大偏差值(設為A),每次檢測到新值時判斷: 如果本次值與上次值之差<=A,則本次值有效,如果本次值與上次值之差>A,則本次值無效,放棄本次值,用上次值代替本次值。

B優點: 能有效克服因偶然因素引起的脈衝干擾。

C缺點: 無法抑制那種週期性的干擾,平滑度差。

D原始碼: 在文章尾部

2種方法:中位值濾波法

A方法: 連續取樣N次(N取奇數),把N次取樣值按大小排列,取中間值為本次有效值。

B優點: 能有效克服因偶然因素引起的波動干擾,對溫度、液位的變化緩慢的被測引數有良好的濾波效果。

C缺點: 對流量、速度等快速變化的引數不宜。

D原始碼: 在文章尾部

3種方法:算術平均濾波法

A方法: 連續取N個取樣值進行算術平均運算,N值較大時:訊號平滑度較高,但靈敏度較低;N值較小時:訊號平滑度較低,但靈敏度較高。N值的選取:一般流量,N=12;壓力:N=4

B優點: 適用於對一般具有隨機干擾的訊號進行濾波,這樣訊號的特點是有一個平均值,訊號在某一數值範圍附近上下波動。

C缺點: 對於測量速度較慢或要求資料計算速度較快的實時控制不適用,比較浪費RAM

D原始碼: 在文章尾部

4種方法:遞推平均濾波法(又稱滑動平均濾波法)

A方法: 把連續取N個取樣值看成一個佇列,佇列的長度固定為

N,每次取樣到一個新資料放入隊尾,並扔掉原來隊首的一次資料(先進先出原則) 。把佇列中的N個數據進行算術平均運算,就可獲得新的濾波結果。N值的選取:流量,N=12;壓力:N=4;液麵,N=4~12;溫度,N=1~4

B優點: 對週期性干擾有良好的抑制作用,平滑度高,適用於高頻振盪的系統。

C缺點: 靈敏度低,對偶然出現的脈衝性干擾的抑制作用較差,不易消除由於脈衝干擾所引起的取樣值偏差,不適用於脈衝干擾比較嚴重的場合,比較浪費RAM

D原始碼: 在文章尾部

5種方法:中位值平均濾波法(又稱防脈衝干擾平均濾波法)

A方法: 相當於中位值濾波法”+“算術平均濾波法,連續取樣N個數據,去掉一個最大值和一個最小值,然後計算

N-2個數據的算術平均值。N值的選取:3~14

B優點: 融合了兩種濾波法的優點,對於偶然出現的脈衝性干擾,可消除由於脈衝干擾所引起的取樣值偏差。

C缺點: 測量速度較慢,和算術平均濾波法一樣,比較浪費RAM

D原始碼: 在文章尾部

6種方法:限幅平均濾波法

A方法: 相當於限幅濾波法”+“遞推平均濾波法,每次取樣到的新資料先進行限幅處理,再送入佇列進行遞推平均濾波處理。

B優點: 融合了兩種濾波法的優點,對於偶然出現的脈衝性干擾,可消除由於脈衝干擾所引起的取樣值偏差。

C缺點: 比較浪費RAM

D原始碼: 在文章尾部

7種方法:一階滯後濾波法

A方法: 取a=0~1,本次濾波結果=1-a*本次取樣值+a*上次濾波結果。

B優點: 對週期性干擾具有良好的抑制作用,適用於波動頻率較高的場合。

C缺點:相位滯後,靈敏度低,滯後程度取決於a值大小,不能消除濾波頻率高於取樣頻率的1/2的干擾訊號。

D原始碼: 在文章尾部

8種方法:加權遞推平均濾波法

A方法: 是對遞推平均濾波法的改進,即不同時刻的資料加以不同的權,通常是,越接近現時刻的資料,權取得越大,給予新取樣值的權係數越大,則靈敏度越高,但訊號平滑度越低。

B優點: 適用於有較大純滯後時間常數的物件和取樣週期較短的系統。

C缺點: 對於純滯後時間常數較小,取樣週期較長,變化緩慢的訊號,不能迅速反應系統當前所受干擾的嚴重程度,濾波效果差。

D原始碼: 在文章尾部

9種方法:消抖濾波法

A方法: 設定一個濾波計數器,將每次取樣值與當前有效值比較: 如果取樣值=當前有效值,則計數器清零。如果取樣值<>當前有效值,則計數器+1,並判斷計數器是否>=上限N(溢位),如果計數器溢位,則將本次值替換當前有效值,並清計數器。

B優點: 對於變化緩慢的被測引數有較好的濾波效果,可避免在臨界值附近控制器的反覆開/關跳動或顯示器上數值抖動。

C缺點: 對於快速變化的引數不宜,如果在計數器溢位的那一次取樣到的值恰好是干擾值,則會將干擾值當作有效值匯入系統。

D原始碼: 在文章尾部

10種方法:限幅消抖濾波法

A方法: 相當於限幅濾波法”+“消抖濾波法,先限幅後消抖。

B優點: 繼承了限幅消抖的優點,改進了消抖濾波法中的某些缺陷,避免將干擾值匯入系統。

C缺點: 對於快速變化的引數不宜。

D原始碼: 在文章尾部

11種方法:IIR 數字濾波器

A方法: 確定訊號頻寬, 濾之。 Y(n) = a1*Y(n-1) + a2*Y(n-2) + ... + ak*Y(n-k) + b0*X(n) + b1*X(n-1) + b2*X(n-2) + ... + bk*X(n-k)

B優點: 高通,低通,帶通,帶阻任意。設計簡單(matlab)。

C缺點: 運算量大。

D原始碼: 在文章尾部

 原始碼如下:

1、限幅濾波
/* A值可根據實際情況調整
   value為有效值,NewValue為當前取樣值
   濾波程式返回有效的實際值*/


#define A 10
unsigned int value;
unsigned char IsADProcessFlg; //


unsigned int filter()
{
unsigned int NewValue;

if (1 == IsADProcessFlg)
{
IsADProcessFlg=0;
NewValue = get_ad();

if((NewValue > (value + A)) || ((NewValue < (value - A))))
{
return value;
}

return NewValue;
}
}


2、中位值濾波法
/* N值可根據實際情況調整,N取奇數,排序採用冒泡法*/
#define N 11


unsigned char IsADProcessFlg;
unsigned int value_buf[N];
unsigned char count=0;
unsigned int filter()
{
unsigned int temp;
unsigned char i,j;


if (1 == IsADProcessFlg)
{
IsADProcessFlg=0;
value_buf[count++] = get_ad();
if(N == count)
{
count=0;
for (j=0;j<N-1;j++)
{
  for (i=0;i<N-j;i++)
  {
if ( value_buf[i] > value_buf[i+1] )
   {
    temp = value_buf[i];
    value_buf[i] = value_buf[i+1]; 
    value_buf[i+1] = temp;
   }
  }
}

return value_buf[(N-1)/2];
}
}
}


2、冒泡法
//連續讀取READ_TIMES次資料,對這些資料升序排列,
//然後去掉最低和最高LOST_VAL個數,取平均值 
//xy:指令(CMD_RDX/CMD_RDY)
//返回值:讀到的資料


#define READ_TIMES 5 //讀取次數
#define LOST_VAL 1   //丟棄值


u16 TP_Read_XOY(u8 xy) //xy取 CMD_RDX,CMD_RDY
{
u16 i, j;
u16 buf[READ_TIMES];
u16 sum=0;
u16 temp;
for(i=0;i<READ_TIMES;i++)
{
buf[i]=TP_Read_AD(xy);
}
for(i=0;i<READ_TIMES-1; i++)//排序
{
for(j=i+1;j<READ_TIMES;j++)
{
if(buf[i]>buf[j])//升序排列
{
temp=buf[i];
buf[i]=buf[j];
buf[j]=temp;
}
}

for(i=LOST_VAL;i<READ_TIMES-LOST_VAL;i++) //i=(READ_TIMES-LOST_VAL)-1,就退出迴圈
{
sum+=buf[i];
}
temp=sum/(READ_TIMES-2*LOST_VAL); //((READ_TIMES-LOST_VAL)-1)-LOST_VAL+1=READ_TIMES-2*LOST_VAL
return temp;   



3、算術平均濾波法
/*
*/
#define N 12


unsigned char IsADProcessFlg;
unsigned int value_buf[N];
unsigned char count=0;
unsigned int filter()
{
unsigned long sum=0;
unsigned char i;

if (1 == IsADProcessFlg)
{
IsADProcessFlg=0;
value_buf[count++] = get_ad();
if(N == count)
{
count=0;
for (i=0;i<N;i++)
{
sum += value_buf[i];
}
return (unsigned int)(sum/N);
}
}
}


4、遞推平均濾波法(又稱滑動平均濾波法)
/*
*/
#define N 12 
unsigned int value_buf[N];
unsigned char count=0;
unsigned char IsADProcessFlg;
unsigned int filter()
{
unsigned char i=0;
unsigned int sum=0;


if (1 == IsADProcessFlg)
{
IsADProcessFlg=0;
value_buf[count++] = get_ad();
if(N == count)
{
count=N-1;
for (i=0;i<N;i++)
{
sum += value_buf[i];
}

for (i=0;i<N-1;i++)
{
value_buf[i]=value_buf[i+1];
}

return (unsigned int)(sum/N);
}
}
}


5、中位值平均濾波法(又稱防脈衝干擾平均濾波法)
/*
*/
#define N 12


unsigned char IsADProcessFlg;
unsigned int value_buf[N];
unsigned char count=0;
unsigned int filter()
{
unsigned char i,j;
unsigned int temp;
unsigned long sum=0;

if (1 == IsADProcessFlg)
{
IsADProcessFlg=0;
value_buf[count++] = get_ad();
if(N == count)
{
count=0;
for (j=0;j<N-1;j++)
{
  for (i=0;i<N-j;i++)
  {
if ( value_buf[i] > value_buf[i+1] )
   {
    temp = value_buf[i];
    value_buf[i] = value_buf[i+1]; 
    value_buf[i+1] = temp;
   }
  }
}

for (i=1;i<N-1;i++)
{
sum += value[i];
}

return (char)(sum/(N-2));
}
}
}


6、限幅平均濾波法
/*
*/ 
略 參考子程式1、3


7、一階滯後濾波法
/* 為加快程式處理速度假定基數為100,a=0~100 */
#define a 50
char value;
char filter()
{
char NewValue;
NewValue = get_ad();
return (100-a)*value + a*NewValue; 
}


//專案中用到的一階濾波,程式碼如下:
#define K                         25            //一階濾波係數初始值
#define FILTER_ADP_VAL            50            //消抖計數加速反應閾值
#define FILTER_ADP_MAX            5             //消抖計數最大值
#define FILTER_1ST_INCREMENT      15            //一階濾波係數增量
#define FILTER_1ST_MAX            150   //一階濾波係數最大值


unsigned char is_SampleProcessFlg;//多久讀取一次流量值標誌位


unsigned char IsFirstFlg;
unsigned int  OldVal;
unsigned int  NewVal; 
unsigned char cnt;
unsigned char dir[3];                 //兩次取樣值變化方向
unsigned char YiJieFilterCo=K;                  //一階濾波係數
unsigned char FilterAdpCnt;                     //消抖計數器


/*******************************************************************************
* 函式名稱: average
* 功能描述: 求平均值函式
* 輸入引數: ADCDataTab[],nChannel //儲存nChannel的ADC轉換值
* 輸出引數:   
* 返回引數:   
* 全域性變數:
* 呼叫函式:
* 被調函式:
*******************************************************************************/
u16 average(vu16 ADCDataTab[], u16 nChannel) 

u16 maxvalue=0, minvalue=0xFFFF, i;
u32 averagevalue=0;

for (i=0;i<20;i++) 

averagevalue += *(ADCDataTab+nChannel+i*2); //2是指有2組ADC轉換通道,n組就*n
if(*(ADCDataTab+nChannel+i*2)>maxvalue) 
{  
maxvalue=*(ADCDataTab+nChannel+i*2);
}
if(*(ADCDataTab+nChannel+i*2)<minvalue)
{
minvalue=*(ADCDataTab+nChannel+i*2);
}
}

return ((averagevalue-maxvalue-minvalue)/18);  
}


/*******************************************************************************
* 函式名稱: YiJieFilter
* 功能描述: 一階濾波函式 Yn=Y(n-1)+(Xn-Y(n-1))*k/256; 
* 輸入引數: OldVal, NewVal, k
* 輸出引數: result
* 返回引數:   
* 全域性變數:
* 呼叫函式:
* 被調函式:
*******************************************************************************/
unsigned int YiJieFilter(unsigned int OldVal,unsigned int NewVal,unsigned char k)
{
unsigned int result;

if(NewVal < OldVal)     
{
result=OldVal-NewVal;
result=result*k;
result=result+128;          
result=result/256;
result=OldVal-result;
}
else if(NewVal > OldVal)
{
result=NewVal-OldVal;
result=result*k;
result=result+128;          
result=result/256;
result=OldVal+result;
}
else
{
result=OldVal;
}

return result;
}




/*******************************************************************************
* 函式名稱: ADC_Process
* 功能描述: ADC處理函式
* 輸入引數: ADCDataTab[],nChannel //儲存nChannel的ADC轉換值
* 輸出引數:   
* 返回引數:   
* 全域性變數:
* 呼叫函式:
* 被調函式:
*******************************************************************************/
void ADC_Process(void) //ADC_Value[1] 儲存SENSE_GAS的AD值
{
if(is_SampleProcessFlg)
{
is_SampleProcessFlg=0;
if(IsFirstFlg == 0)
{
IsFirstFlg=1;
ADC_Value[1]=average(ADC_RCVTab,1);
OldVal=ADC_Value[1];
}
else
{
NewVal=average(ADC_RCVTab,1);  //新的取樣值

if(NewVal > OldVal)
{
dir[cnt++]=1; //遞增
}
if(OldVal > NewVal)
{
dir[cnt++]=0; //遞減
}

if(cnt == 2)
{
if(dir[0] != dir[1]) //變化方向不一致
{
YiJieFilterCo=0;
FilterAdpCnt=0;
ADC_Value[1]=YiJieFilter(OldVal,NewVal,YiJieFilterCo);
OldVal=ADC_Value[1];
}
else 
{
if( (NewVal > OldVal+FILTER_ADP_VAL ) || (OldVal > NewVal+FILTER_ADP_VAL ) ) //變化很快,要加速提高濾波係數
{
FilterAdpCnt += 2; //消抖計數
}
else
{
FilterAdpCnt++; //消抖計數
}

if(FilterAdpCnt >= FILTER_ADP_MAX)  //消抖計數器到達最大
{
FilterAdpCnt=0;
if(YiJieFilterCo <= (FILTER_1ST_MAX - FILTER_1ST_INCREMENT))
{
YiJieFilterCo += FILTER_1ST_INCREMENT;
}
else
{
YiJieFilterCo=FILTER_1ST_MAX;
}
ADC_Value[1]=YiJieFilter(OldVal,NewVal,YiJieFilterCo);
OldVal=ADC_Value[1];
}
}

dir[0]=dir[1];
cnt=1;
}
else
{
OldVal=NewVal;
}
}
}



8、加權遞推平均濾波法
/* coe陣列為加權係數表,存在程式儲存區。*/
#define N 12


unsigned char code coe[N] = {1,2,3,4,5,6,7,8,9,10,11,12};
unsigned char code sum_coe = 1+2+3+4+5+6+7+8+9+10+11+12;


unsigned char IsADProcessFlg;
unsigned int value_buf[N];
unsigned char count=0;
unsigned int filter()
{
unsigned char i;
unsigned long sum=0;
for (count=0,count<N;count++)
{
  value_buf[count] = get_ad();
  delay();
}

if (1 == IsADProcessFlg)
{
IsADProcessFlg=0;
value_buf[count++] = get_ad();
if(N == count)
{
count=0;
for (i=0,i<N;i++)
{
sum += value_buf[i]*coe[i];
}

return (unsigned int)(sum/sum_coe);
}
}
}


9、消抖濾波法
#define N 12


unsigned int value,NewValue;
unsigned int filter()
{
unsigned char count=0;
unsigned int NewValue;

NewValue = get_ad();
while (value != NewValue);
{
count++;
if (count >= N) 
{
return NewValue;
}
delay();
NewValue = get_ad();
}
return value; 
}




10、限幅消抖濾波法
/*
*/
略 參考子程式1、9