找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

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

(分享)程序上怎么減小誤/提高讀數(shù)精度?

  [復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
怎么減小傳感器讀數(shù)誤差?很多初學(xué)的時(shí)候,是一頭霧水的。---其實(shí)就是如何在算法“濾波”!!
好,如果你知道什么是“濾波”。那你以下的你都不用看,因?yàn)槟憧隙〞?huì)下面的了。
看,論壇也很多類似的帖子如下:如果不懂,請(qǐng)往下看


而這個(gè)前提是在你,所謂的在程序上減小誤差”,其實(shí)專業(yè)點(diǎn)叫“算法濾波”,簡稱濾波。對(duì)吧,挺簡單的。
但是,剛剛開始學(xué)習(xí)單片機(jī)的時(shí)候,真的不知道這個(gè)詞。經(jīng)常遇到下面的場景:
1,測量溫度的時(shí)候,變化太快,想慢一點(diǎn),怎么辦?
2,做一個(gè)電子稱,想讓他自動(dòng)去皮,怎么辦?
3,做超聲波測距的時(shí)候,想多次測量求平均值,怎么辦?


其實(shí),如果有人告訴你,這些都濾波算法。你再去上網(wǎng)一搜,立刻你能找到一大堆。所以,這個(gè)算法還是挺重要的。有時(shí)候,就是,你知道有這個(gè)東西,比你自己搗鼓很長時(shí)間有效。有句雞湯是這樣說的“方法有時(shí)候比努力重要!”
--------------------------------
---------------------------------
程序如下:
txt文件:
濾波算法.zip (3.51 KB, 下載次數(shù): 51)

//濾波算法:用一個(gè)程序上的濾波---比如求平均數(shù),排序等各種方法來用來調(diào)整誤差
//來源:摩爾吧公開課
//修改:2018年10月5日
//程序員:畫中仙


//-----------------------------------------------------------------------
//1.平均數(shù) 濾波----最基礎(chǔ)的
//方法:連續(xù)取N個(gè)采樣值進(jìn)行算術(shù)平均運(yùn)算;
//N值較大時(shí):信號(hào)平滑度較高,但靈敏度較低
//N值較小時(shí):信號(hào)平滑度較低,但靈敏度較高
//N值的選。阂话懔髁,N=12;壓力:N=4
//優(yōu)點(diǎn):試用于對(duì)一般具有隨機(jī)干擾的信號(hào)進(jìn)行濾波。
//       這種信號(hào)的特點(diǎn)是有一個(gè)平均值,信號(hào)在某一數(shù)值范圍附近上下波動(dòng)。
//缺點(diǎn):對(duì)于測量速度較慢或要求數(shù)據(jù)計(jì)算較快的實(shí)時(shí)控制不適用。

#define N 12
uint8 averageFilter()
{
    uint8 sum = 0;
    int i;
    for(i = 0; i < N; ++i)
    {
        sum += getValue();
        delay();
    }
    return sum/N;
}
//在調(diào)用函數(shù)中:
while(1)
{
    value = averageFilter();
}


//2.限幅濾波
//方法:根據(jù)經(jīng)驗(yàn)判斷,確定兩次采樣允許的最大偏差值(設(shè)為LIMIT)每次檢測到新值時(shí)判斷:
//如果本次值與上次值之差 <= LIMIT,則本次值有效如果本次值與上次值之差
//如果本次值與上次值之差> LIMIT,則本次值無效,放棄本次值,用上次值代替本次值
//優(yōu)點(diǎn):能有效克服因偶然因素引起的脈沖干擾
//getValue()作為變化的輸入值


  1. #define LIMIT 10;   //限制幅度設(shè)定為10
  2. uint8 amplitudeLimiterFilter(uint8 oldValue)
  3. {
  4.     uint8 newValue = getValue();
  5.     if( (newValue - oldValue) > LIMIT || (oldValue - newValue) < LIMIT))
  6.     {
  7.         return oldValue;
  8.     }
  9.     else
  10.     {
  11.         return newValue;
  12.     }
  13. }

  14. //在調(diào)用函數(shù)中:
  15. //注意oldValue的初始值,用第一次的采樣值作為oldValue
  16. value = getValue();   
  17. while(1)
  18. {
  19.     value = AmplitudeLimiterFilter(value);
  20. }
