周波数選択フィルタの紹介

  • by

こんにちは!
今回のブログは第1R&Dセンターのリサーチャーの塩本が担当します。
今回は周波数選択フィルタについて紹介したいと思います。

今回のブログの内容

  • 周波数選択フィルタがどういうものか簡単に紹介します。
  • 周波数選択フィルタを用いることで音からノイズを除去したり,ノイズのみを抽出してみました。

はじめに

突然ですが,次のサンプル音1をよく注意して聴いてみてください.

サンプル音1

この音を聴いてみると「ピー」という音の後ろで、小さいですが「サー」という音が聞こえると思います。次にこの音をスペクトログラムで可視化します。
スペクトログラムは時系列データの周波数分布の時間変化をあらわしているものになります。ここでは詳細な説明はしませんが、興味のある方は以下のサイトを参照してください。

先程のサンプル音1をスペクトログラムにした図が図1になります。

図1:サンプル音1のスペクトログラム

上記のスペクトログラムは色が黄色いほど周波数成分が強いことを示しており、反対に青くなるほど周波数成分が弱いことを示しています。
図1を見ると、5000Hz、10000Hz、15000Hzに黄色い線が見えますね?これが「ピー」音の正体です。また、それとは別に2500Hz以下の部分に黄緑色の帯が見えると思います。こちらが「サー」という音の正体になります。
ここから周波数選択フィルタを用いてこの「ピー」音と「サー」音を分けてみたいと思います。

周波数選択フィルタ

周波数選択フィルタの説明

周波数選択フィルタを適用する前に、詳しい内容について説明します。周波数選択フィルタを用いると、データの周波数分布から選択した周波数よりも高い周波数帯または低い周波数帯のみを切り出すことが出来ます。選択された周波数を遮断周波数と呼びます。
また,周波数選択フィルタには周波数特性というものが存在します。周波数特性は遮断周波数の付近でどのような挙動を示すかということを表します。理想的な周波数特性は、図2のように遮断周波数でしっかりわかれているものになります。
さらにどのくらいの割合を残すか示したものを利得といいます。つまりある周波数で利得が0.3である場合は、得られる音の周波数成分の大きさが0.3倍になるということです。

図2:理想的な周波数特性

周波数選択フィルタは主に以下の4つが存在します。

  • ハイパスフィルタ
  • ローパスフィルタ
  • バンドパスフィルタ
  • バンドストップフィルタ

次に、それぞれの周波数選択フィルタについて説明します。
ハイパスフィルタは図2のように遮断周波数より高い周波数帯にある音を残し、遮断周波数より低い周波数にある音を小さくしたり消去するフィルタです。

図3:ハイパスフィルタを簡単に示した図

次にローパスフィルタについて説明します。ローパスフィルタは図3のように遮断周波数より低い周波数帯にある音を残して、遮断周波数より高い周波数を小さくしたり消去するフィルタです。

図4:ローパスフィルタを簡単に表した図

今度はバンドパスフィルタについて説明します。図4のようにバンドパスフィルタは周波数を2つ選択することで、遮断周波数内の音だけを残して、それ以外の範囲の音を小さくしたり消去するフィルタです。

図5:バンドパスフィルタを簡単に表した図

最後に、バンドストップフィルタについて説明します。バンドストップフィルタはバンドパスフィルタと逆の効果があり、遮断周波数を2つ選択することで遮断周波数内の音だけを消去して、範囲外の音を残すフィルタです。バンドカットフィルタとも言われます。

図6:バンドストップフィルタを簡単に表した図

周波数選択フィルタにおける特性とデジタルフィルタ

前節で理想的な周波数特性は遮断周波数で0と1にきれいに分かれているフィルタであると説明しました.しかし、図2のような周波数特性をもつフィルタは実装不可能です.試しに,理想的な周波数特性をもつであろうフィルタを作成するために、次のようなコードでサンプル音1からノイズを消し、そのスペクトログラムを確認します。

from scipy.signal import stft, istft

def ideal_filter(data, fs, freq):
    """
    input
        data: フィルタをかける対象のデータ
        fs: サンプリング周波数
       freq: 遮断周波数
    output
        filtered_data: フィルタ適用後のデータ
    """
    f, t, spectrogram = stft(data, fs=fs)
    spectrogram[f <= freq] = 0.0 + 0.0j
    t, filtered_data = istft(data, fs=fs, nperseg=256)
    return filtered_data

遮断周波数を5000Hzにして上記のコードで作成したフィルタを適用したときの音がサンプル音2になります。

サンプル音2

サンプル音2を聴くと,サンプル音1の「ピー」音よりも違和感のある音になっていると感じる人がいると思います。また,サンプル音2のスペクトログラムは次のようになります。

図7:サンプル音1(左)とサンプル音2(右)のスペクトログラム

図7をみると、サンプル音2のスペクトログラムには7500Hz以下の周波数帯に、サンプル音1には無い横線がたくさん見えると思います。このように理想的なフィルタを実現しようとすると、元の音には存在していないノイズが加わることがあります.そのため、遮断周波数近傍でなだらかに振る舞う周波数特性をもつ以下の周波数選択フィルタが実装される場合が多いです。

  • バターワース特性
  • チェビシェフ特性
  • ベッセル特性

ここから各特性について説明します。

バターワース特性は上記の特性の中でも一般的に使われる特性です。選択周波数付近で図8のイメージのようにだんだんと変化するフィルタです。他の特性と比べて、残す周波数帯の影響が小さいのが特徴です。

図8:バターワース特性のイメージ図

次にチェビシェフ特性について説明します。チェビシェフ特性は図9のような周波数特性です。他の特性よりも利得の変化が大きいという性質をもっています。しかし、残す周波数帯にリップルと呼ばれる不必要な変化が発生します。

