找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 4524|回復(fù): 0
打印 上一主題 下一主題
收起左側(cè)

下位機_平均值濾波之-鬼斧神工算法(平均值濾波之經(jīng)典形式改進)

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:90014 發(fā)表于 2015-9-15 15:09 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
在十種經(jīng)典軟件濾波算法中,可以看到很多算法都是平均值濾波算法變種,事實上最常用的也還是平均值濾波算法。但傳統(tǒng)的平均值濾波算法很占內(nèi)存,每次運算都要求累加和,再求平均值,導(dǎo)致運算效率不高。
 今天介紹一種超簡潔超高效的平均濾波算法,此算法是以前搞單片機時一老師所創(chuàng)(單片機上的內(nèi)存簡直是寸土寸金),僅僅用三個變量,就完成了平均值濾波的計算。剛開始看到這個算法是只覺得很佩服,后來用了各種各樣的算法后,才感到此算法簡直到了鬼斧神工的地步(別以為看完后覺得太簡單沒啥大不了的,正是因為太簡單才突出了它的了不起,最開始能想到將一個復(fù)雜的算法簡化到無法再簡的地步非一般功力所能做到的)。
  
 在該基礎(chǔ)上,我們再演變出一種帶死區(qū)和限幅控制的隊列平均值實用算法。
 采樣值 C、累加器 S,平均值 A,采樣次數(shù) N
  
 傳統(tǒng)的平均值濾波算法:
 S = C(1) + C(2) + ... + C(N)
 A = S / N
 需要用循環(huán)來計算累加和,比較耗時,C(1~N)是緩存,隨采樣數(shù)N增大,所需內(nèi)存量也增大
  
 向隊列平均值算法推進:
 S = C(1) + C(2) + ... + C(N) (第一次)
 C(x) = C(x + 1) (隊列前移)
 C(N) = C
 S = S - C(1) + C(N)
 A = S / N
 運算量有所改進(用指針維護循環(huán)隊列,不實際移動數(shù)據(jù)),占用內(nèi)存問題不變
  
 鬼斧神工算法:
 初始化:A=初始值,S=A*N
 S = S - A + C
 A = S / N
 就這么簡單,三個變量(N可以是常數(shù)),只要 S 的量程足夠,N可以任意調(diào)整。
 可以看出,此算法是從隊列平均值算法演變而來,因沒有了隊列,每次計算時不知道該丟棄的最老的一個采樣值是多少,這里用了個替代的辦法,丟棄上次計算出的平均值。
 去掉了緩存維護,節(jié)省內(nèi)存空間,同時也將運算量壓縮到了最小,執(zhí)行效率非常高。調(diào)試時容易修改采樣數(shù)。
  
 優(yōu)化算法:
 此算法的核心思想還是平均值濾波,雖然改進了運算量和內(nèi)存占用,但同樣繼承了平均值濾波法 N 值較大時平滑度好,反應(yīng)遲鈍的特點。
 為此,對算法引入 S7-200 系統(tǒng)濾波程序中死區(qū)的概念:采樣值偏差在死區(qū)范圍內(nèi)時,進行濾波計算,采樣值偏差在死區(qū)范圍以外時直接使用采樣值,達到快速反應(yīng)的效果。
 再溶合限幅濾波法去掉偶然的干擾脈沖:采樣值偏差在限幅范圍內(nèi)時,進行濾波計算,采樣值偏差在限幅范圍以外時直接丟棄,使用上次濾波輸出值。顯然,限幅值應(yīng)該大于死區(qū)值。
  
 將此算法寫成兩個子函數(shù)(也可以做成庫)
 ① 主濾波程序 AveFilter
 
 
  入口參數(shù):
  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ù)類型。
  
 ②濾波器初始化程序 InitFilter
 
  
 入口參數(shù):
  EN  : 調(diào)用使能位
  rInit :初始值(一般為0),參數(shù)類型:浮點數(shù)
  rLen : 濾波隊列長度,參數(shù)類型:浮點數(shù)
 出/入口參數(shù):
  rSum :累加和,參數(shù)類型:浮點數(shù)
  rAve :濾波輸出平均值,參數(shù)類型:浮點數(shù)
  命令行:CALL   InitFilter, 0.0, 4.0, VD0, VD4