復(fù)制代碼



//-----------------------------------------------------------------------
//3.中位值濾波
//方法:連續(xù)采樣N次(N取奇數(shù))把N次采樣值按大小排列取中間值為本次有效值
//優(yōu)點(diǎn):能有效克服因偶然因素引起的波動(dòng)干擾;
//對(duì)溫度、液位等變化緩慢的被測參數(shù)有良好的濾波效果
//缺點(diǎn):對(duì)流量,速度等快速變化的參數(shù)不宜
  1. #define N 10
  2. uint8 middleValueFilter()
  3. {
  4.     uint8 value_buf[N];
  5.     uint8 i,j,k,temp;

  6.     for( i = 0; i < N; i++)    //取值
  7.     {
  8.         value_buf[i] = getValue();
  9.         delay();
  10.     }

  11.     for(j = 0 ; j < N-1; j++)   //從小到大排序,冒泡法排序
  12.     {
  13.         for(k = 0; k < N-j; k++)
  14.         {

  15.             if(value_buf[k] > value_buf[k+1])
  16.             {
  17.                 temp = value_buf[k];
  18.                 value_buf[k] = value_buf[k+1];
  19.                 value_buf[k+1] = temp;
  20.             }
  21.         }
  22.     }
  23.     return value_buf[(N-1)/2];      //取中間的值
  24. }
  25. //在調(diào)用函數(shù)中:
  26. while(1)
  27. {
  28.     value = middleValueFilter();
  29. }
復(fù)制代碼



//-----------------------------------------------------------------------
//4.遞推平均濾波法(又稱滑動(dòng)平均濾波法)
//方法: 把連續(xù)取N個(gè)采樣值看成一個(gè)隊(duì)列,隊(duì)列的長度固定為N
//      每次采樣到一個(gè)新數(shù)據(jù)放入隊(duì)尾,并扔掉原來隊(duì)首的一次數(shù)據(jù)(先進(jìn)先出原則)
//      把隊(duì)列中的N個(gè)數(shù)據(jù)進(jìn)行算術(shù)平均運(yùn)算,就可獲得新的濾波結(jié)果
//      N值的選。毫髁,N=12;壓力:N=4;液面,N=4~12;溫度,N=1~4

//優(yōu)點(diǎn):對(duì)周期性干擾有良好的抑制作用,平滑度高;試用于高頻振蕩的系統(tǒng)
//缺點(diǎn):靈敏度低;對(duì)偶然出現(xiàn)的脈沖性干擾的抑制作用較差,不適于脈沖干擾較嚴(yán)重的場合
//        比較浪費(fèi)RAM(改進(jìn)方法,減去的不是隊(duì)首的值,而是上一次得到的平均值)   

  1. #define N 20
  2. uint8 value_buf[N];
  3. uint8 moveAverageFilter(uint8 curValue, uint8 *sum, uint8 *curNum)
  4. {
  5.     uint8 i;
  6.     if(*curNum < N)
  7.     {
  8.         value_buf[*curNum] = curValue;
  9.         (*curNum)++;
  10.         sum += curValue;
  11.         retrun (*sum)/(*curNum);
  12.     }
  13.     else
  14.     {
  15.     //每次把后面的值往前移動(dòng)一位
  16.     /*    sum -= value_buf[0];
  17.         sum += curValue;
  18.         for(i = 1; i < N; ++i)
  19.         {
  20.             value_buf[i-1] = value_buf[i];
  21.         }
  22.         value_buf[N-1] = curValue;
  23.         return (*sum)/N;
  24.     */
  25.     //把新的值放在curNum%N的位置
  26.         sum -= value_buf[*curNum%N];
  27.         sum += curValue;
  28.         value_buf[*curNum%N] = curValue;
  29.         (*curNum)++;
  30.         if(*curNum == 2N)
  31.         {
  32.             (*curNum) = N;
  33.         }
  34.     }
  35. }   
  36. //減去的值是上次的平均值
  37. uint8 moveAverageFilter(uint8 *sum, uint8 curValue, uint8 num, uint8 *curNum)
  38. {
  39.     if(num <= 0)
  40.     {
  41.         return 0;
  42.     }
  43.     else
  44.     {
  45.         if(*curNum < num)
  46.         {
  47.             ++(*curNum);
  48.             *sum = *sum + curValue;
  49.             return (*sum)/(*curNum);
  50.         }
  51.         else
  52.         {
  53.             *sum = *sum - (*sum)/num;
  54.             *sum = (*sum + curValue);
  55.             return *sum/num;
  56.         }
  57.     }
  58. }
