Python implementation of Butterworth filter and notch filter (based on Scipy)

Butterworth filters and notch filters are very common in signal processing, and will be involved in many papers. The former can filter out high-frequency, low-frequency signals or signals passing a certain frequency, and the latter can be used to filter out specific For frequency signals, I am not a communication major, and I am relatively lacking in theoretical knowledge of signals, so this article mainly focuses on code implementation.

In the process of searching for information, I found that many blogs have only briefly introduced functions, and rarely explained them. Therefore, this article will explain in detail the usage methods of each function and the realization effect of the final result, just as a record.

data generation

For the follow-up demonstration, I generated an image with three trigonometric functions superimposed as the filtered input signal later

plt.rcParams['font.sans-serif'] = ['SimHei']  # 显示中文
plt.rcParams['axes.unicode_minus'] = False
fs = 300.0  # 采样频率
T = 5.0  # 周期5s
n = int(T * fs)  # 总样本数
t = np.linspace(0, T, n, endpoint=False)
y_1 = np.sin(2.4 * 2 * np.pi * t)  
y_2 = np.sin(9 * 2 * np.pi * t) 
y_3 = np.sin(12 * 2 * np.pi * t) 
data = y_1 + y_2 + y_3  # 生成一个三个函数叠加的图像
plt.plot(t, data)
plt.title('原始图像')
plt.show()

The frequency calculation formulas of the trigonometric functions sin and cos are w/(2*pi), so the frequencies of the three functions are 2.4, 9, and 12, respectively.

The image of the original image is as follows

Butterworth Filter

The first is the Butterworth filter. The library implemented is signal.butter. The functions that can be implemented in the library are high-pass, low-pass, band-pass and band-stop . Among them, low-pass is more commonly used and is generally used to extract signal information. It is also the library. The default filtering method, the high pass is used to sharpen the signal, the band pass passes the frequency within the specified frequency, and the band stop prevents the signal within a certain frequency from passing through, which is a bit like the notch filter method.

The function that implements butterworth is as follows:

b, a = butter(N=order, Wn=normal_f, btype='lowpass', analog=False)

in:

N represents the order;

Wn represents the normalized frequency, and the calculation formula is 2*cut-off frequency/sampling frequency;

