幾種軟體濾波方法
幾種軟體濾波演算法的原理和比較
下面是自己這些年做專案並結合網上資料總結的幾種濾波演算法:
第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個取樣值看成一個佇列,佇列的長度固定為
B優點: 對週期性干擾有良好的抑制作用,平滑度高,適用於高頻振盪的系統。
C缺點: 靈敏度低,對偶然出現的脈衝性干擾的抑制作用較差,不易消除由於脈衝干擾所引起的取樣值偏差,不適用於脈衝干擾比較嚴重的場合,比較浪費RAM。
D原始碼: 在文章尾部。
第5種方法:中位值平均濾波法(又稱防脈衝干擾平均濾波法)
A方法: 相當於“中位值濾波法”+“算術平均濾波法”,連續取樣N個數據,去掉一個最大值和一個最小值,然後計算
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