[python] Scipy.signal.butter로 대역 통과 버터 워스 필터를 구현하는 방법

최신 정보:

이 질문에 근거한 Scipy Recipe를 찾았습니다! 따라서 관심있는 사람은 다음으로 바로 이동하십시오. 목차»신호 처리»버터 워스 대역 통과


처음에는 1D numpy 배열 (시계열)에 대해 버터 워스 대역 통과 필터를 구현하는 간단한 작업처럼 보였던 것을 달성하는 데 어려움을 겪고 있습니다.

내가 포함해야하는 매개 변수는 sample_rate, 컷오프 주파수 IN HERTZ 및 가능한 순서입니다 (감쇠, 고유 주파수 등과 같은 다른 매개 변수는 나에게 더 모호하므로 “기본값”값이면됩니다).

지금 내가 가진 것은 이것이 고역 통과 필터로 작동하는 것처럼 보이지만 제대로하고 있는지 확실하지 않습니다.

def butter_highpass(interval, sampling_rate, cutoff, order=5):
    nyq = sampling_rate * 0.5

    stopfreq = float(cutoff)
    cornerfreq = 0.4 * stopfreq  # (?)

    ws = cornerfreq/nyq
    wp = stopfreq/nyq

    # for bandpass:
    # wp = [0.2, 0.5], ws = [0.1, 0.6]

    N, wn = scipy.signal.buttord(wp, ws, 3, 16)   # (?)

    # for hardcoded order:
    # N = order

    b, a = scipy.signal.butter(N, wn, btype='high')   # should 'high' be here for bandpass?
    sf = scipy.signal.lfilter(b, a, interval)
    return sf

여기에 이미지 설명 입력

문서와 예제는 혼란스럽고 모호하지만 “for bandpass”로 표시된 칭찬에 제시된 양식을 구현하고 싶습니다. 주석의 물음표는 무슨 일이 일어나고 있는지 이해하지 못하고 몇 가지 예제를 복사하여 붙여 넣은 위치를 보여줍니다.

저는 전기 공학이나 과학자가 아니며 EMG 신호에 대해 다소 간단한 대역 통과 필터링을 수행해야하는 의료 장비 설계자 일뿐입니다.



답변

buttord의 사용을 건너 뛰고 대신 필터 주문을 선택하고 필터링 기준을 충족하는지 확인할 수 있습니다. 대역 통과 필터에 대한 필터 계수를 생성하려면 butter ()에 필터 차수, 차단 주파수 Wn=[low, high](샘플링 주파수의 절반 인 나이 퀴 스트 주파수의 일부로 표현됨) 및 대역 유형을 제공하십시오 btype="band".

다음은 Butterworth 대역 통과 필터로 작업하기위한 몇 가지 편의 함수를 정의하는 스크립트입니다. 스크립트로 실행하면 두 개의 플롯이 생성됩니다. 하나는 동일한 샘플링 속도 및 차단 주파수에 대해 여러 필터 차수의 주파수 응답을 보여줍니다. 다른 그림은 샘플 시계열에 대한 필터 (차수 = 6)의 효과를 보여줍니다.

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


