濾波器開發之一:基於算數平均的平滑濾波器

信號採集是非常常見的需求,我們也總是希望採集到的數據是純淨而真實的,但這只是我們的希望。環境中存在太多的干擾信號,爲了讓我們得到的數據儘可能地接近實際值,我們需要降低這些干擾信號的影響,於是就有了濾波器的用武之地。這裏我們討論的主要是軟件實現的數字濾波器,這一篇我們就來討論基於遞推算術平均算法的平滑濾波器。

1、問題的提出

在我們通過AD採集獲取數據時,不可避免會受到干擾信號的影響,而且很多時候我們希望儘可能的將這種影響減到最小。爲實現這一目的,人們想了很多辦法,有硬件方面的,也有軟件方面的。在硬件難以改變或者軟件能夠達到相應效果時,我們一般採用軟件方法來實現,通常稱之爲數字濾波。

實現數字濾波的算法有很多種,根據不同的應用需求我們可以選擇不同濾波算法來實現。對於一般的AD採集最常見的是週期性干擾和隨機性噪聲,對於此類干擾一般採用算術平均的方法就能得到比較理想的效果。其計算公式如下:

使用簡單的算術平均值算法雖然能夠實現濾波,但在一些情況下有一個問題可能會有影響,那就是當做算術平均的數量比較大時會出現曲線並不是十分平滑的情況。這很容易理解,因爲一次採集n個數做算術平均得到一個結果,當n越大則間隔的時間就越長。爲了解決這一問題我們並不是甲酸完後就將n個數同時丟棄,而是將最早的數丟棄並採用最新採集的數代替,這就是所謂的遞推算術平均算法。但其計算公式並沒有發生變化。

2、算法設計

我們如何實現這種遞推方式的平滑濾波器呢?首先我們來看一看一般的算術平均算法是如何實現的。算術平均算法就是採集N個數然後對這N個數取平均值作爲最終的結果。我們將這些數的序列記錄如下:

這N個數計算完畢後就會丟棄,然後再採集N個數。很顯然,如果N值較大,採集所耗費的時間跨度就會比較長,數據看起來可能就並不那麼平滑,而且數據的輸出速率會慢很多,也不能展示數據的變化過程。而遞推平均算法則不存在這些問題。同樣是一個長度爲N的數據隊列,但沒采樣一次數據,我們就用最新的數據替換掉最久的數據,並輸出算術平均值。我們將這些數的序列記錄如下:

這樣每採樣一個數據我們都會輸出一個濾波後的數據,而不是等待採集N個數據後纔會輸出,這樣既可保證數據的連續性也可達到平滑濾波的效果。

3、代碼實現

我們分析了平滑濾波器的實現算法,接下來我們來討論如何實現這一濾波器。首先我們將濾波器作爲一個對象,我們實現的濾波器操作也將面向這一對象來實現。那麼我們實現對濾波器對象的操作需要確定該對象的那些屬性呢?

作爲濾波器肯定需要獲取當前採集到的數據值;同時我們爲了實現對N個數據的遞推平均就需要有一個存儲這N個數的隊列;我們需要記錄最新的數據硬件存儲到哪個位置就需要一個位置指針;同時我們也需要知道N的大小,所以我們將它們都定義濾波器對象的屬性。平滑濾波的過程必須要計算算術平均值,而遞推算術平均則是在每次採集一個數據之時都計算平均值,可是如果N值較大時,就會存在大量的重複計算。我們考慮到上一次採樣的平均值已經得到,我們將其記錄下來的話就可以用最新採集的數據替換掉最老的數據,從而得到新的平均值,所以我們將上一時間的輸出值記錄下來作爲對象的一個屬性。根據以上分析我們可定義濾波器對象類型爲:

/*定義平滑濾波對象類型*/
typedef struct FilterObject{
  float newValue;       //最新測量值
  float lastValue;      //上一個輸出值
  float *buffer;        //數據緩存區
  int16_t position;    //寫操作位置指針
  uint16_t bufCount;    //濾波的數量
}FilterObjectType;

我們獲得了濾波器對象,接下來我們基於該對象實現平滑濾波器。對於平滑濾波自然是要採取計算平均值的過程。但我們使用了循環隊列的操作方式,所以判斷新數據指針當前所處的位置。具體實現如下:

/*平滑濾波處理函數,返回濾波後的值 */
float SmoothingFilter(FilterObjectType *filter)
{
  float result=0.0;
 
  if(filter->position<0)
  {
    for(int i=0;i<filter->bufCount;i++)
    {
      filter->buffer[i]=filter->newValue;
    }
    filter->position=0;
    filter->lastValue=filter->newValue;
  }
 
  if(filter->position>=filter->bufCount)
  {
    filter->position=0;
  }
 
  result=filter->lastValue-filter->buffer[filter->position]/filter->bufCount;
 
  result=result+filter->newValue/filter->bufCount;
 
  filter->buffer[filter->position++]=filter->newValue;
 
  filter->lastValue=result;
 
  filter->newValue=0.0;
  return result;
}

4、應用總結

我們實現了基於算術平均的平滑濾波器,對於消除週期性干擾有良好的抑制作用,對於一般具有隨機干擾的信號也能進行濾波。對於數據平滑度較高有不錯的效果。

但是這種濾波方式有幾點是需要注意的。第一,它的靈敏度低。這很好理解,因爲我們總是對N個數採取平均值算法,所以新數據對平均值的影響有限,數據變化不明顯,響應較慢,而且N越大越明顯。第二.對偶然出現的脈衝性干擾的抑制作用較差。第三,不易消除由於脈衝干擾所引起的採樣值偏差。所以這種濾波器並不適用於脈衝干擾比較嚴重的場合。

歡迎關注:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章