Unlike the filters seen before, Butter is not a windowed filter. It has both a and b constants. It is very popular and has very good frequency response as follows
import os, sys
nb_dir = os.path.split(os.getcwd())[0]
if nb_dir not in sys.path:
sys.path.append(nb_dir)
%matplotlib inline
%load_ext autoreload
%autoreload 2
The autoreload extension is already loaded. To reload it, use: %reload_ext autoreload
from directdemod import filters, constants
import matplotlib.pyplot as plt
import numpy as np
from scipy import signal
Fs = 2048000
bh = filters.butter(Fs, 20000, typeFlt = constants.FLT_LP)
plt.plot(bh.getB)
w, h = signal.freqz(bh.getB, bh.getA)
w *= Fs/(2*np.pi)
plt.clf()
fig = plt.figure()
plt.title('Digital filter frequency response')
ax1 = fig.add_subplot(111)
plt.plot(w, 20 * np.log10(abs(h)), 'b')
plt.ylabel('Amplitude [dB]', color='b')
plt.xlabel('Frequency [Hz]')
ax2 = ax1.twinx()
angles = np.unwrap(np.angle(h))
plt.plot(w, angles, 'g')
plt.ylabel('Angle (radians)', color='g')
plt.grid()
plt.axis('tight')
plt.show()
hDB = 20 * np.log10(abs(h))
print("3dB point:", w[hDB < (hDB[0]-3)][0], "Hz")
<matplotlib.figure.Figure at 0x233231bf9e8>
3dB point: 20000.0 Hz
Fs = 2048000
bh = filters.butter(Fs, 200000, typeFlt = constants.FLT_HP)
plt.plot(bh.getB)
w, h = signal.freqz(bh.getB, bh.getA)
w *= Fs/(2*np.pi)
plt.clf()
fig = plt.figure()
plt.title('Digital filter frequency response')
ax1 = fig.add_subplot(111)
plt.plot(w, 20 * np.log10(abs(h)), 'b')
plt.ylabel('Amplitude [dB]', color='b')
plt.xlabel('Frequency [Hz]')
ax2 = ax1.twinx()
angles = np.unwrap(np.angle(h))
plt.plot(w, angles, 'g')
plt.ylabel('Angle (radians)', color='g')
plt.grid()
plt.axis('tight')
plt.show()
<matplotlib.figure.Figure at 0x23322f9f2e8>
Fs = 2048000
bh = filters.butter(Fs, 50000, 100000, typeFlt = constants.FLT_BP)
plt.plot(bh.getB)
w, h = signal.freqz(bh.getB, bh.getA)
w *= Fs/(2*np.pi)
plt.clf()
fig = plt.figure()
plt.title('Digital filter frequency response')
ax1 = fig.add_subplot(111)
plt.plot(w, 20 * np.log10(abs(h)), 'b')
plt.ylabel('Amplitude [dB]', color='b')
plt.xlabel('Frequency [Hz]')
ax2 = ax1.twinx()
angles = np.unwrap(np.angle(h))
plt.plot(w, angles, 'g')
plt.ylabel('Angle (radians)', color='g')
plt.grid()
plt.axis('tight')
plt.show()
<matplotlib.figure.Figure at 0x23323037c50>
Fs = 2048000
bh = filters.butter(Fs, 50000, 100000, typeFlt = constants.FLT_BS)
plt.plot(bh.getB)
w, h = signal.freqz(bh.getB, bh.getA)
w *= Fs/(2*np.pi)
plt.clf()
fig = plt.figure()
plt.title('Digital filter frequency response')
ax1 = fig.add_subplot(111)
plt.plot(w, 20 * np.log10(abs(h)), 'b')
plt.ylabel('Amplitude [dB]', color='b')
plt.xlabel('Frequency [Hz]')
ax2 = ax1.twinx()
angles = np.unwrap(np.angle(h))
plt.plot(w, angles, 'g')
plt.ylabel('Angle (radians)', color='g')
plt.grid()
plt.axis('tight')
plt.show()
<matplotlib.figure.Figure at 0x233232e7160>
The butter filter is very accurate and has constant gain for pass bands