濾波器的技術指標
$\omega _p$:通帶截止頻率
$\omega _s$:阻帶截止頻率
$\delta_p$:通帶波動
$\delta_s$:阻帶波動
衰減單位是db
巴特沃斯濾波器
butterworth低通濾波器的頻域特性
$$|H(jw)|^2=\frac{1}{1+(\frac{\omega }{\omega _c})^{2N}}$$
N:濾波器的階數
$\omega _c$:3dB截頻
圖 典型BW低通濾波器的幅度響應
特點:在通帶的頻率響應曲線最平滑
Python實現
scipy.signal.butter(N, Wn, btype='low', analog=False, output='ba')
輸入
- N:濾波器的階數
- Wn:對於數字濾波器:Wn應該歸一化為(0,1),Wn=截止頻率/訊號頻率,(訊號頻率=取樣率的一半,奈奎斯特取樣定理)對於模擬濾波器:Wn是角頻率,弧度/樣本,rad/s
- btype:濾波器的型別{'lowpass','highpass','bandpass','bandstop'}
- analog:如果為True,則返回模擬濾波器,否則返回數字濾波器。
輸出
- b,a:濾波器係數, a為分母,b為分子。
scipy.signal.
freqs
(b, a, worN=200, plot=None)
計算模擬濾波器的頻率響應H(w)。
引數
- b,a:濾波器的分子和分母,
- worN:可選,如果為None,則計算響應曲線的有趣部分周圍的200個頻率。如果是一個整數,則計算那麼多頻率。
返回
- w:計算h的角頻率
- h:頻率響應
scipy.signal.freqz(b, a=1, worN=None, whole=False, plot=None)
計算數字濾波器的頻率響應。
引數
- b,a:線性濾波器的分子和分母
- worN:如果為None(預設值),則計算在單位圓周圍等間隔的512個頻率。如果是一個整數,則計算那麼多頻率。如果是array_like,則計算給定頻率的響應(以弧度/樣本為單位)。
返回
- w:計算h的歸一化頻率,以弧度/樣本計算。
- h:頻率響應
scipy.signal.lfilter(b, a, x, axis=-1, zi=None)
使用IIR或FIR濾波器沿一維過濾資料。使用數字濾波器過濾資料序列x。
輸入
- b,a:分子和分母,即濾波器係數
- x:輸入資料
返回:數字濾波器的輸出
from scipy.signal import butter, lfilter from scipy import signal import numpy as np import matplotlib.pyplot as plt b, a = signal.butter(4, 100, 'low', analog=True) # 設計N階數字或模擬Butterworth濾波器並返回濾波器係數 w, h = signal.freqs(b, a) # 根據係數計算濾波器的頻率響應,w是角頻率,h是頻率響應 plt.semilogx(w, 20 * np.log10(abs(h))) plt.title('Butterworth filter frequency response') plt.xlabel('Frequency [radians / second]') plt.ylabel('Amplitude [dB]') plt.margins(0, 0.1) plt.grid(which='both', axis='both') plt.axvline(100, color='green') # cutoff frequency plt.show()
提取窄帶語音訊號
對取樣率為16000Hz,奈奎斯特頻率為8000Hz的語音,通過巴特沃斯低通濾波器,濾除高於4000Hz頻率的語音,提取低頻語音。過濾出的訊號,在取樣率相同的情況下,頻率只有原來的一半。
import librosa import numpy as np from scipy.signal import butter, lfilter, freqz import matplotlib.pyplot as plt def butter_lowpass(cutoff, fs, order=5): # cutoff:截止頻率 # fs 取樣率 nyq = 0.5 * fs # 訊號頻率 normal_cutoff = cutoff / nyq # 正常截止頻率=截止頻率/訊號頻率 b, a = butter(order, normal_cutoff, btype='lowpass', analog=False) return b, a def butter_lowpass_filter(data, cutoff, fs, order=5): b, a = butter_lowpass(cutoff, fs, order=order) y = lfilter(b, a, data) return y # Filter requirements. order = 10 fs = 16000 # 取樣率, Hz cutoff = 4000 # 濾波器的期望截止頻率,Hz # 得到濾波器係數,這樣我們就可以檢查它的頻率響應。 b, a = butter_lowpass(cutoff, fs, order) # 繪製頻率響應 w, h = freqz(b, a) plt.subplot(3, 1, 1) plt.plot(0.5*fs*w/np.pi, np.abs(h), 'b') plt.axvline(cutoff, color='k') plt.xlim(0, 0.5*fs) plt.title("Lowpass Filter Frequency Response") plt.xlabel('Frequency [Hz]') data, wav_fs = librosa.load("./48k/p225_001.wav", sr=16000, mono=True) # 48000--->16000 y = butter_lowpass_filter(data, cutoff, fs, order) plt.subplot(3, 1, 2) plt.specgram(data, Fs=16000, scale_by_freq=True, sides='default') plt.xlabel('Time [sec]') plt.subplot(3, 1, 3) plt.specgram(y, Fs=16000, scale_by_freq=True, sides='default') plt.xlabel('Time [sec]') plt.show()
切比雪夫I形狀濾波器
CB I型低通濾波器的頻域特性
$$|H(jw)|^2=\frac{1}{1+\varepsilon ^2C_N^2(\frac{w}{w_c})}$$
N:濾波器的階數
$\varepsilon$:通帶波紋
$\omega _c$:通帶截頻
圖 CB I型低通濾波器的幅度響應
特點:通帶是等波動的,阻帶是單調的
scipy.signal.cheby1(N, rp, Wn, btype='low', analog=False, output='ba')
Chebyshev I型數字和模擬濾波器,設計N階數字或模擬Chebyshev I型濾波器並返回濾波器係數。
引數:
- N:濾波器的階數
- rp:通帶中允許的最大紋波低於單位增益,以分貝為單位,正數
- Wn:對於數字濾波器:Wn應該歸一化為(0,1),Wn=截止頻率/訊號頻率,(訊號頻率=取樣率的一半,奈奎斯特取樣定理)對於模擬濾波器:Wn是角頻率,弧度/樣本,rad/s
- btype:濾波器的型別{'lowpass','highpass','bandpass','bandstop'}
- analog:如果為True,則返回模擬濾波器,否則返回數字濾波器。
- output:預設“ba”,輸出分子和分母
返回
- b,a:濾波器係數, a為分母,b為分子。
import numpy as np from scipy import signal import matplotlib.pyplot as plt b, a = signal.cheby1(4, 5, 100, 'low', analog=True) w, h = signal.freqs(b, a) plt.semilogx(w, 20 * np.log10(abs(h))) plt.title('Chebyshev Type I frequency response (rp=5)') plt.xlabel('Frequency [radians / second]') plt.ylabel('Amplitude [dB]') plt.margins(0, 0.1) plt.grid(which='both', axis='both') plt.axvline(100, color='green') # cutoff frequency plt.axhline(-5, color='green') # rp plt.show()
切比雪夫II形狀濾波器
CB II型低通濾波器的頻域特性
$$|H(jw)|^2=1-\frac{1}{1+\varepsilon ^2C_N^2(\frac{w}{w_c})}$$
N:濾波器的階數
$\varepsilon$:阻帶波紋
$\omega _c$:阻帶截頻
圖 CB II型低通濾波器的幅度響應
特點:通帶是單調的,阻帶是等波動的
scipy.signal.cheby2(N, rs, Wn, btype='low', analog=False, output='ba')
Chebyshev II型數字和模擬濾波器,設計N階數字或模擬Chebyshev II型濾波器並返回濾波器係數。
引數:
- N:濾波器的階數
- rs:阻帶所需最小衰減,以分貝為單位,正數
- Wn:對於數字濾波器:Wn應該歸一化為(0,1),Wn=截止頻率/訊號頻率,(訊號頻率=取樣率的一半,奈奎斯特取樣定理)對於模擬濾波器:Wn是角頻率,弧度/樣本,rad/s
- btype:濾波器的型別{'lowpass','highpass','bandpass','bandstop'}
- analog:如果為True,則返回模擬濾波器,否則返回數字濾波器。
- output:預設“ba”,輸出分子和分母
返回
- b,a:濾波器係數, a為分母,b為分子。
from scipy import signal import numpy as np import matplotlib.pyplot as plt b, a = signal.cheby2(4, 40, 100, 'low', analog=True) w, h = signal.freqs(b, a) plt.semilogx(w, 20 * np.log10(abs(h))) plt.title('Chebyshev Type II frequency response (rs=40)') plt.xlabel('Frequency [radians / second]') plt.ylabel('Amplitude [dB]') plt.margins(0, 0.1) plt.grid(which='both', axis='both') plt.axvline(100, color='green') # cutoff frequency plt.axhline(-40, color='green') # rs plt.show()
橢圓低通濾波器
橢圓模擬低通濾波器的頻域特性
圖 橢圓低通濾波器的幅度相應
特點:通帶和阻帶都等波動
scipy.signal.ellip(N, rp, rs, Wn, btype='low', analog=False, output='ba')
橢圓數字和模擬濾波器,設計N階數字或模擬橢圓濾波器並返回濾波器係數。
引數:
- N:濾波器的階數
- rp:通帶中允許的最大紋波低於單位增益,以分貝為單位,正數
- rs:阻帶所需最小衰減,以分貝為單位,正數
- Wn:對於數字濾波器:Wn應該歸一化為(0,1),Wn=截止頻率/訊號頻率,(訊號頻率=取樣率的一半,奈奎斯特取樣定理)對於模擬濾波器:Wn是角頻率,弧度/樣本,rad/s
- btype:濾波器的型別{'lowpass','highpass','bandpass','bandstop'}
- analog:如果為True,則返回模擬濾波器,否則返回數字濾波器。
- output:預設“ba”,輸出分子和分母
返回
- b,a:濾波器係數, a為分母,b為分子。
import numpy as np from scipy import signal import matplotlib.pyplot as plt b, a = signal.ellip(4, 5, 40, 100, 'low', analog=True) w, h = signal.freqs(b, a) plt.semilogx(w, 20 * np.log10(abs(h))) plt.title('Elliptic filter frequency response (rp=5, rs=40)') plt.xlabel('Frequency [radians / second]') plt.ylabel('Amplitude [dB]') plt.margins(0, 0.1) plt.grid(which='both', axis='both') plt.axvline(100, color='green') # cutoff frequency plt.axhline(-40, color='green') # rs plt.axhline(-5, color='green') # rp plt.show()
下采樣方法
插值方法進行下采樣
Volodymyr Kuleshov的論文中使用抗混疊濾波器對語音訊號進行下采樣,再通過三次樣條插值把下采樣訊號上取樣到相同的長度。
from scipy.signal import decimate import librosa import numpy as np import matplotlib.pyplot as plt from scipy import interpolate def upsample(x_lr, r): """ 上取樣,每隔一步去掉語音波形的r個點,然後用三次樣條插值的方法把去掉的點補回來,有機會可以畫圖看看 :param x_lr: 音訊資料 :param r: 樣條插值前個數 :return: 樣條插值後的音訊訊號 """ x_lr = x_lr.flatten() # 把x_lr陣列摺疊成一維的陣列 x_hr_len = len(x_lr) * r i_lr = np.arange(x_hr_len, step=r) i_hr = np.arange(x_hr_len) f = interpolate.splrep(i_lr, x_lr) # 樣條曲線插值係數 x_sp = interpolate.splev(i_hr, f) # 給定樣條表示的節點和係數,返回在節點處的樣條值 return x_sp yt, wav_fs = librosa.load("./48k/p225_001.wav", sr=16000, mono=True) x_lr = decimate(yt, 2) # 應用抗混疊濾波器後對訊號進行下采樣,獲得低解析度音訊,下采樣因子scale=2 print(len(yt)) print(len(x_lr)) plt.subplot(2, 1, 1) plt.specgram(yt, Fs=16000, scale_by_freq=True, sides='default') x_lr = upsample(x_lr, 2) # 上取樣 plt.subplot(2, 1, 2) plt.specgram(x_lr, Fs=16000, scale_by_freq=True, sides='default') plt.show()
重取樣(signal.resample)——下采樣
利用重新取樣的方法對語音進行下采樣
scipy.signal.resample(x, num, t=None, axis=0, window=None)
沿給定軸使用傅立葉方法重新取樣x到num個樣本。因為使用傅立葉方法,所以假設訊號是週期性的。
引數:
- x:要重取樣的陣列
- num:重取樣訊號的樣本數
返回:
- resample_x:重新取樣返回的陣列
import librosa from scipy import signal import numpy as np import matplotlib.pyplot as plt y, wav_fs = librosa.load("./48k/p225_001.wav", sr=16000, mono=True) f = signal.resample(y, len(y)//2) f = signal.resample(f, len(y)) plt.subplot(2,1,1) plt.specgram(y, Fs=16000, scale_by_freq=True, sides='default') plt.subplot(2,1,2) plt.specgram(f, Fs=16000, scale_by_freq=True, sides='default') plt.show()
librosa.core.resample重取樣(下采樣)
凌振華老師的下采樣方法和上面的一樣
import librosa from scipy import signal import numpy as np import matplotlib.pyplot as plt y, wav_fs = librosa.load("./48k/p225_001.wav", sr=16000, mono=True) audio8k = librosa.core.resample(y, wav_fs, wav_fs/2) # 下采樣率 16000-->8000 audio8k = librosa.core.resample(audio8k, wav_fs/2, wav_fs) # 上取樣率 8000-->16000,並不恢復高頻部分 plt.subplot(2,1,1) plt.specgram(y, Fs=16000, scale_by_freq=True, sides='default') plt.subplot(2,1,2) plt.specgram(audio8k, Fs=16000, scale_by_freq=True, sides='default') plt.show()
librosa.load下采樣
用librosa.load想下采樣,再不恢復頻率的情況下上取樣。
import librosa import matplotlib.pyplot as plt y_16k, fs_16k = librosa.load("./48k/p225_001.wav", sr=16000, mono=True) y_8k, fs_8k = librosa.load("./48k/p225_001.wav", sr=8000, mono=True) librosa.output.write_wav('./8k_sample.wav', y_8k, sr=8000) # 把下采樣的寫好 y_8k, fs_8k = librosa.load("./8k_sample.wav", sr=16000, mono=True) # 失去的就補不回來了 plt.subplot(2, 1, 1) plt.specgram(y_16k, Fs=16000, scale_by_freq=True, sides='default') plt.xlabel('16k') plt.subplot(2, 1, 2) plt.specgram(y_8k, Fs=16000, scale_by_freq=True, sides='default') plt.xlabel('8k') plt.show()
參考文獻