ω s \omega _s ωs:阻带截止频率
δ p \delta_p δp:通带波动
δ s \delta_s δs:阻带波动
衰减单位是db
butterworth低通滤波器的频域特性
∣ H ( j w ) ∣ 2 = 1 1 + ( ω ω c ) 2 N |H(jw)|^2=\frac{1}{1+(\frac{\omega }{\omega _c})^{2N}} ∣H(jw)∣2=1+(ωcω)2N1
N:滤波器的阶数
ω c \omega _c ωc:3dB截频
图2 典型BW低通滤波器的幅度响应
特点:在通带的频率响应曲线最平滑
scipy.signal.butter(N, Wn, btype='low', analog=False, output='ba')
输入
输出
scipy.signal.freqs(b, a, worN=200, plot=None)
计算模拟滤波器的频率响应H(w)。
参数
返回
scipy.signal.freqz(b, a=1, worN=None, whole=False, plot=None)
计算数字滤波器的频率响应。
参数
返回
scipy.signal.lfilter(b, a, x, axis=-1, zi=None)
使用IIR或FIR滤波器沿一维过滤数据。使用数字滤波器过滤数据序列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()
CB I型低通滤波器的频域特性
∣ H ( j w ) ∣ 2 = 1 1 + ε 2 C N 2 ( w w c ) |H(jw)|^2=\frac{1}{1+\varepsilon ^2C_N^2(\frac{w}{w_c})} ∣H(jw)∣2=1+ε2CN2(wcw)1
N:滤波器的阶数
ε \varepsilon ε:通带波纹
ω c \omega _c ωc:通带截频
图 CB I型低通滤波器的幅度响应
特点:通带是等波动的,阻带是单调的
scipy.signal.cheby1(N, rp, Wn, btype='low', analog=False, output='ba')
Chebyshev I型数字和模拟滤波器,设计N阶数字或模拟Chebyshev I型滤波器并返回滤波器系数。
参数:
返回
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()
CB II型低通滤波器的频域特性
∣ H ( j w ) ∣ 2 = 1 − 1 1 + ε 2 C N 2 ( w w c ) |H(jw)|^2=1-\frac{1}{1+\varepsilon ^2C_N^2(\frac{w}{w_c})} ∣H(jw)∣2=1−1+ε2CN2(wcw)1
N:滤波器的阶数
ε \varepsilon ε:阻带波纹
ω c \omega _c ωc:阻带截频
图 CB II型低通滤波器的幅度响应
特点:通带是单调的,阻带是等波动的
scipy.signal.cheby2(N, rs, Wn, btype='low', analog=False, output='ba')
Chebyshev II型数字和模拟滤波器,设计N阶数字或模拟Chebyshev II型滤波器并返回滤波器系数。
参数:
返回
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阶数字或模拟椭圆滤波器并返回滤波器系数。
参数:
返回
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()
利用重新采样的方法对语音进行下采样
scipy.signal.resample(x, num, t=None, axis=0, window=None)
沿给定轴使用傅立叶方法重新采样x到num个样本。因为使用傅立叶方法,所以假设信号是周期性的。
参数:
返回:
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()
凌振华老师的下采样方法和上面的一样
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想下采样,再不恢复频率的情况下上采样。
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()
[1] 北京交通大学(数字信号处理)陈后金教授
[2] 信号处理(scipy.signal)
[3] scipy.signal.butter
[4] scipy.signal.freqs
[4] scipy.signal.freqz
[5] scipy.signal.cheby1
[6] scipy.signal.ellip
[7] scipy.signal.decimate
[8] scipy.signal.resample