十種經(jīng)典軟件濾波算法中,可以看到很多算法都是平均值濾波算法變種,事實上最常用的也還是平均值濾波算法。但傳統(tǒng)的平均值濾波算法很占內(nèi)存,每次運算都要求累加和,再求平均值,導(dǎo)致運算效率不高。
今天介紹一種超簡潔超高效的平均濾波算法,此算法是以前搞單片機時一老師所創(chuàng)(單片機上的內(nèi)存簡直是寸土寸金),僅僅用三個變量,就完成了平均值濾波的計算。剛開始看到這個算法是只覺得很佩服,后來用了各種各樣的算法后,才感到此算法簡直到了鬼斧神工的地步(別以為看完后覺得太簡單沒啥大不了的,正是因為太簡單才突出了它的了不起,最開始能想到將一個復(fù)雜的算法簡化到無法再簡的地步非一般功力所能做到的)。
在該基礎(chǔ)上,我們再演變出一種帶死區(qū)和限幅控制的隊列平均值實用算法。采樣值 C、累加器 S,平均值 A,采樣次數(shù) N;
傳統(tǒng)的平均值濾波算法
S = C(1) + C(2) + ... + C(N)
A = S / N
需要用循環(huán)來計算累加和,比較耗時,C(1~N)是緩存,隨采樣數(shù)N增大,所需內(nèi)存量也增大
 
向隊列平均值算法推進
S = C(1) + C(2) + ... + C(N) (第一次)
C(x) = C(x + 1) (隊列前移)
C(N) = C
S = S - C(1) + C(N)
A = S / N
運算量有所改進(用指針維護循環(huán)隊列,不實際移動數(shù)據(jù)),占用內(nèi)存問題不變
 
鬼斧神工算法
初始化:A=初始值,S=A*N
            S = S - A + C(i)  i從第二個起,不算A
            A = S / N
就這么簡單,三個變量(N可以是常數(shù)),只要 S 的量程足夠,N可以任意調(diào)整。
可以看出,此算法是從隊列平均值算法演變而來,因沒有了隊列,每次計算時不知道該丟棄的最老的一個采樣值是多少,這里用了個替代的辦法,丟棄上次計算出的平均值。
去掉了緩存維護,節(jié)省內(nèi)存空間,同時也將運算量壓縮到了最小,執(zhí)行效率非常高。調(diào)試時容易修改采樣數(shù)。
優(yōu)化算法
此算法的核心思想還是平均值濾波,雖然改進了運算量和內(nèi)存占用,但同樣繼承了平均值濾波法 N 值較大時平滑度好,反應(yīng)遲鈍的特點。
為此,對算法引入 S7-200 系統(tǒng)濾波程序中死區(qū)的概念:采樣值偏差在死區(qū)范圍內(nèi)時,進行濾波計算,采樣值偏差在死區(qū)范圍以外時直接使用采樣值,達到快速反應(yīng)的效果。
再溶合限幅濾波法去掉偶然的干擾脈沖:采樣值偏差在限幅范圍內(nèi)時,進行濾波計算,采樣值偏差在限幅范圍以外時直接丟棄,使用上次濾波輸出值。顯然,限幅值應(yīng)該大于死區(qū)值。
將此算法寫成兩個子函數(shù)(也可以做成庫)
① 主濾波程序 AveFilter
入口參數(shù):

 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ù)類型。

常用軟件濾波方法及其示例程序 http://www.torrancerestoration.com/bbs/dpj-38875-1.html

防脈沖干擾移動平均值法數(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");
 }
}

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復(fù)

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機教程網(wǎng)

快速回復(fù) 返回頂部 返回列表