I'm designing a bandpass filter in scipy following the cookbook. However, if I decrecrease the filtering frequencies too much I end up with garbage at high order filters. What am I doing wrong?
from scipy.signal import butter, lfilter
def butter_bandpass(lowcut, highcut, fs, order=5):
nyq = 0.5 * fs
low = lowcut / nyq
high = highcut / nyq
b, a = butter(order, [low, high], btype='band')
return b, a
if __name__ == "__main__":
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import freqz
# Sample rate and desired cutoff frequencies (in Hz).
fs = 25
# Plot the frequency response for a few different orders.
plt.figure(1)
plt.clf()
for order in [1, 3, 5, 6, 9]:
b, a = butter_bandpass(0.5, 4, fs, order=order)
w, h = freqz(b, a, worN=2000)#np.logspace(-4, 3, 2000))
plt.semilogx((fs * 0.5 / np.pi) * w, abs(h), label="order = %d" % order)
plt.xlabel('Frequency (Hz)')
plt.ylabel('Gain')
plt.grid(True)
plt.legend(loc='best')
plt.figure(2)
plt.clf()
for order in [1, 3, 5, 6, 9]:
b, a = butter_bandpass(0.05, 0.4, fs, order=order)
w, h = freqz(b, a, worN=2000)#np.logspace(-4, 3, 2000))
plt.semilogx((fs * 0.5 / np.pi) * w, abs(h), label="order = %d" % order)
plt.xlabel('Frequency (Hz)')
plt.ylabel('Gain')
plt.grid(True)
plt.legend(loc='best')
plt.show()
Update: the issue was discussed and apparently solved on Scipy 0.14. However, the plot still looks really bad after Scipy update. What's wrong?
The frequency response of the Butterworth filter is maximally flat (i.e. has no ripples) in the passband and rolls off towards zero in the stopband. When viewed on a logarithmic Bode plot, the response slopes off linearly towards negative infinity.
The Butterworth and Chebyshev Type II filters have flat passbands and wide transition bands. The Chebyshev Type I and elliptic filters roll off faster but have passband ripple. The frequency input to the Chebyshev Type II design function sets the beginning of the stopband rather than the end of the passband.
To generate the filter coefficients for a bandpass filter, give butter() the filter order, the cutoff frequencies Wn=[lowcut, highcut] , the sampling rate fs (expressed in the same units as the cutoff frequencies) and the band type btype="band" .
Third-order Butterworth Low Pass Filter and finally our circuit of the third-order low pass Butterworth Filter with a cut-off corner frequency of 284 rads/s or 45.2Hz, a maximum pass band gain of 0.5dB and a minimum stop band gain of 20dB is constructed as follows.
b, a = butter
for high-order filters, whether in Matlab or SciPy or Octave. Transfer function format has numerical stability problems, because some of the coefficients are very large while others are very small. This is why we changed the filter design functions to use zpk format internally. To see the benefits of this, you need to use z, p, k = butter(output='zpk')
and then work with poles and zeros instead of numerator and denominator.sos = butter(output='sos')
and then filter using sosfilt()
or sosfiltfilt()
. This is the recommended way to filter for most applications.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With