復(fù)制代碼



//-----------------------------------------------------------------------
//5.中位值平均濾波(防脈沖干擾平均濾波法)
//方法:相當(dāng)于“中位值濾波法”+“算術(shù)平均濾波法”
//        連續(xù)采樣N個(gè)數(shù)據(jù),去掉一個(gè)最大值和一個(gè)最小值然后計(jì)算N-2個(gè)數(shù)據(jù)的算術(shù)平均值
//        N值的選。3~14
//優(yōu)點(diǎn):融合了兩種濾波的優(yōu)點(diǎn)。對(duì)于偶然出現(xiàn)的脈沖性干擾,可消除有其引起的
//         采樣值偏差。對(duì)周期干擾有良好的抑制作用,平滑度高,適于高頻振蕩的系統(tǒng)。
//缺點(diǎn):測量速度慢
  1. #define N 10
  2. uint8 middleAverageFilter()
  3. {
  4.     uint8 i,j;
  5.     uint8 temp,value,sum = 0;
  6.     uint8 value_buf[N];
  7.     for(i = 0; i < N; ++i)
  8.     {
  9.         value_buf[i] = getValue();
  10.         delay();
  11.     }
  12.     //從小到大冒泡排序
  13.     for(j = 0; j < N-1; ++j)
  14.     {
  15.         for(i = 0; i < N-j; ++i)
  16.         {
  17.             if(value_buf[i] > value_buf[i+1])
  18.             {
  19.                 temp = value_buf[i];
  20.                 value_buf[i] = value_buf[i+1];
  21.                 value_buf[i+1] = temp;
  22.             }
  23.         }
  24.     }
  25.     for(i = 1; i < N-1; ++i)
  26.     {
  27.         sum += value_buf[i];
  28.     }
  29.     return sum/(N-2);
  30. }
復(fù)制代碼



//-----------------------------------------------------------------------
//6.遞推中位值濾波法
// 優(yōu)點(diǎn):對(duì)于偶然出現(xiàn)的脈沖性干擾,可消除由其引起的采樣值偏差。
// 對(duì)周期性干擾有良好的抑制作用,平滑度高;
// 試用于高頻振蕩的系統(tǒng)。
// 缺點(diǎn):測量速度慢

