隨機誤差是有隨機干攪引起的,其特點是在相同條件下測量同一個量時,其大小和符號做無規(guī)則變化而無法預測,但多次測量結果符合統(tǒng)計規(guī)律。為克服隨機干攪引入的誤差,硬件上可采用濾波技術,軟件上可以采用軟件算法實現(xiàn)數字濾波,其算法往往是系統(tǒng)測控算法的一個重要組成部分,實時性很強,采用匯編語言來編寫。
采用數字濾波算法克服隨機干攪引入的誤差具有以下幾個優(yōu)點:
(1)數字濾波無須硬件,只用一個計算過程,可靠性高,不存在阻抗匹配問題,尤其是數字濾波可以對
頻率很高或很低的信號進行濾波,這是模擬濾波器做不到的。
(2)數字濾波是用軟件算法實現(xiàn)的,多輸入通道可用一個軟件“濾波器”從而降低系統(tǒng)開支。
(3)只要適當改變軟件濾波器的濾波程序或運行參數,就能方便地改變其濾波特性,這個對于低頻、脈沖
干攪、隨機噪聲等特別有效。
常用的數字濾波器算法有程序判斷法、中值判斷法、算術平均值法、加權濾波法、滑動濾波法、低通濾波法和復合濾波法。
1.程序判斷法:
程序判斷法又稱限副濾波法,其方法是把兩次相鄰的采樣值相減,求出其增量(以絕對值表示)。然后與兩次采樣允許的最大差值△Y進行比較,△Y的大小由被測對象的具體情況而定,若小于或等于△Y,則取本次采樣的值;若大于△Y,則取上次采樣值作為本次采樣值,即
yn-yn-1|≤△Y,則yn有效,
yn-yn-1|>△Y,則yn-1有效。
式中yn——第n次采樣的值;
Yn-1——第(n-1)次采樣的值;
△Y——相鄰兩次采樣值允許的最大偏差。
設R1和R2為內部RAM單元,分別存放yn-1和yn,濾波值也存放在R2單元,采用MCS-51單片機指令編寫的程序判斷法子程序如下:付表
2.中值濾波法即對某一參數連續(xù)采樣N次(一般N為奇數),然后把N次采樣值按從小到大排隊,再取中間值作為本次采樣值。
設DATA為存放采樣值的內存單元首地址,SAMP為存放濾波值的內存單元地址,N為采樣值個數,用MCS-51指令編寫的中值濾波子程序如下:副表
3.算術平均值濾波算法
算術平均濾波法就是連續(xù)取N次采樣值進行算術平均,其數學表達式是:
Y=∑yi
~y=1/N ∑ yi
i=1……N
式中~y——N個采樣值的算術平均值;
Yi ——第i個采樣值;
設8次采樣值依次存放在地址DATA開始的連續(xù)單元中,濾波結果保留在累加器A中,程序如下:副表
4.加權平均濾波法
算術平均濾波法存在前面所說的平滑和靈敏度之間的矛盾。采樣次數太少,平滑效果差,次數太多,靈敏度下降,對參數的變化趨勢不敏感。協(xié)調兩者關系,可采用加權平均濾波,對連續(xù)N次采樣值,分別乘上不同的加權系數之后再求累加和,加權系數一般先小后大,以突出后面若干采樣的效果,加強系統(tǒng)對參數的變化趨勢的辯識,各個加權系數均為小于1的小數,且滿足總和等于1的約束條件,這樣,加權運算之后的累加和即為有效采樣值。為方便計算,可取各個加權系數均為整數,且總和為256,加權運算后的累加和除以256(即舍去低字節(jié))后便是有效采樣值。
設每批采樣8個數據,依次存放在地址DATA開始的單元中,各加權系數是用一個表格存放在ROM中,MCS-51指令編寫的算術平均濾波程序如下:副表
5.滑動平均濾波法:
以上介紹的各種平均濾波算法有一個共同點,即每取得一個有效采樣值必須連續(xù)進行若干次采樣,當采樣速度較慢(如雙積分型A/D轉換)或目標參數變化較快時,系統(tǒng)的實時性不能保證,滑動平均濾波算法只采樣一次,將這一次采樣值和過去的若干次采樣值一起求平均,得到的有效采樣值即可投入使用,如果取N個采樣值求平均,RAM中必須開辟N個數據的暫存區(qū)。每新采樣一個數據便存入暫存區(qū),同時去掉一個最老的數據,保持這N個數據始終是最近的數據,這種數據存放方式可以用環(huán)行隊列結構方便的實現(xiàn)。設環(huán)行隊列為40H-4FH連續(xù)16個單元,RO作為隊尾指針,濾波程序如下:副表
6.低通濾波法:
將普通硬件RC低通濾波器的微分方程用差分方程來表求,變可以采用軟件算法來模擬硬件濾波的功能,經推導,低通濾波算法如下:
Yn=a* Xn+ (1-a) *Yn-1
式中Xn——本次采樣值
Yn-1——上次的濾波輸出值;
a——濾波系數,其值通常遠小于1;
Yn——本次濾波的輸出值。
由上式可以看出,本次濾波的輸出值主要取決于上次濾波的輸出值(注意不是上次的采樣值,這和加權平均濾波是有本質區(qū)別的),本次采樣值對濾波輸出的貢獻是比較小的,但多少有些修正作用,這種算法便模擬了具體有教大慣性的低通濾波器功能。濾波算法的截止頻率可用以下式計算:
fL=a/2Pitpi為圓周率3.14…
式中a——濾波系數;
t——采樣間隔時間;
例如:當t=0.5s(即每秒2次),a=1/32時;
fL=(1/32)/(2*3.14*0.5)=0.01Hz
當目標參數為變化很慢的物理量時,這是很有效的。另外一方面,它不能濾除高于1/2采樣頻率的干攪信號,本例中采樣頻率為2Hz,故對1Hz以上的干攪信號應采用其他方式濾除,
低通濾波算法程序于加權平均濾波相似,但加權系數只有兩個:a和1-a。為計算方便,a取一整數,1-a用256-a,來代替,計算結果舍去最低字節(jié)即可,因為只有兩項,a和1-a,均以立即數的形式編入程序中,不另外設表格。雖然采樣值為單元字節(jié)(8位A/D)。為保證運算精度,濾波輸出值用雙字節(jié)表示,其中一個字節(jié)整數,一字節(jié)小數,否則有可能因為每次舍去尾數而使輸出不會變化。
設Yn-1存放在30H(整數)和31H(小數)兩單元中,Yn存放在32H(整數)和33H(小數)中。濾波程序如下:副表
結束語:
微型計算機在儀器儀表系統(tǒng)中的成功應用,使傳統(tǒng)的電子儀器以及復雜的跟蹤測量裝置發(fā)生了許多革命性變化。其中一個突出表現(xiàn)就是一個系統(tǒng)中包含了智能性運作。微機具有很強的分析和運算能力,智能系統(tǒng)可完成復雜的數據處理,智能系統(tǒng)采用軟件硬件想結合的方法進行隨機誤差的數字濾波和系統(tǒng)誤差的修正,可以實現(xiàn)實時修正,較準測量數據,這些都是傳統(tǒng)儀器難以比擬的。
#include
#include
#include
#include <./Atmel/at89x52.h>
#include "source.h"
main()
{
filter_1();
filter_2();
filter_3();
filter_4();
filter_5();
filter_6();
filter_7();

filter_8();
filter_9();
filter_10();
}
unsigned char get_ad(void){
static unsigned char i;
return i++;
}
void delay(void){
unsigned char i=0;
while(1){
i++;
if(i>20) return;
}
}
#define A 10 //設置兩次采樣允許的最大偏差值
char value;//上次采用后的有效值變量
char filter_1(void){
charnew_value; //本次采樣值變量
new_value=get_ad(); //讀入本次采樣值
if((new_value-value>A)||(value-new_value>A))//比較是否超出最大偏差值
return value;//如果超出,返回上次的有效值作為本次的有效值
returnnew_value;// 如果沒有超出,返回本次的采樣值作為本次的有效值
}
#define N 11 //設置連續(xù)采樣的次數
char filter_2(void){
charvalue_buf[N]; //緩存N次采樣值的存儲變量
charcount,i,j,temp; //i,j是冒泡排序的下標變量,count是采樣數據讀入的下標變量
//temp是臨時變量
for(count=0;count
{
value_buf[count]=get_ad();
delay();
}
for(j=0;j
{
for(i=0;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];//將排序后N個采樣值的中間值作為最后結果返回
}
#undef N
#define N 12 //設置每組參與平均運算的采樣值個數
char filter_3(){
int sum=0;//求和變量,用于存儲采樣值的累加值
char count;//采樣數據讀入的下標變量
for(count=0;count
{
sum+=get_ad();
delay();
}
return (char)(sum/N);//講累加值進行平均計算作為返回值
}
#undef N
#define N 12 //設置FIFO隊列的長度
charvalue_buf[N];//FIFO隊列變量
char i=0;//隊列的下標變量
char filter_4(){
char count;
int sum=0;
value_buf[i++]=get_ad();
if(i==N)i=0;
for(count=0;count
sum+=value_buf[count];
return(char)(sum/N);
}
#undef N
#define N 12 //設置每組采樣值的數量
char filter_5()
{
char count,i,j,temp;//i,j是冒泡排序的下標變量,count是采樣數據讀入的下標變量
char value_buf[N]; // 緩沖N個采樣值的存儲變量
int sum=0;//求和變量,用于存儲采樣值的累加值
for(count=0;count
{
value_buf[count] = get_ad();
delay();
}
for (j=0;j
{
for (i=0;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(count=1;count
sum += value_buf[count];//去掉兩端的最小和最大采樣值,對中間的N-2個采樣值求和
return (char)(sum/(N-2));//返回中間N-2個采樣值的平均值
}
#undef A
#undef N
#define A 10 //設置兩次采樣允許的最大偏差值
#define N 12 //設置每組參與平均運算的采樣值個數
char value;//上次采用后的有效值變量
char filter_6()
{
charnew_value; //本次采樣值變量
int sum=0;//求和變量,用于存儲采樣值的累加值
char count;//采樣數據讀入的下標變量
for(count=0;count
{
new_value=get_ad(); //讀入本次采樣值
if((new_value-value>A)||(value-new_value>A))//比較是否超出最大偏差值
new_value=value;//如果超出,返回上次的有效值作為本次的有效值
sum+=new_value; //累加采樣的有效值
value=new_value;
delay();
}
return (char)(sum/N);//將累加值進行平均計算作為返回值
}
#define COE 50 //定義加權系數
char value; //上一個采樣值變量
char filter_7()
{
charnew_value; //本次采樣值變量
new_value = get_ad();
return (100-COE)*value + COE*new_value;//返回的本次濾波結果
}
#undef N
#define N 12//設置FIFO隊列的長度
char code coe[N] ={1,2,3,4,5,6,7,8,9,10,11,12}; //加權系數
char code sum_coe =1+2+3+4+5+6+7+8+9+10+11+12;
char filter_8()
{
char count; //采樣數據讀入的下標變量
char value_buf[N]; //緩存N個采樣值的存儲變量
int sum=0;//求和變量,用于存儲采樣值的累加值
for (count=0;count
{
value_buf[count] = get_ad();//讀入采樣值
delay();
}
for (count=0;count
sum += value_buf[count]*coe[count];//累加采樣值和系數的乘積
return (char)(sum/sum_coe);//累加值與系數和相除作為返回結果
}
#undef N
#define N 12 //設置計數器溢出值
char filter_9()
{
char count=0; //計數變量
char new_value; //本次采樣值變量
new_value = get_ad(); //讀入本次采樣值
while (value !=new_value);
{
count++; //計數器加1
if(count>=N)return new_value; //如果本次采樣值與當前有效值不相等,
//且計數器溢出,返回本次采樣值
delay();
new_value = get_ad();
}
return value;//如果本次采樣值與當前有效值相等,則返回當前有效值
}
#undef A
#undef N
#define A 10 //設置兩次采樣允許的最大偏差值
#define N 12 //設置計數器溢出值
char value;//有效值變量
char filter_10()
{
char count=0; //計數變量
char new_value; //本次采樣值變量
new_value = get_ad(); //讀入本次采樣值
if((new_value-value>A)||(value-new_value>A))//比較是否超出最大偏差值
new_value=value;//如果超出,返回有效值作為本次的采樣有效值
while (value !=new_value);
{
count++; //計數器加1
if(count>=N)return new_value; //如果本次采樣值與當前有效值不相等,
//且計數器溢出,返回本次采樣值
delay();
new_value = get_ad();
}
return value;//如果本次采樣值與當前有效值相等,則返回當前有效值
}
愛華網