def butter_bandpass_filter(data, lowcut, highcut, fs, order=5):
    b, a = butter_bandpass(lowcut, highcut, fs, order=order)
    y = lfilter(b, a, data)
    return y


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 = 5000.0
    lowcut = 500.0
    highcut = 1250.0

    # Plot the frequency response for a few different orders.
    plt.figure(1)
    plt.clf()
    for order in [3, 6, 9]:
        b, a = butter_bandpass(lowcut, highcut, fs, order=order)
        w, h = freqz(b, a, worN=2000)
        plt.plot((fs * 0.5 / np.pi) * w, abs(h), label="order = %d" % order)

    plt.plot([0, 0.5 * fs], [np.sqrt(0.5), np.sqrt(0.5)],
             '--', label='sqrt(0.5)')
    plt.xlabel('Frequency (Hz)')
    plt.ylabel('Gain')
    plt.grid(True)
    plt.legend(loc='best')

    # Filter a noisy signal.
    T = 0.05
    nsamples = T * fs
    t = np.linspace(0, T, nsamples, endpoint=False)
    a = 0.02
    f0 = 600.0
    x = 0.1 * np.sin(2 * np.pi * 1.2 * np.sqrt(t))
    x += 0.01 * np.cos(2 * np.pi * 312 * t + 0.1)
    x += a * np.cos(2 * np.pi * f0 * t + .11)
    x += 0.03 * np.cos(2 * np.pi * 2000 * t)
    plt.figure(2)
    plt.clf()
    plt.plot(t, x, label='Noisy signal')

    y = butter_bandpass_filter(x, lowcut, highcut, fs, order=6)
    plt.plot(t, y, label='Filtered signal (%g Hz)' % f0)
    plt.xlabel('time (seconds)')
    plt.hlines([-a, a], 0, T, linestyles='--')
    plt.grid(True)
    plt.axis('tight')
    plt.legend(loc='upper left')

    plt.show()

다음은이 스크립트에 의해 생성 된 플롯입니다.

여러 필터 차수에 대한 주파수 응답

여기에 이미지 설명 입력


답변

허용되는 답변 의 필터 설계 방법 은 정확하지만 결함이 있습니다. B로 디자인 SciPy 대역 통과 필터는은 불안정 하고 발생할 수 오 필터 에서 높은 필터 차수 .

대신 필터 설계의 sos (2 차 섹션) 출력을 사용하십시오.

from scipy.signal import butter, sosfilt, sosfreqz

def butter_bandpass(lowcut, highcut, fs, order=5):
        nyq = 0.5 * fs
        low = lowcut / nyq
        high = highcut / nyq
        sos = butter(order, [low, high], analog=False, btype='band', output='sos')
        return sos

def butter_bandpass_filter(data, lowcut, highcut, fs, order=5):
        sos = butter_bandpass(lowcut, highcut, fs, order=order)
        y = sosfilt(sos, data)
        return y

또한 다음을 변경하여 주파수 응답을 플롯 할 수 있습니다.

b, a = butter_bandpass(lowcut, highcut, fs, order=order)
w, h = freqz(b, a, worN=2000)

…에

sos = butter_bandpass(lowcut, highcut, fs, order=order)
w, h = sosfreqz(sos, worN=2000)


답변

대역 통과 필터의 경우 ws는 하단 및 상단 코너 주파수를 포함하는 튜플입니다. 이는 필터 응답이 통과 대역보다 3dB 낮은 디지털 주파수를 나타냅니다.

wp는 정지 대역 디지털 주파수를 포함하는 튜플입니다. 최대 감쇠가 시작되는 위치를 나타냅니다.

gpass는 통과 대역의 최대 감쇠 (dB 단위)이고 gstop은 저지 대역의 감쇠입니다.

예를 들어 코너 주파수가 300Hz와 3100Hz 인 8000 샘플 / 초의 샘플링 속도에 대한 필터를 설계하려한다고 가정 해 보겠습니다. 나이 퀴 스트 주파수는 샘플 속도를 2로 나눈 값입니다.이 예에서는 4000Hz입니다. 동등한 디지털 주파수는 1.0입니다. 그러면 두 코너 주파수는 300/4000 및 3100/4000입니다.

이제 정지 대역이 코너 주파수에서 30dB +/- 100Hz 아래로 내려 가기를 원한다고 가정 해 보겠습니다. 따라서 정지 대역은 200 및 3200Hz에서 시작하여 디지털 주파수는 200/4000 및 3200/4000이됩니다.

필터를 만들려면 buttord를 다음과 같이 호출합니다.

fs = 8000.0
fso2 = fs/2
N,wn = scipy.signal.buttord(ws=[300/fso2,3100/fso2], wp=[200/fs02,3200/fs02],
   gpass=0.0, gstop=30.0)

결과 필터의 길이는 정지 대역의 깊이와 코너 주파수와 정지 대역 주파수 간의 차이에 의해 결정되는 응답 곡선의 가파른 정도에 따라 달라집니다.


답변