我想 在 每个 连续 1024个样本的 块/时间帧上 应用FIR或IIR滤波器(例如:低通滤波器)。
可能的应用:
实时 音频处理,例如EQing。在一个精确的时间,缓冲区中只有接下来的1024个样本。下一个要处理的样本尚不可用(实时)。
如答案所示,通过将输入信号分成多个块来制作一个时变截止滤波器。
我在这里尝试过:
import numpy as np from scipy.io import wavfile from scipy.signal import butter, lfilter, filtfilt, firwin sr, x = wavfile.read('input.wav') x = np.float32(x) y = np.zeros_like(x) N = 1024 # buffer block size = 23ms for a 44.1 Khz audio file f = 1000 # cutoff pos = 0 # position while True: b, a = butter(2, 2.0 * f / sr, btype='low') y[pos:pos+N] = filtfilt(b, a, x[pos:pos+N]) pos += N f -= 1 # cutoff decreases of 1 hz every 23 ms, but the issue described here also present with constant cutoff! print f if pos+N > len(x): break y /= max(y) # normalize wavfile.write('out_fir.wav', sr, y)
我试过了:
既可以使用Butterworth滤波器也可以使用FIR(用替换之前的行b, a = firwin(1000, cutoff=f, fs=sr), 1.0)
b, a = firwin(1000, cutoff=f, fs=sr), 1.0
都与lfilter和filtfilt(后者向前和向后应用过滤器的优势,这能解决问题阶段),
lfilter
filtfilt
但这是问题所在:
**在每个时间帧输出的边界处,存在连续性问题,这会使音频信号严重失真。
如何解决这个不连续性问题? 我考虑过windowing + OverlapAdd方法,但是肯定有一种更简单的方法。
正如@sobek在评论中提到的那样,当然需要指定初始条件以允许连续性。这是通过的zi参数完成的lfilter。
zi
通过更改主循环可以解决此问题:
while True: b, a = butter(2, 2.0 * f / sr, btype='low') if pos == 0: zi = lfilter_zi(b, a) y[pos:pos+N], zi = lfilter(b, a, x[pos:pos+N], zi=zi) pos += N f -= 1 if pos+N > len(x): break
即使每次迭代都修改了过滤器的截止时间(并因此修改了a和b),这似乎仍然有效。
a
b