具有时变截止频率的低通滤波器,使用Python

时间:2018-09-19 10:18:59

标签: python numpy scipy signal-processing

如何应用低通滤波器,其截止频率线性变化(或比线性变化更普遍)。 10000hz到200hz随时间变化,有numpy / scipy,可能没有其他库吗?

示例:

  • 在00:00,000,低通截止= 10000hz
  • 在00:05,000时,低通截止频率= 5000hz
  • 00:09,000,低通截止频率= 1000hz
  • 然后截止频率在10秒内保持在1000hz,然后截止频率降低到200hz

这里是执行简单的100hz低通的方法:

from scipy.io import wavfile
import numpy as np
from scipy.signal import butter, lfilter

sr, x = wavfile.read('test.wav')
b, a = butter(2, 100.0 / sr, btype='low')  # Butterworth
y = lfilter(b, a, x)
wavfile.write('out.wav', sr, np.asarray(y, dtype=np.int16))

但是如何使临界值变化?

注意:我已经读过Applying time-variant filter in Python,但答案非常复杂(通常适用于多种过滤器)。

2 个答案:

答案 0 :(得分:4)

一种比较简单的方法是使滤波器保持固定并改为调制信号时间。例如,如果信号时间快10倍,则10KHz低通将像标准时间中的1KHz低通一样。

为此,我们需要解决一个简单的ODE

dy       1
--  =  ----
dt     f(y)

t是实时调制时间yf是时间y的期望截止时间。

原型实现:

from __future__ import division
import numpy as np
from scipy import integrate, interpolate
from scipy.signal import butter, lfilter, spectrogram

slack_l, slack = 0.1, 1
cutoff = 50
L = 25

from scipy.io import wavfile
sr, x = wavfile.read('capriccio.wav')
x = x[:(L + slack) * sr, 0]
x = x

# sr = 44100
# x = np.random.normal(size=((L + slack) * sr,))

b, a = butter(2, 2 * cutoff / sr, btype='low')  # Butterworth

# cutoff function
def f(t):
    return (10000 - 1000 * np.clip(t, 0, 9) - 1000 * np.clip(t-19, 0, 0.8)) \
        / cutoff

# and its reciprocal
def fr(_, t):
    return cutoff / (10000 - 1000 * t.clip(0, 9) - 1000 * (t-19).clip(0, 0.8))

# modulate time
# calculate upper end of td first
tdmax = integrate.quad(f, 0, L + slack_l, points=[9, 19, 19.8])[0]
span = (0, tdmax)
t = np.arange(x.size) / sr
tdinfo = integrate.solve_ivp(fr, span, np.zeros((1,)),
                             t_eval=np.arange(0, span[-1], 1 / sr),
                             vectorized=True)
td = tdinfo.y.ravel()
# modulate signal
xd = interpolate.interp1d(t, x)(td)
# and linearly filter
yd = lfilter(b, a, xd)
# modulate signal back to linear time
y = interpolate.interp1d(td, yd)(t[:-sr*slack])

# check
import pylab
xa, ya, z = spectrogram(y, sr)
pylab.pcolor(ya, xa, z, vmax=2**8, cmap='nipy_spectral')
pylab.savefig('tst.png')

wavfile.write('capriccio_vandalized.wav', sr, y.astype(np.int16))

示例输出:

Spectrogram of first 25 seconds of BWV 826 Capriccio filtered with a time varying lowpass implemented via time bending.

BWV 826 Capriccio的前25秒频谱图,通过时弯实现时变低通滤波。

答案 1 :(得分:3)

您可以使用scipy.fftpack.fftfreq和scipy.fftpack.rfft设置阈值

fft = scipy.fftpack.fft(sound)
freqs = scipy.fftpack.fftfreq(sound.size, time_step)

对于time_step,我对声音的采样率提高了两倍

fft[(freqs < 200)] = 0

这会将所有将小于200 Hz的所有频率设置为零

对于时变截止,我将声音拆分并应用滤镜。假设声音的采样率为44100,则5000hz滤波器将从采样220500(五秒钟)开始

10ksound = sound[:220500]
10kfreq = scipy.fftpack.fftreq(10ksound.size, time_step)
10kfft = scipy.fftpack.fft(10ksound)
10kfft[(10kfreqs < 10000)] = 0

然后使用下一个过滤器:

5ksound = sound[220500:396900]
5kfreq = scipy.fftpack.fftreq(10ksound.size, time_step)
5kfft = scipy.fftpack.fft(10ksound)
5kfft[(5kfreqs < 5000)] = 0

编辑:要使其“滑动”或逐渐过滤而不是逐段过滤,您可以使“块”更小,并将越来越大的频率阈值应用于相应的块(5000-> 5001-> 5002)