找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

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

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

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






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

 EN  : 調(diào)用使能位
 bType :采樣值類型,'W'=整型、'F'=浮點(diǎn)型、'D'(或其它)=長(zhǎng)整型,參數(shù)類型:字節(jié)
 wHi : 采樣值高位字(采樣值為整型是,實(shí)參必須為0),參數(shù)類型,2字節(jié)
 wLo : 采樣值低位字,參數(shù)類型,2字節(jié)
 rDie : 濾波死區(qū),參數(shù)類型:浮點(diǎn)數(shù)
 rMaxErr : 最大允許偏差,參數(shù)類型:浮點(diǎn)數(shù)
 rLen :濾波隊(duì)列長(zhǎng)度,參數(shù)類型:浮點(diǎn)數(shù)
出/入口參數(shù):
 rSum :累加和,參數(shù)類型:浮點(diǎn)數(shù)
 rAve :濾波輸出平均值,參數(shù)類型:浮點(diǎn)數(shù)
命令行:CALL   AveFilter, 'W', 0, SMW28, 640.0, 32000.0, 4.0, VD0, VD4
注意:本程序采樣值是參數(shù)類型可適應(yīng)的,用 wHi/wLo 的組合來(lái)適應(yīng)整型、長(zhǎng)整型、浮點(diǎn)型的參數(shù)類型輸入,避免使用多個(gè)相同的子程序來(lái)適應(yīng)不同類型的輸入?yún)?shù)。由 bType 來(lái)指定輸入的參數(shù)類型。

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

防脈沖干擾移動(dòng)平均值法數(shù)字濾波器的C語(yǔ)言算法及其實(shí)現(xiàn)

在許多的數(shù)據(jù)采集系統(tǒng)中,現(xiàn)場(chǎng)的強(qiáng)電設(shè)備較多,不可避免地會(huì)產(chǎn)生尖脈沖干擾,這種干擾一般持續(xù)時(shí)間短,峰值大,對(duì)這樣的數(shù)據(jù)進(jìn)行數(shù)字濾波處理時(shí),僅僅采用算術(shù)平均或移動(dòng)平均濾波時(shí),盡管對(duì)脈沖干擾進(jìn)行了1/n的處理,但,其剩余值仍然較大。
      這種場(chǎng)合最好的策略是:將被認(rèn)為是受干擾的信號(hào)數(shù)據(jù)去掉,這就是防脈沖干擾平均值濾波法的原理
 防脈沖干擾平均值濾波法的算法是:對(duì)連續(xù)的n個(gè)數(shù)據(jù)進(jìn)行排序,去掉其中最大和最小的2個(gè)數(shù)據(jù),將剩余數(shù)據(jù)示平均值。

      在一般8051單片機(jī)的應(yīng)用中為了加快數(shù)據(jù)處理速度,n可以取值6。 而對(duì)于具有較快速度的處理器,則n值可以適當(dāng)取大一些。但最好是 n=2^k+2, k為整數(shù),因?yàn)檫@樣在求平均值average=SUM/(n-2)=SUM/2^k時(shí),可以寫(xiě)成average=SUM>>k,用移位的方法,可以加快處理速度。
   
      上述算法顯然還存在一個(gè)不足之處,就是每采集一個(gè)數(shù)據(jù)就要進(jìn)行一次排序,這樣會(huì)大量占用系統(tǒng)寶貴的時(shí)間。這可以通過(guò)存儲(chǔ)當(dāng)前數(shù)據(jù)中的最大值和最小值來(lái)改進(jìn)。具體做法是:系統(tǒng)中用兩個(gè)變量來(lái)存儲(chǔ)當(dāng)前n個(gè)數(shù)據(jù)的最大值和最小值在這個(gè)數(shù)組中的偏移量(也就是數(shù)組下標(biāo),存儲(chǔ)數(shù)組下標(biāo)而直接不存儲(chǔ)數(shù)據(jù)本身是因?yàn)椋涸谝话愕南到y(tǒng)中,n不會(huì)超無(wú)符號(hào)短整形的表示范圍,因此用一個(gè)char形變量就可以存儲(chǔ)了而如果直接存儲(chǔ)數(shù)據(jù)本身,則許多情況下要用int形變量,甚至更長(zhǎng)的類型)。這樣只要在當(dāng)前輸入的數(shù)據(jù)將要覆蓋的數(shù)據(jù)正好是當(dāng)前的最大值或最小值時(shí)才在下個(gè)數(shù)組中查找最大值或最小值,而其他情況下則只要將輸入的數(shù)據(jù)與最大值和最小值比較就可以修改下最大值和最小值了,而且不用進(jìn)行數(shù)據(jù)排序。

     這個(gè)算法很簡(jiǎn)單,下面是對(duì)應(yīng)的C語(yǔ)言代碼實(shí)現(xiàn),可以很方便的應(yīng)用的具體的51單片機(jī)或其他處理器上,只須做少量的修改。

 #include"stdio.h"
#define dtype unsigned int // 采集數(shù)據(jù)的數(shù)據(jù)類型
#define uint8 char

#define LEN  6   //移動(dòng)算術(shù)平均的個(gè)數(shù)+2=SHIFT<<2+2
#define SHIFT 2   //2^SHIFT

uint8 pdata;    //移動(dòng)指針
uint8 pmax,pmin;   //記錄數(shù)據(jù)表中最大值和最小值的位置,在一般的數(shù)據(jù)采集系統(tǒng)中,數(shù)據(jù)的長(zhǎng)度>=8,因此用指針記錄而不是直接記錄最大值和最小值
dtype datas[LEN];

dtype szlb(dtype _data)
{  
/****************************/
/* 在調(diào)用此子程序前必須對(duì) pdata,datas[]數(shù)組,  pmax,pmin進(jìn)行初始化  */
/****************************/

 uint8 i;
 dtype average=0;  //清零,用來(lái)計(jì)算平均值
 pdata=(pdata+1)%LEN; //指針下標(biāo)在0到LEN-1上滑動(dòng)
 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)前最大值的位置時(shí)
 {      //由以上方法將不可行,必須從其他位置中查找極值
      for(i=0;i<LEN;i++)
          if(datas[i]>datas[pmax])
          pmax=i;
 }
 else if(pdata==pmin)//如果當(dāng)前輸入值將存入當(dāng)前最大值的位置時(shí)
 {      //由以上方法將不可行,必須從其他位置中查找極值
     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)境下運(yùn)行的測(cè)試程序**/

/***通過(guò)手動(dòng)輸入來(lái)模擬數(shù)據(jù)采集過(guò)程****/

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ù)

使用道具 舉報(bào)

本版積分規(guī)則

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

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

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