Butterworth フィルターとノッチ フィルターの Python 実装 (Scipy に基づく)

バターワース フィルターとノッチ フィルターは信号処理で非常に一般的であり、多くの論文で取り上げられます。前者は高周波信号、低周波信号、または特定の周波数を通過する信号をフィルターで除去でき、後者は特定の信号をフィルターで除去するために使用できます。周波数信号については、私は通信を専攻しておらず、信号に関する理論的な知識が比較的不足しているため、この記事では主にコードの実装に焦点を当てます。

情報を探していると、多くのブログでは機能を簡単に紹介するだけで、説明がほとんどされていないことが多かったので、この記事では、各機能の使用方法と最終的な結果の実現効果について詳しく説明します。記録。

データ生成

フォローアップのデモンストレーションとして、後でフィルタリングされた入力信号として 3 つの三角関数を重ね合わせた画像を生成しました。

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) なので、3 つの関数の周波数はそれぞれ 2.4、9、12 となります。

元画像のイメージは以下の通り

バターワースフィルター

1 つ目はバターワース フィルターです。実装されるライブラリは signal.butter です。ライブラリで実装できる関数は、ハイパス、ローパス、バンドパス、バンドストップです。このうち、ローパスがより一般的です。信号情報を抽出するために使用され、一般に使用されます。これはライブラリでもあります。デフォルトのフィルタリング方法では、ハイパスは信号を鮮明にするために使用され、バンドパスは指定された周波数内の周波数を通過させ、バンドストップは信号がその範囲内に収まることを防ぎます。特定の周波数の通過を防ぎます。これはノッチ フィルター方法に似ています。

Butterworthを実装する関数は次のとおりです。

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

の:

N は順序を表します。

Wnは正規化周波数を表し、計算式は2*カットオフ周波数/サンプリング周波数です。

btypeのパラメータには、{'lowpass'、'highpass'、'bandpass'、'bandstop'} を指定できます。それぞれ、ローパス、ハイパス、バンドパス、バンドストップです。デフォルトはローパスです。バンドパスの場合、範囲はバイナリです。メタ リストは、範囲であるため、上限と下限の周波数です。アナログは 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 番目の画像は、フィルタリングされた周波数信号です。示されているように、信号が三角関数に近づくことがわかります。これは、高周波数帯域 (f=9&f=12) の信号であるため、周波数 2.4 の曲線です。フィルタリングされて除外されました。

 同時に周波数 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()

 ノッチフィルター

ノッチフィルターは主に特定の周波数の信号を除去するために使用され、例えば 50Hz の信号は交流信号であるため、多くの場合除去されます。

フィルターを実装するには、2 つのパラメーター a と b を計算することも必要です。関数は次のとおりです。

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

の:

w0 は標準化周波数を表し、計算方法は上記の Butterworth の計算方法と同じです。

Q は品質係数を表し、それが大きいほどフィルタリング範囲が狭くなるように見えます。

以下はコードの実装ですが、元のイメージは上記の Butterworth と一致しており、直接一緒に書きました。

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 であることがわかります。2 番目のグラフを見ると、フィルタリングされた画像には 2 つの三角関数があるはずです。 

2 つの三角関数を重ね合わせてフィルター処理した画像を比較すると、それらはほぼ完全に重なっていることがわかり、周波数 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()

とりあえずはここまでです、機会があればまた追加します

おすすめ

転載: blog.csdn.net/weixin_60360239/article/details/131827400