The parameter of btype can be {'lowpass', 'highpass', 'bandpass', 'bandstop'}, which are low-pass, high-pass, band-pass, and band-stop respectively. The default is low-pass. If it is band-pass, the range is a binary The meta list , because it is a range, is the upper limit and lower limit frequency; analog is False, which means returning a digital signal, otherwise it is an analog signal (I don't know much about this).

The following is the code, which implements low-pass filtering:

def butter_filter(data, fs, cutoff, order=5):
    normal_f = 2*np.array(cutoff)/fs
    b, a = butter(N=order, Wn=normal_f, btype='lowpass', analog=False)
    # 根据阶数n和归一化截止频率Wn计算ButterWorth滤波器分子分母系数(b为分子系数的矢量形式,a为分母系数的矢量形式)
    return np.array(filtfilt(b, a, data)),b,a  

# 滤波参数并绘制频率响应图
cutoff = 3.667  # 设定截止频率,频率为截止频率时信号是输入信号的0.707倍
order = 5 # 设定滤波器阶数,阶数越高那么越能够有效地抑制不需要的频率成分
y,b,a = butter_lowpass_filter(data, fs, cutoff, order)  # 小数据集
w, h = freqz(b, a, worN=800)  # 计算滤波器的频率响应(Response),也就是对不同频段的放大倍数,0.707倍的是截止频率
plt.subplot(2, 1, 1)
plt.plot(0.5 * fs * w / np.pi, np.abs(h), 'b')
plt.plot(cutoff, 0.5 * np.sqrt(2), 'ko')
plt.axvline(cutoff, color='k')
plt.xlim(0, 10)
plt.title("频率响应图")
plt.xlabel('频率')
plt.grid()  # 画线
plt.subplot(2, 1, 2)
plt.plot(t, data, 'b-', label='滤波前')
plt.plot(t, y, 'g-', linewidth=2, label='滤波后')
plt.xlabel('时间')
plt.grid()
plt.legend()
plt.subplots_adjust(hspace=0.35)
plt.show()

Run the image and observe the first picture, which is the frequency response diagram . You can see that the magnification factor of the signal at the cutoff frequency of 3.6 is about 0.7, and it is almost 0 after the frequency is 8; look at the second picture, which is the filtered frequency signal Shown , it can be seen that the signal becomes close to a trigonometric function, this is the curve with a frequency of 2.4, because the signal in the high frequency band (f=9&f=12) has been filtered out.

 At the same time, the image with a frequency of 2.4 and the filtered image are drawn, and it is found that they overlap almost completely.

plt.plot(t,y,'b-', label='滤波后图像')
plt.plot(t,y_1,'y',label='f=2.4图像')
plt.legend()
plt.xlabel('频率')
plt.title('函数对比')
plt.show()

Complete code for this part

import numpy as np
from matplotlib import pyplot as plt
from scipy import signal
from scipy.signal import lfilter, butter, filtfilt, freqz


def butter_filter(data, fs, cutoff, order=5):
    normal_f = 2*np.array(cutoff)/fs
    b, a = butter(N=order, Wn=normal_f, btype='lowpass', analog=False)
    # 根据阶数n和归一化截止频率Wn计算ButterWorth滤波器分子分母系数(b为分子系数的矢量形式,a为分母系数的矢量形式)
    return np.array(filtfilt(b, a, data)),b,a  


if __name__ == '__main__':
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 显示中文
    plt.rcParams['axes.unicode_minus'] = False
    fs = 300.0  # 采样频率
    T = 5.0  # 周期5s
    n = int(T * fs)  # 总样本数
    t = np.linspace(0, T, n, endpoint=False)
    y_1 = np.sin(2.4 * 2 * np.pi * t) 
    y_2 = np.sin(9 * 2 * np.pi * t)  
    y_3 = np.sin(12 * 2 * np.pi * t)  
    data = y_1 + y_2 + y_3  # 生成一个三个函数叠加的图像
    plt.plot(t, data)
    plt.title('原始图像')
    plt.show()

    # 滤波参数并绘制频率响应图
    cutoff = 3.667  # 设定截止频率,频率为截止频率时信号是输入信号的0.707倍
    order = 5 # 设定滤波器阶数,阶数越高那么越能够有效地抑制不需要的频率成分
    y,b,a = butter_filter(data, fs, cutoff, order)  # 小数据集
    w, h = freqz(b, a, worN=800)  # 计算滤波器的频率响应(Response),也就是对不同频段的放大倍数,0.707倍的是截止频率
    plt.subplot(2, 1, 1)
    plt.plot(0.5 * fs * w / np.pi, np.abs(h), 'b')
    plt.plot(cutoff, 0.5 * np.sqrt(2), 'ko')
    plt.axvline(cutoff, color='k')
    plt.xlim(0, 10)
    plt.title("频率响应图")
    plt.xlabel('频率')
    plt.grid()  # 画线
    plt.subplot(2, 1, 2)
    plt.plot(t, data, 'b-', label='滤波前')
    plt.plot(t, y, 'g-', linewidth=2, label='滤波后')
    plt.xlabel('时间')
    plt.grid()
    plt.legend()
    plt.subplots_adjust(hspace=0.35)
    plt.show()
    
    # 绘制对比图像 
    plt.plot(t,y,'b-', label='滤波后图像')
    plt.plot(t,y_1,'y',label='f=2.4图像')
    plt.legend()
    plt.xlabel('频率')
    plt.title('函数对比')
    plt.show()

 Notch Filter

The notch filter is mainly used to filter out signals of a specific frequency. For example, a 50Hz signal is an AC signal, and it will be filtered out in many cases.

To implement the filter, it is also necessary to calculate two parameters a and b, the function is as follows:

b,a = signal.iirnotch(w0, Q)

in:

w0 represents the standardized frequency, and the calculation method is the same as that of Butterworth above;

Q represents the quality factor, and the larger it seems, the narrower the filtering range is.

The following is the implementation of the code. The original image is still consistent with the Butterworth above, and I wrote it together directly.

def notch_filter(data,fs,Q,f_remove):
    w0 = 2*f_remove / fs
    b, a = signal.iirnotch(w0, Q)
    return np.array(filtfilt(b, a, data)),b,a

# 滤波参数并绘制频率响应图
f_remove = 9  # 设定截止频率,频率为截止频率时信号是输入信号的0.707倍
Q = 300 # Q表示质量因数,越大滤波的范围越窄(目标频率周围的)
y,b,a = notch_filter(data, fs, Q,f_remove)  # 小数据集
w, h = freqz(b, a, worN=800)  # 计算滤波器的频率响应(Response),也就是对不同频段的放大倍数,0.707倍的是截止频率
plt.subplot(2, 1, 1)
plt.plot(0.5 * fs * w / np.pi, np.abs(h), 'b')
plt.plot(f_remove, 0.5 * np.sqrt(2), 'ko')
plt.axvline(f_remove, color='k')
plt.xlim(0, 10)
plt.title("频率响应图")
plt.xlabel('频率')
plt.grid()  # 画线
plt.subplot(2, 1, 2)
plt.plot(t, data, 'b-', label='滤波前')
plt.plot(t, y, 'g-', linewidth=2, label='滤波后')
plt.xlabel('时间')
plt.grid()
plt.legend()
plt.subplots_adjust(hspace=0.35)
plt.show()

plt.plot(t,y,'b-', label='滤波后图像')
plt.plot(t,y_1+y_3,'y',label='f=2.4图像')
plt.legend()
plt.xlabel('频率')
plt.title('函数对比')
plt.show()

 I set the filtering frequency as f=9, and you can see that 9 points in the frequency response graph are already 0. Looking at the second graph, there should be two trigonometric functions in the filtered image. 

Draw a comparison of the superimposed and filtered images of the two trigonometric functions, and it is found that they overlap almost completely, indicating that the image with a frequency of 9 has been filtered out.

Complete code for this part

import numpy as np
from matplotlib import pyplot as plt
from scipy import signal
from scipy.signal import lfilter, butter, filtfilt, freqz


def notch_filter(data,fs,Q,f_remove):
    w0 = 2*f_remove / fs
    b, a = signal.iirnotch(w0, Q)
    return np.array(filtfilt(b, a, data)),b,a

if __name__ == '__main__':
    plt.rcParams['font.sans-serif'] = ['SimHei']  # 显示中文
    plt.rcParams['axes.unicode_minus'] = False
    fs = 300.0  # 采样频率
    T = 5.0  # 周期5s
    n = int(T * fs)  # 总样本数
    t = np.linspace(0, T, n, endpoint=False)
    y_1 = np.sin(2.4 * 2 * np.pi * t)
    y_2 = np.sin(9 * 2 * np.pi * t)
    y_3 = np.sin(12 * 2 * np.pi * t)
    data = y_1 + y_2 + y_3  # 生成一个三个函数叠加的图像
    plt.plot(t, data)
    plt.title('原始图像')
    plt.show()

    # 滤波参数并绘制频率响应图
    f_remove = 9  # 设定截止频率,频率为截止频率时信号是输入信号的0.707倍
    Q = 30 # Q表示质量因数,越大滤波的范围越窄(目标频率周围的)
    y,b,a = notch_filter(data, fs, Q,f_remove)  # 小数据集
    w, h = freqz(b, a, worN=800)  # 计算滤波器的频率响应(Response),也就是对不同频段的放大倍数,0.707倍的是截止频率
    plt.subplot(2, 1, 1)
    plt.plot(0.5 * fs * w / np.pi, np.abs(h), 'b')
    plt.plot(f_remove, 0.5 * np.sqrt(2), 'ko')
    plt.axvline(f_remove, color='k')
    plt.xlim(0, 10)
    plt.title("频率响应图")
    plt.xlabel('频率')
    plt.grid()  # 画线
    plt.subplot(2, 1, 2)
    plt.plot(t, data, 'b-', label='滤波前')
    plt.plot(t, y, 'g-', linewidth=2, label='滤波后')
    plt.xlabel('时间')
    plt.grid()
    plt.legend()
    plt.subplots_adjust(hspace=0.35)
    plt.show()

    plt.plot(t,y,'b-', label='滤波后图像')
    plt.plot(t,y_1+y_3,'y',label='f=2.4+f=12图像')
    plt.legend()
    plt.xlabel('频率')
    plt.title('函数对比')
    plt.show()

That's it for now, I'll add some more when I have a chance

Guess you like

Origin blog.csdn.net/weixin_60360239/article/details/131827400