pythonで信号にフィルタをかける

音や電気信号などの測定データなどのデータセットに対して、解析や機械学習の前処理としてフィルタをかけたくなることはよくあると思います。
その時に、他のデータとの時間同期をとるためなどの理由で位相遅れのないフィルタが欲しい、というのもまたよくあると思います。
今回はpythonでゼロ位相フィルタを用いて位相遅れなしでフィルタを実装します。
信号に対して、順方向と逆方向からフィルタをかけることで位相遅れを相殺しています。

音源はESC-50というデータセットからお借りしました。
データセットのリポジトリはこちら➡https://github.com/karolpiczak/ESC-50
siren(サイレン)のタグがついたファイルを借りました➡1-76831-A-42.wav

scipy.signal.filtfiltを用いたフィルタ

フィルタにはローパス(低い周波数を通す)、ハイパス(高い周波数を通す)、バンドパス(区間の周波数を通す)、バンドストップ(区間の周波数を止める)がありますが、実装上はあまり変わりません。
まずローパスフィルタのプログラムを示します。
関数には、(信号、サンプリング周波数、カットオフ周波数、フィルタの次数)を渡します。

from scipy import signal
def lpf(wave, fs, fe , n):
    nyq = fs / 2.0
    b, a = signal.butter(1, fe/nyq, btype='low')
    for i in range(0, n):
        wave = signal.filtfilt(b, a, wave)
    return wave

音声ファイルを読み込み、3000Hz以下を通す5次のローパスフィルタをかけるプログラムを書いてみます。

if __name__ == "__main__":
    wave, fs = wav_read(path_to_wavefile)
    t = np.arange(len(wave))/fs
    wave_f = lpf(wave, fs, 3000, 5)け

結果は下のグラフです。

よく分からないので、結果をSTFTしてプロットしてみます。(参考:pythonで時間周波数解析~STFT~)

高周波の成分がカットされているのが分かると思います。

簡単に位相遅れなしでフィルタをかけることができました。

このゼロ位相フィルタは便利なだけではないので原理を見てみるといいと思います。

ハイパスフィルタ、バンドパスフィルタ、バンドストップフィルタ

他のフィルタの処理も先ほど書いたローパスフィルタと基本的には同じです。

def lpf(wave, fs, fe , n):
    nyq = fs / 2.0
    b, a = signal.butter(1, fe/nyq, btype='high')
    for i in range(0, n):
        wave = signal.filtfilt(b, a, wave)
    return wave
def bpf(wave, fs, fe1, fe2, n):
    nyq = fs / 2.0
    b, a = signal.butter(1, [fe1/nyq, fe2/nyq], btype='band')
    for i in range(0, n):
        wave = signal.filtfilt(b, a, wave)
    return wave
def bsf(wave, fs, fe1, fe2 , n):
    nyq = fs / 2.0
    b, a = signal.butter(1, [fe1/nyq, fe2/nyq], btype='bandstop')
    for i in range(0, n):
        wave = signal.filtfilt(b, a, wave)
    return wave
フィルタの種類について

今回はバタワースフィルタ(signal.butter)を用いました。

https://docs.scipy.org/doc/scipy/reference/signal.htmlを見ればわかりますが、scipy.signalにはバタワースフィルタ以外にもベッセルフィルタ(signal.bessel)やチェビシェフフィルタ(signal.cheby1)が用意されています。

使いたい処理に合わせて使い分けるといいと思います。

コメント

タイトルとURLをコピーしました