手習ひデジタル信号処理(64) Scilab、FIRフィルタの係数求めてフィルタしてみるの回

Joseph Halfmoon

前回は差分方程式をループで回すという「原始的」な方法で1次のIIRフィルタの時間応答を計算してみました。今回はScilabのネイティブ機能を使って、100次のFIRフィルタの応答を「1撃」で計算してみたいと思います。100次のフィルタの係数の計算もScilabに「お任せ」。中身はよくわからないけれど楽ちん。いいのか?

※「手習ひデジタル信号処理」投稿順 Indexはこちら

参照させていただいているScilabの日本語版HELPページ

以下のページに「FIRローパスフィルタの係数」を求めるための関数 ffilt についての説明があります。

ffilt

ローパスフィルタとタイトルにありますが、ローパス、ハイパス、バンドパス、バンドストップ、皆計算できる関数です。今回はローパスのみ使用してみました。

以下のページではデジタルフィルタの係数を入力信号ベクトル(時系列信号)に適用し出力信号ベクトルを計算してくれる filter 関数が説明されてます。

filter

与える係数は「直接型 II 転置」配置であるようです。「直接型 II 転置」配置は「一番よくつかわれている」のではないかと勝手に想像しています。知らんけど。まあ信号処理プロの人がいろいろ書いてくれてそうです。

filter関数の方は「直接型 II 転置」配置であれば、FIRでもIIRでも適用可能だと思います。

FIRフィルタ関数に一枚かぶせる

上記の係数算出用関数は 正規化された周波数に対して動作するみたいです。正規化周波数のままでは年寄にはイメージが湧かないというとぼけた理由で、このところサンプリング周波数Fsを与える関数を自前作成しています。ffiltにも一枚かぶせてみました(割り算ひとつだけれども。)

作製した関数が以下に。

// Calculate FIR Lowpass Filter
// Fs: sampling frequency [Hz]
// nFlt: number of filter order
// Fc: cutoff frequency [Hz]
function coeff=genFIRLP(Fs, nFlt, Fc)
    Fcnorm = Fc / Fs;
    coeff = ffilt("lp", nFlt, Fcnorm);
endfunction
実際にフィルタを作成する準備

上記の関数に加えて、過去回で作成した、サンプル波形の作成関数、Fsに対応したFFTのプロット関数などをロードしておきます。以下は、それらスクリプトがHOMEディレクトリ配下のscilabに格納されている場合の例であります。

exec('scilab\genSin.sce');
exec('scilab\genImpluse.sce');
exec('scilab\plotFFT.sce');
exec('scilab\genFIRLP.sce');
FIRローパス・フィルタの作成

今回はサンプリング周波数10kHz、ローパスフィルタの遮断周波数500Hz、FIRフィルタ次数100ということで生成してみました。

Fs=10000;
coeff = genFIRLP(Fs, 100, 500);

前回まで1次のフィルタだったのに100次とは一気だな。ま、計算しているのはScilab様だし。

正弦波波形をフィルタしてみる

正弦波2つ、周波数333Hz(遮断周波数より低い)と777Hz(遮断周波数より高い)を重ねた信号を入力信号xとして、これに上記で生成したフィルタをかけて出力信号yを生成してみます。出力信号x, y をFFTにかけて観察すれば、フィルタが働いているか否かが一目瞭然と。

[t, x333] = genSin(Fs, 4096, 333, 0, 1);
[t, x777] = genSin(Fs, 4096, 777, 0, 1);
x = x333 + x777;
[y, zf] = filter(coeff, [1], x);
plotFFT(Fs, x, 1);
xtitle("Input Signal 333Hz + 777Hz, FFT");
plotFFT(Fs, y, 1);
xtitle("Output Signal 333Hz + 777Hz, FFT");

入力 x にFFTかけたものが以下に(プロットはナイキスト周波数5kHzまでなので該当するあたりを手動で拡大してます。)333Hzと777Hzあたりに元気にピークがでております。InputSignalFFT

出力 y にFFTかけたものが以下に(プロットはナイキスト周波数5kHzまでなので該当するあたりを手動で拡大してます。)あわれ777Hzは風前の灯状態、一方333Hzは元気。あたりまえか。OutputSignalFFT

作製したフィルタのインパルス応答(周波数応答)

上記の正弦波波形で雰囲気は分かった(ホントか?)ので、今度はインパルス波形(といってもピークの値1)を作成したフィルタにかけてFFTしてみました。これで周波数応答が求まるハズ。

[ti, xi] = genImpulse(Fs, 4096, 2047, 1);
[yi, zfi] = filter(coeff, [1], xi);
plotFFT(Fs, yi, 1);
xtitle("Impluse response, FFT");

単位インパルス応答の結果が以下に。500Hzでスッパリと切れてるみたいっす。でも縦軸dBじゃない、リニアだあ。またもや後の祭り。ImpluseResponse

ローパスしているみたいっす。

手習ひデジタル信号処理(63) Scilab、差分方程式を直接計算、一次IIRフィルタ へ戻る

手習ひデジタル信号処理(65) Scilab、FIRフィルタの係数求めるついでに周波数特性 へ進む