FIRフィルタを作って周波数特性を検証
適応フィルタを作ってみる では、サンプルコードを紹介しましたが、実際に動かしてみたいと思います。そこで適応フィルタの前に、まずはシンプルに固定フィルタを検証してみます。
FIRフィルタ
適応フィルタを作ってみる
で使用したFIR【Finite Impulse Response】のサンプルコードを、まずは固定フィルタで検証してみます。
サンプルコード
サンプルコード【C言語】
#define FIR_TAP 15 // 目的に合わせて調整する (今回は15で試してみます)
// clip static short double_saturate(double in) { if (in > 32767.0) in = 32767.0; if (in < -32768.0) in = -32768.0; return (short)in; } // FIR short fir_sample(float* coef, short *mem, short in) { int i; double sum = 0.; short *buff = &mem[FIR_TAP - 1]; for (i = 0; i < (FIR_TAP - 1); i++) { mem[i] = mem[i + 1]; } mem[i] = in; // convolution for (i = 0; i < FIR_TAP; i++) { sum += coef[i] * (double)*buff--; } return double_saturate(sum); }
検証用のコード
FIRの動作を確認するための環境を用意します。
サンプルコード
サンプルコード【C言語】
ファイル入出力で動かしてみます。
#include <stdio.h> #include <stdlib.h> #include <string.h> short fir_sample(float* coef, short *mem, short in); // サンプルコードのプロトタイプ宣言 extern float g_filter_coef[FIR_TAP]; //フィルタ係数 short mem[FIR_TAP]; //フィルタメモリ int main(int argc, char **argv) { FILE *fp_in; FILE *fp_out; if((fp_in = fopen(argv[1],"rb"))==NULL){ // PCM入力ファイル printf("can not open %s\n", argv[1]); exit(EXIT_FAILURE); } if((fp_out = fopen(argv[2],"wb"))==NULL){ // PCM出力ファイル printf("can not open %s\n", argv[2]); exit(EXIT_FAILURE); } for (int i = 0; i < FIR_TAP; i++) mem[i] = 0; // フィルタメモリ初期化 while(1) { short in, out; if (!fread(&in, sizeof(short), 1, fp_in))break; // PCM入力(16bitモノラル) out = fir_sample(g_filter_coef, mem, in); // FIRサンプルコード fwrite(&out, sizeof(short), 1, fp_out); // PCM出力(16bitモノラル) } fclose(fp_in); fclose(fp_out); return EXIT_SUCCESS; }
フィルタスルーで動作確認
上記の検証用コードで、フィルタ係数をg_filter_coef[FIR_TAP]としました。この係数によってフィルタ特性が決まります。 ADF【Adaptive Filter】では、これを適応アルゴリズムで自動で求め更新して行くわけですが、 固定フィルタなので、フィルタを設計してこの係数を求めます。
まずは、簡単にフィルタをスルーにして基本的な動作を確認してみます。例えば、フィルタ係数の5番目を1.0、それ以外を0.0にします。
float g_filter_coef[FIR_TAP] = { 0., 0., 0., 0., 1.0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0. };
Audacityで正弦波を作ってフィルタに入力
検証用の入力音源の作成にはAudacityを使用しました。 Audactiyについてはこちらを Audacityを使ってみました - Smile Engineering Blog
Audacityで正弦波の生成
【ジェネレーター】➞【トーン】
Audacityで正弦波を作ってフィルタに入力してみます。周波数は適当に1000(Hz)です。
Audacityで周波数分析
トーン | 設定 | 説明 |
---|---|---|
波形: | サイン波 | 波形の種類 |
周波数(Hz): | 1000 | とりあえず1kHz |
振幅(0-1): | 0.8 | 0~1.0の値 |
カーソルを波形の上に置き、Ctrl+スクロールで波形が拡大されます。
AudacityでPCMファイルの保存
【ファイル】➞【Export】➞【オーディオの書き出し】
生成した正弦波をファイル保存します。
「ファイルの種類」は、【その他の非圧縮ファイル】として、今回はファイル名をsin_1kHz.pcmとしました。
フォーマットオプションは、「ヘッダ」を【RAW (header-less)】、「エンコーディング」を【Signed 16-bit PCM】です(リニアPCMでwavヘッダ無しで使用したいため)。
この時のサンプリング周波数を覚えておいて下さい。読み込む時も同じ周波数です。
今回は48kHz(モノラル)にしています。
Audacityを使ってみました
実行方法
ビルドした実行プログラムが、"fir_test.exe"の場合の起動方法は次です。
> fir_test.exe sin_1kHz.pcm out.pcm
AudacityでPCMファイルの読み込み
【ファイル】➞【 取り込み】➞【 ロー (Raw) データの取り込み】
出力されたout.pcmを、Audacityで読み込んで波形表示してみます。PCMファイルの読み込みは保存した時と同じファイル形式で、
サンプリング周波数も保存した時と同じ周波数です。
フィルタ出力(out.pcm)の波形は、入力(原音: sin_1kHz.pcm)に対し5サンプル遅れた波形になります。いわゆるインパルス応答が、遅延5サンプルというイメージです。係数の1.0を0.5にすれば半分の振幅になります(-6dB)。
ローパスフィルタを検証
とは言っても、フィルタ設計は簡単には行かないので、 こちら を参考にします。 フィルタの種類はローパスフィルタ(Low Pass Filter: LPF)にして、フィルタ長:N(タップ)は15にしました。今度はこのフィルタ係数をg_filter_coef[FIR_TAP] として使用します。ローパスフィルタはサンプリング変換で使う機会が多いです。
// フィルタ長 : N = 15 // フィルタの種類 : LPF // 窓の種類 : Hamming // 正規化遮断周波数 : 0.2 float g_filter_coef[15] = { 2.138261220088319e-03, 6.334857723412623e-03, - 3.947985652659257e-18, - 3.312179298358531e-02, - 4.006136998985733e-02, 7.734675062134251e-02, 2.889400004322881e-01, 4.000000000000000e-01, 2.889400004322881e-01, 7.734675062134251e-02, - 4.006136998985733e-02, - 3.312179298358531e-02, - 3.947985652659257e-18, 6.334857723412623e-03, 2.138261220088319e-03 };
Audacityでホワイトノイズを生成してフィルタ特性を調べる
【ジェネレータ】➞【ノイズ】(デジタル信号処理とは、Audacityでフィルタを使ってみる)
フィルタの周波数特性を見るには、ホワイトノイズ(White noise)という全ての周波数成分が同じ強度で含まれる雑音を使用すると良く分かります。
ノイズ | 設定 | 備考 |
---|---|---|
ノイズの種類: | ホワイト | 乱数によって生成できます |
振幅(0-1): | 0.5 | 0.0~1.0を指定、信号の振幅です |
Audacityでスペクトラム表示
【解析】➞【 スペクトラム表示】(リニア周波数軸)(Audacityで周波数分析)
Audacityのスペクトラム表示で周波数特性を見ると、全ての周波数成分があることが分かります。
実行方法
Audacityで生成したホワイトノイズを正弦波と同様の手順でファイル保存し、このホワイトノイズをFIR(ローパスフィルタ)に入力してみます。次はホワイトノイズのファイル名をwnoise.pcmとした例です。
> fir_test.exe wnoise.pcm out.pcm
ローパスフィルタの結果(out.pcm)も、Audacityで読み込んでスペクトラム表示で波形を見ます。高域が減衰される周波数特性が分かります。