第12章

ディジタルフィルタの基礎

この章のねらい

  • 周波数選択フィルタの発想と LPF/HPF/BPF の分類を知る
  • FIRフィルタが「インパルス応答とのたたみこみ」であることを理解する
  • 差分方程式・IIRフィルタの仕組みと、FIRとの利害得失を説明できるようになる

12.1 周波数選択フィルタと線形時不変システム

やる夫

聞いてくれお。やる夫の声をマイクで録音したら、後ろで「サーッ」っていう細かいノイズがずっと鳴ってるんだお。録り直すのは面倒だから、ノイズだけ消したいんだお。

やらない夫

ちょうどいい題材だ。その「サーッ」は高い周波数に散らばる成分で、声の主成分はもっと低い周波数にいる。つまりお前の要求はこう言い換えられる。

信号の中の、いらない周波数成分だけを削りたい。

これをやる装置がフィルタだ。コーヒーのフィルタが粉を止めて液だけ通すように、特定の周波数を止めて残りを通す。

やる夫

言いたいことはわかるけど、波形は時間の関数だお? 録音データのどこを見ても「ここが高周波です」なんて書いてないお。どうやって周波数を狙い撃ちするんだお。

やらない夫

そこで第8章の主役を呼び戻す。線形時不変(LTI)システムに信号を通すと、周波数領域では

Y(ω)=H(ω)X(ω)(12.1)Y(\omega) = H(\omega) X(\omega) \tag{12.1}

という掛け算になるんだった。H(ω)H(\omega) は周波数応答。つまり LTI システムは、もともと「周波数成分ごとに別々の倍率を掛ける装置」なんだ。

やる夫

あ! ってことは、消したい周波数のところだけ H(ω)=0H(\omega) = 0 になるようなシステムを作ればいいのかお! 残したいところは H(ω)=1H(\omega) = 1 で素通しにして!

やらない夫

それがフィルタ設計の発想のすべてだ。あとは HH の形で名前が付いている。

  • 低域通過フィルタ(LPF): 低い周波数を通し、高い周波数を止める
  • 高域通過フィルタ(HPF): 高い周波数を通し、低い周波数を止める
  • 帯域通過フィルタ(BPF): ある帯域だけを通す
  • 帯域阻止フィルタ(BEF): ある帯域だけを止める

お前のノイズ退治なら LPF だな。理想を言えば、遮断周波数 ωc\omega_c までは利得1、そこから先は利得0、つまり

H(ω)={1(ωωc)0(ω>ωc)(12.2)H(\omega) = \begin{cases} 1 & (|\omega| \le \omega_c) \\ 0 & (|\omega| > \omega_c) \end{cases} \tag{12.2}

という矩形の周波数応答が欲しい。これを理想低域通過フィルタと呼ぶ。

やる夫

矩形…。なんか嫌な予感がするお。第3章で「時間領域の矩形パルス⇔周波数領域のsinc」っていうペアを見たお。周波数領域で矩形ってことは…

やらない夫

鋭くなってきたな。その予感は当たっていて、理想LPFのインパルス応答は sinc 関数になり、時間方向に無限に伸びる。しかも入力が来るから応答が始まる非因果的な代物だから、そのままでは実現できない。「理想にどう近づけるか」がフィルタ設計の本題で、それは後の章でやる。この章では、そもそもディジタルフィルタという機械がどう動くのか、その骨組みを押さえる。

12.2 インパルス応答のたたみこみによるディジタルフィルタ

やらない夫

ディジタルの世界での LTI システムを思い出そう。離散時間の LTI システムの出力は、入力 x[n]x[n] とインパルス応答 h[n]h[n]たたみこみだった。h[n]h[n] が有限の長さ MM で終わるなら、こう書ける。

y[n]=k=0M1h[k]x[nk](12.3)y[n] = \sum_{k=0}^{M-1} h[k]\, x[n-k] \tag{12.3}

この形のフィルタを FIR フィルタ(Finite Impulse Response、有限インパルス応答)と呼ぶ。

やる夫

式だけ見ると仰々しいけど、やってることは「いま来た値 x[n]x[n] と、過去 M1M-1 個の値に、それぞれ決まった重み h[k]h[k] を掛けて全部足す」だお? 加重平均みたいなもんだお。

やらない夫

そのとおり。重み係数の列 h[0],h[1],,h[M1]h[0], h[1], \dots, h[M-1]タップ係数と呼ぶ。そしてここが美しいところなんだが、この係数列の正体は何だと思う? 試しに式 (12.3) にインパルス x[n]=δ[n]x[n] = \delta[n] を入れてみろ。

やる夫

えーと、δ[nk]\delta[n-k]n=kn = k のときだけ1だから…総和の中で生き残るのは k=nk = n の項だけで…出力は y[n]=h[n]y[n] = h[n] だお。…あれ? 係数の列そのものが出てくるお。

やらない夫

そう。タップ係数 = インパルス応答そのものだ。「フィルタを設計する」とは「望みの H(ω)H(\omega) を持つインパルス応答 h[k]h[k] を決める」ことに他ならない。

いちばん身近な例が移動平均だ。直近 MM 点をただ平均する。

y[n]=1Mk=0M1x[nk](12.4)y[n] = \frac{1}{M} \sum_{k=0}^{M-1} x[n-k] \tag{12.4}

これは h[k]=1/Mh[k] = 1/Mk=0,,M1k = 0, \dots, M-1)の FIR フィルタだ。

