標籤:style blog http for 2014 代碼 ar 演算法
最近做項目要提取一個聲音訊號的包絡波形,所以花了點時間研究各種包絡提取的演算法。
所謂包絡檢測又叫幅度解調,在許多領域都有重要的應用。如果載波訊號是確定的,那麼通常可以採用同步解調的方式,這種方式的信噪比最好,對訊號中混入的雜訊的抑制能力最強。所謂同步解調是通訊領域通常的叫法。在訊號檢測領域,這種方式通常稱為“相敏檢波”,鎖相放大器(Lock-in Amplifier)採用的就是這種方式最典型的例子。
如果載波比較亂,就像我現在的應用情境,要提取雜訊的幅度隨時間變化的規律,那麼包絡檢波法會更適宜。我這裡的代碼就是採用的包絡檢波法。
包絡檢波法的基本原理可以看下面這個電路圖,這個是最基本的半波包絡檢波。
把這個過程用程式來實現就有了下面的代碼。
/** * 包絡檢波,類比了硬體半波檢波的過程 * rc = 0 時初始化 **/double env_1(double x, double rct){ static double old_y = 0.0; if(rct == 0.0) { old_y = 0.0; } else { if(x > old_y) { old_y = x; } else { old_y *= rct / ( rct + 1 ); } } return old_y;}void env_2(double x[], double y[], int N, double rct){ double xx = 0.0; int i; y[0] = fabs(x[0]); for(i = 1; i < N; i++) { if( x[i] > y[i-1]) { y[i] = x[i]; } else { y[i] = y[i-1] * rct / ( rct + 1 ); } }}
上面是半波檢測的代碼,只要稍微增加幾行,就能實現全波檢測。
/** * 包絡檢波,類比了硬體全波檢波的過程 * rc = 0 時初始化 **/double env_3(double x, double rct){ static double old_y = 0.0; if(rct == 0.0) { old_y = 0.0; } else { x = fabs(x); if(x > old_y) { old_y = x; } else { old_y *= rct / ( rct + 1 ); } } return old_y;}void env_4(double x[], double y[], int N, double rct){ double xx = 0.0; int i; y[0] = fabs(x[0]); for(i = 1; i < N; i++) { xx = fabs(x[i]); if( xx > y[i-1]) { y[i] = xx; } else { y[i] = y[i-1] * rct / ( rct + 1 ); } }}
這個代碼中有個參數 rct,對應的是硬體電路中的RC時間常數,要根據待檢測的包絡訊號的頻帶來確定。
下面是用這個代碼實際提取包絡的算例。可以看出這個代碼的效果還是蠻不錯的。(比採用Hilbert 變換得到的結果還要好)