0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

理想のローパスフィルタと現実のフィルタ

Last updated at Posted at 2024-10-06

はじめに

対象読者

デジタルフィルタについてなんとなくわかっているけどどう設計したら良いかわからない人

書いてる人

オーディオマニアです。
エンジニアではありません。
デジタル信号処理を学んだこもありません。
書いてる内容はすべてネット上の情報の受け売りです。

参考サイト

https://jp.mathworks.com/help/signal/ug/practical-introduction-to-digital-filter-design.html

環境

Linux(Ubuntu 24.04) 上の GNU Octave 8.4.0 で計算

参考サイトは MATLAB なのでサンプルプログラム(Signal Processing Toolbox)はOctaveでは動きません

CDの再生を想定して fs 88200Hz、 フィルタのカットオフ22050Hz で計算
波形を表示するときは必要に応じてアップサンプリングしてます

お願い

素人がデジタルフィルタを解説するという無謀な記事です。
説明が雑なのは許してください。
間違っていたら指摘をお願いします。
ただし私の能力が足りないため、指摘されても記事が適切に修正できるかわかりません。

理想のローパスフィルタ

皆さんご存知、sinc関数です。

sin(x)/x, sinc(0) = 1

Octave や Python の sinc関数は正規化sinc関数です。 sin(πx)/πx

非正規化sinc関数として扱いたいならxの代わりに x/π を使います。

sinc関数の波形
fig01.png

前後に無限に続きます。

理想ローパスフィルタの周波数特性

振幅特性(横:周波数 Linear、縦:dB)
fig02.png

理想というだけあって以下の特徴があります。

  • 直線位相
  • 通過帯域は完全にフラット(0dB)
  • 阻止帯域はgin 0(-∞dB)
  • 遷移帯域は無い
  • 実現するためには前後に無限の長さの時間が必要

前後に無限の長さが必要なので実現不可能です。

現実のフィルタ

単純にぶった切る(矩形窓)

前後に無限に続いた信号を単純に切り詰めてみます。

波形: 青が長さ511、赤が16倍の8191です。
fig03.png

fig04.png

青は端のところで打ち切られています。赤も端で同様に打ち切られてます。

理想ローパスフィルタを有限に打ち切ったときの特性

青が長さ511、赤が8191です。

fig05.png

肩部分の拡大

fig06.png

  • 通過帯域がフラットではない(リップルがある)
  • 阻止帯域が−∞ではない
  • 遷移帯域がある

フィルタを長くすると改善しますが、長くするにも限界があります。
sinc関数はxに反比例するので長さを16倍にしても端の大きさは1/16にしかなりません。

窓関数

有限に打ち切るときにそのままだと端の部分でいきなりゼロになります。
この急激な変化により特性が悪化します。
このため端の部分で滑らかにゼロに近づくように窓関数をかけます。

窓関数の波形

青:Hamming、赤:Kaiser(β=8)、マゼンタ:Kaiser(β=20)

fig07.png

端の部分の波形
青:窓関数なし、赤:Kaiser(β=8)
fig08.png

窓関数を使用したときの周波数特性

青:長さ511窓関数なし、赤:長さ8191窓関数なし、マゼンタ:長さ511窓関数Kaiser(β=8)
fig09fig09.png

阻止帯域の減衰量は長さ8191で打ち切ったものよりも長さ1/16で窓関数を使ったもののほうが遥かに良いです。

肩部分を拡大します。
fig10fig10.png

Kaiser窓を使ったものはリプルがなくフラットです。

fig11fig11.png

Kaiser窓を使用したものは肩がなだらかで遷移帯域は広くなります。

窓関数を変えたときの周波数特性

長さは511
青:Hamming、赤:Kaiser(β=8)、マゼンタ:Kaiser(β=20)
fig12fig12.png

fig13fig13.png

Kaiser(β=20)が一番阻止帯域の減衰量が大きいのですが、肩はなだらかで遷移帯域が一番広くなっています。
フィルタの肩特性と阻止帯域の減衰量は相反します。
両方改善しようとするとフィルタ長を長くする必要があります。

同じ窓関数で長さを変える

窓関数はKaiser(β=8)
青:長さ511、赤:長さ1023、マゼンタ:長さ8191
fig14fig14.png

fig15fig15.png

長くすると阻止帯域の減衰量も改善し、遷移帯域も狭くなります。

カットオフ周波数を変えてみる

長さ511、窓関数Kaiser(β=8)
青:22050Hz、赤:22000Hz、マゼンタ:21950Hz
fig16
fig16.png

ちゃんと50Hzずつずれています。
ちなみにカットオフ周波数でのゲインは0.5、約-6dBとなります。

雑に作ってみる

MATLABなんかでは必要な特性を入力すれば最小の長さのフィルタを自動で作ってくれます。
今回は手動で適当にパラメータを決めていきます。

  • サンプリング周波数 88200Hz
  • カットオフ周波数 20940Hz
  • 長さ511
  • 窓関数:Kaiser(β=20)

作ったフィルタの特性
fig17fig17.png

阻止帯域は22050Hz で約-190dB、通過帯域は-0.5dBが20552Hz(22050の93%)、カットオフ(-6dB)が20940Hz(22050Hzの94.7%)と充分な特性です。

このフィルタを作るOctaveのコードを載せておきます。
Octaveのsignalパッケージにはfir1関数があってローパスフィルタを簡単に作れますが、学習目的なのでこの関数は使ってません。

pkg load signal; # signal パッケージをロード
fs = 88200; # サンプリング周波数
fc = 20940; # カットオフ周波数
x = -1/fs*255:1/fs:1/fs*255; # 長さ511 (255*2+1)
low = sinc(x*fc*2)*fc/fs*2; # 正規化sinc関数
low = low .* kaiser(length(low), 20)'; # 窓関数
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?