やる夫

移動平均は株価のチャートで見たことあるお。ギザギザの値動きに、滑らかな線が重ねて描いてあるやつだお。

やらない夫

その「滑らかになる」を周波数の言葉で言えば、速い変動=高周波成分が削られている、つまり移動平均は LPF だ。平均を取れば細かい上下動は相殺されるが、ゆっくりした傾向は平均しても残る。直観とも合うだろ。

じゃあ係数を自分の手で動かして、h[k]h[k]H(ejω)|H(e^{j\omega})| の関係を体感してみろ。下のデモは5タップの FIR フィルタだ。初期状態は全タップ 0.2、つまり5点移動平均になっている。

FIR TAPS — PLAYGROUND INTERACTIVE
スライダーで係数 h[0]〜h[4] を動かすと、下段の振幅応答 |H| が連動する。全部同符号にすると左が高い低域通過、+と−を交互にすると右が高い高域通過になる=係数の「波打ち方」がそのフィルタの好きな周波数を決めると体感できる。
やる夫

おお、ほんとに初期状態だと左が高くて右が下がる LPF だお! …ちょっと遊んでみるお。係数を +0.5,0.5,+0.5,0.5,+0.5+0.5, -0.5, +0.5, -0.5, +0.5 みたいに交互にしたら…今度は右上がりになったお! 高い周波数だけ通す HPF だお!

やらない夫

いい発見だ。理屈はこうだ。係数が全部同符号なら、ゆっくり変化する入力(低周波)は同じ符号のまま足し合わされて生き残る。逆に交互符号の係数は「隣との差」を取る動きになるから、1サンプルごとに符号が反転するような最速の振動(ω=π\omega = \pi 付近)に強く反応する。係数の並びの「波打ち方」が、そのフィルタの好きな周波数を決めるんだ。

理屈はいいとして、最初の目的を忘れるな。ノイズ混じりの信号に移動平均を実際にかけてみよう。

MOVING AVERAGE — DENOISE INTERACTIVE
タップ数 M を増やすと出力(緑)が滑らかになる一方、信号本体の山も低くなり波形が右に遅れていく=ノイズ除去は常に「信号の歪み・遅延」との取引だと分かる。下段の |H| で通過帯域が狭まる様子も同時に見える。
やる夫

M = 5 でだいぶツルツルになったお! もっと増やせば最強だお…と思ったら、M = 15 だと肝心の波まで痩せて、しかも右にずれてるお。

やらない夫

それが副作用だ。デモ下段の H|H| を見ろ。MM を増やすと高域はよく削れるが、通過帯域も狭くなって信号本体の成分まで削り始める。さらに「直近 MM 点の平均」は時間的に過去寄りの代表値だから、出力はおよそ (M1)/2(M-1)/2 サンプル遅れる。フィルタは常に「ノイズの除去量」と「信号の歪み・遅延」の取引なんだ。

12.3 線形差分方程式によるディジタルフィルタ

やる夫

ところで、FIRの「過去 MM 点に重みを掛けて足す」って、急峻なフィルタを作ろうとしたらタップが何百本も要りそうだお。1サンプルごとに何百回も掛け算するのは大変だお。

やらない夫

いい問題意識だ。そこで第二の方式が出てくる。出力の計算に、過去の出力そのものを再利用するんだ。一般形はこうなる。

y[n]=k=0Mbkx[nk]k=1Naky[nk](12.5)y[n] = \sum_{k=0}^{M} b_k\, x[n-k] - \sum_{k=1}^{N} a_k\, y[n-k] \tag{12.5}

これを線形差分方程式と呼ぶ。第1項は FIR と同じ「入力の加重和」。新顔は第2項、過去の出力 y[n1],,y[nN]y[n-1], \dots, y[n-N] のフィードバックだ。

第2項の頭に付いているマイナスが唐突に見えるかもしれないが、これはわざとだ。本来は「y[n]y[n] と過去の出力をまとめた左辺=入力の加重和」という形 k=0Naky[nk]=kbkx[nk]\sum_{k=0}^{N} a_k y[n-k] = \sum_k b_k x[n-k]a0=1a_0=1)で、それを y[n]y[n] について解こうと過去の出力項を右辺へ移項したから符号が反転している。この符号で書いておくと、第14章で z変換したときに分母が 1+a1z1+a2z2+1 + a_1 z^{-1} + a_2 z^{-2} + \cdots という綺麗な形で出てくる(係数 aka_k がそのまま分母に並ぶ)。いまは「あとで分母が整うための仕込み」とだけ思っておけ。