図9:チェビシェフ特性のイメージ図

最後のベッセル特性は図10のような周波数特性です。3つの特性の中で一番利得の変化が小さい特性となります。その代わり,波形の歪みが3つの中で一番小さいため、できるだけ波形を維持したままフィルタをかけるときには有効です。

図10:ベッセル特性のイメージ図

周波数選択フィルタをサンプル音に適用してみた

今回はバターワース特性をもつフィルタを用いてサンプル音1からノイズを除去したり、ノイズを抽出してみましょう。
まず始めに、サンプル音1からハイパスフィルタを用いてノイズを除去してみます。
pythonでバターワース特性をもつフィルタを実装する方法として1番簡単な方法である、scipyを用いた実装を今回使用します。
バターワース特性をもつハイパスフィルタをデータに適用する関数の実装例は次のとおりです。

from scipy.signal import butter, sosfilt

def apply_highpass_filter(data, fs, freq):
    """
    input
        data: フィルタをかける対象のデータ
        fs: サンプリング周波数
       freq: 遮断周波数
    output
        filtered_data: フィルタ適用後のデータ
    """
    highpass_filter = butter(N=6, Wn=(freq / (fs /2.0)), btype='high', output='sos')
    filtered_data = sosfilt(highpass_filter, data)
    return filtered_data

上記のコードについて説明します。まず関数butterで指定したパラメータからバターワース特性をもつフィルタを作成します。次に関数sosfiltで作成したフィルタをデータに適用しています.
関数butterの引数は以下のようになっています。

  • N:バターワースフィルタを計算する際に必要な値です。大きくなるほど理想的なフィルタに近づきますが、計算時間が増えます。
  • Wn:遮断周波数です。ここでは[0.0, 1.0]であり,1.0のとき(遮断周波数)=(サンプリング周波数)/ 2 の値になるように設定されるため,上記のコードのような変換が必要です。
  • btype:フィルタの種類です。ここでハイパス,ローパス,バンドパス,バンドストップか指定します.
  • output:アウトプットの形を指定します。基本的に問題がないならばsosに設定するのが無難です。

上記のコードで,遮断周波数を5000Hzにしたハイパスフィルタをサンプル音1に適用して得られた音は、次のサンプル音2になります。

サンプル音3:サンプル音1にハイパスフィルタを適用した音

サンプル音3を聴くとサンプル音1にあった「サー」という音が消えているのが確認できると思います。
また、サンプル音3のスペクトログラムは図11になります。2500Hz以下の部分が図1よりも小さくなっていることがわかりますね?

図11:サンプル音1(左)とサンプル音3(右)のスペクトログラム

次に、チェビシェフ特性をもつローパスフィルタをサンプル音1に適用することで、ノイズだけを取り出すことをやってみます。
チェビシェフ特性をもつローパスフィルタをデータに適用する関数の実装例は次のとおりです。

from scipy.signal import cheby1, sosfilt

def apply_lowpass_filter(data, fs, freq):
    """
    input
        data: フィルタをかける対象のデータ
        fs: サンプリング周波数
       freq: 遮断周波数
    output
        filtered_data: フィルタを適用したデータ
    """
    lowpass_filter = cheby1(N=6, rp=1.0, Wn=(freq / (fs /2.0)), btype='low', output='sos')
    filtered_data = sosfilt(lowpass_filter, data)
    return filtered_data

上記のコードについて説明します。まず関数cheby1で指定したパラメータからチェビシェフ特性をもつフィルタを作成します。次に関数sosfiltで作成したフィルタをデータに適用しています.
関数cheby1の引数は以下のようになっています。

  • N:チェビシェフフィルタを計算する際に必要な値です。大きくなるほど理想的なフィルタに近づきますが、計算時間が増えます。
  • rp:許容するリップルの強さを決める値です。
  • Wn:遮断周波数です。ここでは[0.0, 1.0]であり,1.0のとき(遮断周波数)=(サンプリング周波数)/ 2 の値になるように設定されるため,上記のコードのような変換が必要です。
  • btype:フィルタの種類です。ここでハイパス,ローパス,バンドパス,バンドストップか指定します.
  • output:アウトプットの形を指定します。基本的に問題がないならばsosに設定するのが無難です。

遮断周波数を3000Hzにしたローパスフィルタをサンプル音1に適用した音は次のようになります。

サンプル音4:サンプル音1にローパスフィルタを適用した音

今度は「ピー」という音が小さくなって、「サー」という音がよく聴こえていることが確認できると思います。
サンプル音4をスペクトログラムにすると、今度は図1にあった10000Hz、15000Hzの線の色が薄くなっているとともに、2500Hz以下の周波数帯の色が濃くなっていることがわかると思います。

図12:サンプル音1(左)とサンプル音3(右)のスペクトログラム

このように、ハイパスフィルタやローパスフィルタを用いることで特定の周波数の音だけを抽出することができます。
実世界の音はサンプル音のように単純な構造をしていませんが、例えば、論文「少数マイクロフォンを用いる環境雑音を考慮した音源の特徴抽出及び位置推定に関する研究」では、ハイパスフィルタを用いることで豚舎の中で豚のくしゃみに似ている音の部分だけを取り出すなど、特定の領域では周波数選択フィルタを用いることである程度ほしい区間だけを抽出できる場合もあるため、やってみると面白いと思います。

最後に

今回は簡単に周波数選択フィルタとは何かということと、周波数選択フィルタを実装する方法について説明して,実際に周波数選択フィルタをかけた音の変化を聴いてもらいました。
このブログが役に立ってもらえたら幸いです!

参考サイト・参考論文