//取最近的10個(gè)值,去掉最大最小值求平均
//隊(duì)列queue中,第0個(gè)值換成新值,其余值依次往后移一個(gè)位置
  1. uint8 recursionMiddleFilter(uint8 newValue, uint8 *queue, uint8 num, uint8 *curNum)
  2. {
  3.     uint8 max, min, i;
  4.     queue[0] = newValue;
  5.     max = newValue;
  6.     min = newValue;
  7.     sum = newValue;
  8.     if( *curNum < num)
  9.     {
  10.         for(i = 0; i < *curNum; ++i)
  11.         {

  12.     for(i = num-1; i > 0; --i)
  13.     {
  14.         if(queue[i] > max)   
  15.         {   
  16.             max = queue[i];
  17.         }
  18.         else if(queue[i] < min)     
  19.         {
  20.             min = queue[i];
  21.         }
  22.         sum = sum + queue[i];
  23.         queue[i] = queue[i-1];
  24.     }
  25.     sum = sum - max - min;
  26.     return sum/num;
  27. }
復(fù)制代碼



//-----------------------------------------------------------------------   
//7.限幅平均濾波法
//方法:相當(dāng)于“限幅濾波法”+“遞推平均濾波法”
//        每次采樣到的新數(shù)據(jù)先進(jìn)行限幅處理再送入隊(duì)列進(jìn)行遞推平均濾波處理
//優(yōu)點(diǎn):對(duì)于偶然出現(xiàn)的脈沖性干擾,可消除有其引起的采樣值偏差。   
//缺點(diǎn):比較浪費(fèi)RAM   
  1. #define A 10
  2. #define N 12
  3. unsigned char data[];
  4. unsigned char filter(data[])
  5. {
  6.   unsigned char i;
  7.   unsigned char value,sum;
  8.   data[N]=GetAD();
  9.   if(((data[N]-data[N-1])>A||((data[N-1]-data[N])>A))
  10.   data[N]=data[N-1];
  11.   //else data[N]=NewValue;
  12.   for(i=0;i<N;i++)
  13.   {
  14.     data[i]=data[i+1];
  15.     sum+=data[i];
  16.   }
  17.   value=sum/N;
  18.   return(value);
  19. }
復(fù)制代碼


//8.一階滯后濾波法
//方法:取a=0~1,本次濾波結(jié)果=(1-a)*本次采樣值+a*上次濾波結(jié)果   
//優(yōu)點(diǎn):對(duì)周期性干擾具有良好的抑制作用適用于波動(dòng)頻率較高的場合
//缺點(diǎn):相位滯后,靈敏度低滯后程度取決于a值大小不能消除濾波頻率高于采樣頻率的1/2的干擾信號(hào)
  1. float a;
  2. uint8 firstOrderFilter(uint8 newValue, uint8 oldValue)
  3. {
  4.     return  a * newValue + (1-a) * oldValue;
  5. }

  6. //使用
  7. value = getValue();
  8. while(1)
  9. {
  10.     value = firstOrderFilter(getValue(),value);
  11. }
復(fù)制代碼



//-----------------------------------------------------------------------
//9.加權(quán)遞推平均濾波法(并沒有遞推)
//方法:是對(duì)遞推平均濾波法的改進(jìn),即不同時(shí)刻的數(shù)據(jù)加以不同的權(quán);
//        通常是,越接近現(xiàn)時(shí)刻的數(shù)值,權(quán)取得越大;
//        給予新采樣值的權(quán)系數(shù)越大,則靈敏度越高,但信號(hào)平滑度越低。               
//優(yōu)點(diǎn):適用于有較大純滯后時(shí)間常數(shù)的對(duì)象和采樣周期較短的系統(tǒng)
//缺點(diǎn):對(duì)于純滯后時(shí)間常數(shù)較小,采樣周期較長
//        變化緩慢的信號(hào)不能迅速反應(yīng)系統(tǒng)當(dāng)前所受干擾的嚴(yán)重程度,濾波效果差。

  1. #define N 10
  2. uint8 weight[N] = {1,2,3,4,5,6,7,8,9,10};
  3. uint8 weigth_sum = 1+2+1+2+3+4+5+6+7+8+9+10;
  4. uint8 weightAverageFilter()
  5. {
  6.     uint8 value_buf[N];
  7.     uint8 i, sum = 0;
  8.     for(i = 0; i < N; ++i)
  9.     {
  10.         value_buf[i] = getValue();
  11.         delay();
  12.     }
  13.     for(i = 0; i < N; ++i)
  14.     {
  15.         sum += value_buf[i] * weight[i];
  16.     }
  17.     return sum/weight_sum;
  18. }
復(fù)制代碼



//-----------------------------------------------------------------------
//10.消抖濾波法
//方法:比如開關(guān),剛按下去的時(shí)候會(huì)產(chǎn)生抖動(dòng),但是經(jīng)過一段時(shí)間后回到穩(wěn)態(tài);
//        如果N次后,還不是穩(wěn)態(tài),就取當(dāng)前值作為新狀態(tài)值
//        設(shè)置一個(gè)濾波計(jì)數(shù)器,將每次采樣值與當(dāng)前有效值比較:
//        如果采樣值=當(dāng)前有效值,則計(jì)數(shù)器清零
//        如果采樣值<>當(dāng)前有效值,則計(jì)數(shù)器+1,并判斷計(jì)數(shù)器是否>=上限N(溢出)
//        如果計(jì)數(shù)器溢出,則將本次值替換當(dāng)前有效值,并清計(jì)數(shù)器
//優(yōu)點(diǎn):對(duì)于變化緩慢的被測參數(shù)有較好的濾波效果,可避免在臨界值附近控制器的反復(fù)開/關(guān)跳動(dòng)或顯示器上數(shù)值抖動(dòng)
//缺點(diǎn):對(duì)于快速變化的參數(shù)不宜
//        如果在計(jì)數(shù)器溢出的那一次采樣到的值恰好是干擾值,則會(huì)將干擾值當(dāng)作有效值   

  1. uint8 glitchFilter(uint8 oldValue)
  2. {
  3.     uint8 newValue = getValue();
  4.     uint8 count = 0;
  5.     while(oldValue != newValue)
  6.     {
  7.         count ++;
  8.         if(count >= N)
  9.         {
  10.             return newValue;
  11.         }
  12.         delay();
  13.         newValue = getValue();
  14.     }
  15.     return oldValue;
  16. }
復(fù)制代碼

評(píng)分

參與人數(shù) 2黑幣 +85 收起 理由
admin + 50 共享資料的黑幣獎(jiǎng)勵(lì)!
angmall + 35 贊一個(gè)!

查看全部評(píng)分

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

使用道具 舉報(bào)

沙發(fā)
ID:164602 發(fā)表于 2018-10-6 08:04 | 只看該作者
有點(diǎn)意思。頂一下。
回復(fù)

使用道具 舉報(bào)

板凳
ID:308437 發(fā)表于 2018-10-6 21:24 | 只看該作者
HC6800-ES-V2.0 發(fā)表于 2018-10-6 08:04
有點(diǎn)意思。頂一下。

額,不敢當(dāng)哈。這個(gè)是個(gè)人見解,不喜勿噴~
回復(fù)

使用道具 舉報(bào)

地板
ID:156220 發(fā)表于 2019-1-8 17:18 | 只看該作者
謝謝樓主的分享 ,學(xué)習(xí)了,有用
回復(fù)

使用道具 舉報(bào)

5#
ID:588676 發(fā)表于 2019-7-30 14:09 | 只看該作者
厲害,學(xué)習(xí)了
回復(fù)

使用道具 舉報(bào)

6#
ID:831355 發(fā)表于 2020-10-27 10:57 | 只看該作者
太厲害了,膜拜
回復(fù)

使用道具 舉報(bào)

7#
ID:861022 發(fā)表于 2020-12-15 22:52 | 只看該作者
6怎么減小傳感器讀數(shù)誤差?
回復(fù)

使用道具 舉報(bào)

8#
ID:882212 發(fā)表于 2021-3-16 15:52 | 只看該作者
好教程,值得學(xué)習(xí)。
回復(fù)

使用道具 舉報(bào)

9#
ID:884815 發(fā)表于 2021-8-9 11:10 | 只看該作者
很有用的資料,學(xué)習(xí)了
回復(fù)

使用道具 舉報(bào)

10#
ID:965367 發(fā)表于 2021-9-10 22:28 | 只看該作者

謝謝樓主的分享 ,學(xué)習(xí)了,有用
回復(fù)

使用道具 舉報(bào)

11#
ID:999623 發(fā)表于 2022-1-4 14:25 | 只看該作者
過采樣方法,也可以增大精度
回復(fù)

使用道具 舉報(bào)

12#
ID:99525 發(fā)表于 2022-5-4 11:26 | 只看該作者
實(shí)際上就是為了減少線路或器件干擾帶來的偶發(fā)誤差,避免系統(tǒng)產(chǎn)生誤判!
回復(fù)

使用道具 舉報(bào)

13#
ID:1037221 發(fā)表于 2022-10-22 10:19 | 只看該作者
卡爾曼濾波算法可以介紹一下嗎?
回復(fù)

使用道具 舉報(bào)

14#
ID:1065536 發(fā)表于 2024-1-19 12:27 | 只看該作者
膜拜大佬
回復(fù)

使用道具 舉報(bào)

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

本版積分規(guī)則

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

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

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