やる夫

出力を入力側に戻すのかお!? 自分の出した答えをまた材料に使うって、なんか出力がぐるぐる回って雪だるま式に増えそうで怖いお。

やらない夫

その「ぐるぐる回る」感覚は正しいし、「雪だるま式」の心配もあとで効いてくる。まず一番簡単な例で挙動を見よう。

y[n]=x[n]+0.9y[n1](12.6)y[n] = x[n] + 0.9\, y[n-1] \tag{12.6}

インパルス x[n]=δ[n]x[n] = \delta[n] を入れる。初期状態は y[1]=0y[-1] = 0 だ。順に手で計算してみろ。

やる夫

えーと。y[0]=1+0.9×0=1y[0] = 1 + 0.9 \times 0 = 1y[1]=0+0.9×1=0.9y[1] = 0 + 0.9 \times 1 = 0.9y[2]=0+0.9×0.9=0.81y[2] = 0 + 0.9 \times 0.9 = 0.81y[3]=0.729y[3] = 0.729…。あ、これ入力はとっくに 0 なのに、出力がいつまでも止まらないお。

やらない夫

そう、インパルス応答は h[n]=0.9nh[n] = 0.9^nn0n \ge 0)で、無限に続く。だからこの方式を IIR フィルタ(Infinite Impulse Response、無限インパルス応答)と呼ぶ。一度入った刺激の「残響」がフィードバックループの中を回り続けるイメージだ。

注目すべきは効率だ。式 (12.6) の計算は1サンプルあたり掛け算1回・足し算1回。それで無限に長いインパルス応答が手に入る。同じ応答を FIR で真似ようとしたら、タップが何十本も必要になる。

やる夫

たった2項でそれかお。じゃあもう全部 IIR でいいんじゃないかお?

やらない夫

そうは行かない。さっきお前が言った「雪だるま」を思い出せ。式 (12.6) の係数 0.9 を 1.1 に変えたらどうなる?

やる夫

h[n]=1.1nh[n] = 1.1^n で…1, 1.1, 1.21, 1.331…って、どんどん増えて爆発するお! 入力はインパルス1発だったのに!

やらない夫

それが不安定という状態だ。フィードバックがあるシステムは、係数の選び方を誤ると有限の入力から無限の出力を生む。FIR にはこの心配が原理的にない。式 (12.3) は有限個の有限な値の和だから、FIR は常に安定だ。両者の利害得失を整理するとこうなる。

FIR フィルタ

  • 常に安定(フィードバックがないので爆発しようがない)
  • 係数を左右対称にすれば線形位相(全周波数が同じ時間だけ遅れる、波形が歪まない)にできる
  • そのかわり急峻な特性には高い次数(多くのタップ)が必要で、計算量とメモリを食う

IIR フィルタ

  • 低い次数で急峻な特性が作れて計算が軽い
  • そのかわり安定性の確認が必須。係数誤差にも敏感
  • 位相特性は一般に歪む(線形位相にはできない)
やる夫

なるほどだお。安全で素直だけど大所帯の FIR、少数精鋭だけど暴走リスク持ちの IIR…。ところで「係数の選び方を誤ると爆発する」って言うけど、0.9 はセーフで 1.1 はアウトっていう境界線は、どこかにちゃんと書いてあるのかお? 毎回手で計算して爆発を確かめるのは嫌だお。

やらない夫

それが次の2つの章のテーマそのものだ。安定か不安定かは、システムを複素平面の上で眺めると一目でわかるようになる。連続時間システム用の地図がラプラス変換(第13章)、ディジタルフィルタ用の地図が z変換(第14章)だ。0.9 と 1.1 の運命を分けた境界線は、z平面では半径1の円として目に見える形で現れる。

この章のまとめ
  • フィルタとは「周波数成分ごとの倍率 H(ω)H(\omega)」を設計して掛ける LTI システムのこと。通す帯域によって LPF/HPF/BPF/BEF に分類される
  • FIR フィルタ y[n]=k=0M1h[k]x[nk]y[n] = \sum_{k=0}^{M-1} h[k] x[n-k] は入力とインパルス応答のたたみこみ。タップ係数=インパルス応答そのもの
  • 移動平均は最も簡単な LPF。タップ数 MM を増やすとよく滑らかになるが、信号本体も削れて遅延も増える
  • 差分方程式 y[n]=bkx[nk]aky[nk]y[n] = \sum b_k x[n-k] - \sum a_k y[n-k] は出力をフィードバックする。インパルス応答が無限に続くので IIR フィルタと呼ぶ
  • FIR は常に安定で線形位相にできるが次数が高くなりがち。IIR は低次で急峻だが不安定になりうる
  • 安定・不安定の境界線を見るための道具が、次章からのラプラス変換と z変換