巴特沃斯滤波器和陷波滤波器的Python实现(基于Scipy)

巴特沃斯滤波器和陷波滤波器在信号处理中很常见,很多论文中也会有所涉及,前者可以滤除高频段、低频段信号或者通过一定频率的信号,后者可用于滤除特定频率的信号,本人并非通信专业,在信号的理论知识方面比较匮乏,因此本文主要围绕代码实现展开。

本人在查找资料的过程中,发现很多博客对函数的介绍都是一笔带过,很少展开说明,因此本文会比较详细说明各个函数的使用方法还有最终结果的实现效果,就当做是做个记录。

数据生成

为了后续演示,我生成了一个三个三角函数叠加的图像作为后面的滤波输入信号

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()

三角函数sin和cos的频率计算公式为w/(2*pi),所以三个函数的频率分别是2.4、9、12。

原始图像的图像如下

巴特沃斯滤波器(Butterworth Filter)

首先是巴特沃斯滤波器,实现的库是signal.butter,库中可以实现的功能有高通、低通、带通和带阻,其中低通比较常用,一般用于提取信号信息,也是该库的默认滤波方式,高通用于锐化信号,带通通过指定频率内的频率,带阻阻止一段频率内的信号通过,有点像是陷波滤波方式。

实现butterworth的函数如下:

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

其中:

N表示阶数;

Wn表示的是标准化频率,计算公式为2*截止频率/采样频率;

btype的参数可以是{‘lowpass’, ‘highpass’, ‘bandpass’, ‘bandstop’},分别是低通、高通、带通、带阻,默认是低通,如果是带通的范围是一个二元列表,因为是一个范围,分别是上限和下限频率;analog为False表示返回数字信号,否则是模拟信号(这个我也不太懂)。

下面是代码,实现的是低通滤波:

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()

运行图像,观察第一张图片即频率响应图,可以看到在截止频率3.6处信号的放大倍数是0.7左右,在频率为8之后就几乎为0了;看第二张图也就是滤波频率信号展示,可以看到信号变为了接近一条三角函数,这个就是频率为2.4的那一条曲线,因为高频段的信号(f=9&f=12)已经被滤掉了。

 同时画出频率为2.4的和滤波后的图像,发现几乎完全重合。

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

本部分完整代码

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()

 陷波滤波器(Norch Filter)

陷波滤波器主要用于滤除特定频率的信号,比如50Hz的信号是交流电信号,很多时候就会被滤掉。

要实现该滤波器,也是要计算两个参数a和b,函数如下:

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

其中:

w0表示标准化频率,计算方式和上面的巴特沃斯一致;

Q表示质量因数,越大似乎是滤波范围越窄。

下面是代码的实现,原始的图像还是跟上面的巴特沃斯一致,我直接写在一起了。

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()

 我设定的滤波频率为f=9,可以看到频率响应图中的9处已经为0,看第二个图,滤波后的图像应该还有两个三角函数。 

画出两个三角函数叠加和滤波后的图的对比,发现几乎完全重合,说明频率为9的图像被滤掉了。

本部分完整代码

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()

就先到这里了,有机会再加一些其他的

  • 7
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
巴特沃斯低通滤波器是一种常用的信号处理方法,可以用于去除信号中的高频噪声。在Python中,可以使用scipy库中的butter函数来设计和实现巴特沃斯低通滤波器。以下是一个示例代码: ```python import numpy as np from scipy.signal import butter, filtfilt # 设计低通滤波器 def butter_lowpass(cutoff, fs, order=5): nyq = 0.5 * fs normal_cutoff = cutoff / nyq b, a = butter(order, normal_cutoff, btype='low', analog=False) return b, a # 应用滤波器 def butter_lowpass_filter(data, cutoff, fs, order=5): b, a = butter_lowpass(cutoff, fs, order=order) y = filtfilt(b, a, data) return y # 示例数据 data = np.random.randn(1000) # 设计并应用低通滤波器 cutoff = 100 # 截止频率 fs = 1000 # 采样率 order = 6 # 阶数 filtered_data = butter_lowpass_filter(data, cutoff, fs, order) # 绘制原始数据和滤波后的数据 import matplotlib.pyplot as plt t = np.arange(len(data)) / fs plt.plot(t, data, 'r-', label='raw data') plt.plot(t, filtered_data, 'b-', linewidth=2, label='filtered data') plt.legend() plt.xlabel('Time (seconds)') plt.ylabel('Amplitude') plt.show() ``` 在上面的示例代码中,我们先定义了两个函数:butter_lowpass和butter_lowpass_filter。其中,butter_lowpass用于根据指定的截止频率、采样率和阶数,设计出一个巴特沃斯低通滤波器;而butter_lowpass_filter则是用于将输入数据应用到这个滤波器上,得到滤波后的输出数据。最后,我们使用随机生成的数据并绘制了原始数据和滤波后的数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值