痞酷網_PIGOO

 找回密碼
 立即註冊
!!! [系統偵測到廣告阻擋軟體] !!!

如果您覺得痞酷網對您有些許幫助,或者您認同痞酷網的理想,

那麼希望您將痞酷網設定為白名單.

並請在上論壇的時候,動動您的手指,用行動支持我們.

謝謝!
查看: 8258|回復: 3

[教學文獻] 濾波功能的子程式 分享一小段原程式碼分析

[複製鏈接]
發表於 2011-9-6 00:28:13 | 顯示全部樓層 |閱讀模式
濾波功能的子程式 分享一小段原程式碼分析
====================================
不知該放 哪一版  DIY / 軟體   版大若是覺得不妥 移版或刪文
因為自動控制版 有討論到8051 我就放到這裡  文筆差請各位原諒
====================================
程式來源是PHILIPS 充電器示範用程式碼,  中擷取出一小段, 濾波功能的子程式
程式結構非常簡單, 背後卻是大有深意, 了解之後對DIY同好有相當助益

原配合電路以RC積分加上電壓OPA比較器, 用來與待測ANALOG 電壓 作比較 ,
並以16bit  timer 0xffff 導數計時 .
計算 RC積分電壓 從清除開始要昇到等同待測電壓 , 所必須花費的時間  .
此時timer 上的數值 , 即為待測電壓的數位量化值 .
~~就是最簡單的ADC~~

輸入值若是遇到雜訊干擾 , ADC  產生異常數值
以下就是將數位量化值 經過濾波演算的子程式
事實上是新數值連同7組舊數值以連續平均值運算
將偶爾異常數值(雜訊) 均分掉  進而提昇系統容錯能力
整個功能像不像電容濾波濾雜訊?

若是用在DIY 的LCR 頻率計 DC_SEVO相位檢測修正……等等
不方便直接使用電容濾雜訊或是電容不能放太大場合  可以拿來參考修改

以下藍色部分就是將數位量化值 經過濾波演算的子程式
中文注解是 我加上的

1.宣告 全域變數  用來蓄存
       word this_period         最新量化值
       word last1~ word last7  前次7組資料
2. 程式演算
將最新數值 與前次7組資料作平均值運算後
    推移更新前次7組資料 並且將運算值回存到最新數值
      
/* 宣告 全域變數  使用RAM */

/* global variables */
word this_period; /* 最新量化值    */
word last1;        /*  前1次量化值  */
word last2;        /*  前2次量化值  */
word last3;        /*  前3次量化值  */
word last4;        /*  前4次量化值  */
word last5;        /*  前5次量化值  */
word last6;        /*  前6次量化值  */
word last7;        /*  前7次量化值  */

word
filter (
word last0
) {                                     /* 區域變數 word last0 = 2 byte */
word temp1, temp2, temp3, temp4;  /* 區域變數 4 word= 8 byte */
word result1, result2;              /* 區域變數 2 word= 4 byte */
temp1 = ((last0 / 2) + (last1 / 2));  
temp2 = ((last2 / 2) + (last3 / 2));
temp3 = ((last4 / 2) + (last5 / 2));
temp4 = ((last6 / 2) + (last7 / 2));
result1 = ((temp1 / 2) + (temp2 / 2));
result2 = ((temp3 / 2) + (temp4 / 2));
last7 = last6;
last6 = last5;
last5 = last4;
last4 = last3;
last3 = last2;
last2 = last1;
last1 = last0;
return((result1 / 2) + (result2 / 2));
}

======================================  
以下是我個人想法分析
======================================  

  temp1 = ((last0 / 2) + (last1 / 2)) ;

  表面上temp1 是 last0 和 last1 平均數
  那為何不直接寫成   temp1 = ((last0 + last1) / 2) ;
   這是因為 last0 + last1 直接相加 可能造成溢位錯誤
   (好一點的compiler會發出溢位警告 若是組和語言會不警告你)
    假設 last0 =  1??? ???? ???? ????  
         last1 =  1??? ???? ???? ????
    那麼該數值相加後最高位元 將產生進位而超出最高位元 產生溢位錯誤
    一般在PC環境執行的軟體手法上 會直接宣告 以更長更大double word 雙字元組
     來承載 兩個字元組 之和
     Double word temp1;
     temp1 = ((last0 + last1) / 2) ;
   奈何這裡使用的是8位元單晶片  可供蓄存變數的  RAM 記憶體 少的可憐
  不仿想像成 at89c2051 之類 [宣告double word ] 無疑是個敗家子行為
  
將某一數值作 (數值/2) 這樣的運算在表面上是除以2
  實際上是右移1位 因此可以寫成
   temp1 = ((last0 >> 1 ) + (last1 >> 1 ));
  只是說  程式用意是求平均數  使用數學運算式表達  更易於清楚辨識程式目的
  將來修改維護時 不會一頭霧水  引起誤解

  說到誤解 我曾經改寫如下
/* 新平均數 = ( 舊7組數值 + 新1組數值 ) /8
            = ( 舊7組數值 / 8 ) + ( 新1組數值 /8 )
         舊7組數值 改用1組舊平均數值last_n代表  (7/8) = ( 1-1/8)
         新1組數值佔平均數比例  1/8 新數值
*/
  last0 = (((last_n - (last_n / 8)) + last0 / 8 ) ;

  結果濾波器程式 濾很大一些細微變化
  last0最後面3個位元 全被(數值/8)這個動作砍了
  last0 新數值 若是只有最後面3個位元有變化時 全被(數值/8)砍了
  因此連續幾次輸入新數值  整組平均數根本沒變化 表面上很穩定
  系統輸入的靈敏度解析度 變得非常遲鈍 動態表現很差

所以原式全段皆使用(數值/2) 只砍最後面1個位元 就是希望最大限度保留精細度

評分

4

查看全部評分

發表於 2011-9-7 09:18:49 | 顯示全部樓層
Very Nice sharing! Thanks!
發表於 2011-9-7 10:03:17 | 顯示全部樓層
好東西~~~感謝你的教學~~
發表於 2011-9-12 11:22:40 | 顯示全部樓層
好仔細的分析, 補充一下俺使用過的經驗, 這就是典型的 數位濾波方法之一, [簡單移動平均數] 算法

洋人稱為 (simple moving average algorithm)

原理有看過類似的, http://www.dspguide.com/CH15.PDF

至於精度, 就有多種方案達成, 會因為不同的CPU和COMPLIER各有特色, 但是基本用ASM寫的話, 這個原理一定要很明確掌握才寫得好.

如果要測驗自己寫的或是COMPLIER得到的算法是否夠好, 可用 EXCEL, 輸入一系列的數據, 再用他提供的 [移動平均數] 函數算出一系列的結果比對就知道誤差多寡, 也就是自己寫得有沒有達到微軟的水準.

另外也用過一種更快速的算法 [first order filter] 或稱為 [low pass filter], 不過還沒有時間驗證其誤差, 全部 ADC 的場合, 都會用到數位濾波方法, 有興趣的可參考.
http://hk.myblog.yahoo.com/xiao-laba/article?mid=2613
http://hk.myblog.yahoo.com/xiao-laba/article?mid=2623
您需要登錄後才可以回帖 登錄 | 立即註冊

本版積分規則

關閉

站長小叮嚀上一條 /1 下一條

禁閉室|手機版|連繫我們|痞酷網電子技術論壇

GMT+8, 2024-11-21 08:59 PM , Processed in 0.254770 second(s), 19 queries , Gzip On.

Powered by Discuz! X3.4 Licensed

© 2001-2023 Discuz! Team.