投稿

1月, 2012の投稿を表示しています

IIR デジタルフィルタ Javaで自作

イメージ
少ないタップ数で実現できる IIR (Infinite impulse response 無限インパルス応答)デジタルフィルタ。LPF/HPF(ローパス/ハイパスフィルタ)でも試しに作ってみようかと思う。図書館で借りた本を頼りにプログラムまで作ることにしてみた。 これまでに作ったFIRはタップ数が多く計算量が増えてしまうのに対して、IIRは極端にタップ数が少なく1~8程度。無限のフィードバックを利用することで少ないタップを実現している。欠点は位相のズレが出てしまうことと、条件によっては不安定になりやすいことなど。AudacityのLPF/HPFはIIRのButterworthを使っているので、いろいろ試したら欠点はやはり位相だと思えた。元の波形が結構大きく変化してしまう。FIRで同じようにLPF/HPFを作ると、波形の乱れはなかった。その差は歴然。ただIIRは計算量が少ないので、ディレイやリバーブ内のLPFとして使う場合には都合がよい。 IIRは元々アナログ回路用のフィルタなので、アナログ回路設計を雛形にしてデジタルに変換するという設計が基本のようだ。IIRで作れる有名なフィルタは Butterworth、Chebyshev、楕円フィルタなどがある。実際使いそうなフィルタは平坦な特性のButterworthぐらいなので、これだけ試すことにした。基本となるブロック図は以下のようなもの。図は4次のブロック図。このan、bnに係数を入れることでフィルタになる。anはフィードバックになる。さらにカスケードするなどの改良型もある。 内容を理解しようとしたら、結構難しいかも。まずは下の式から次数ごとのバターワースのプロトタイプというものを作る。 とりあえず1次から4次までのプロトタイプは数式でこのようになった。 1次 2次 3次 4次 次に求めたい特性に応じて、どの次数のButterworthを使えばよいかを計算する。Butterworthはカットオフ周波数が-3dBになるように計算されている。単純に次数が増えれば急な傾斜を実現できる。軽く高域を削る程度なら1次でよいこともあるし、完全なカットをしたいなら4次でも不十分になる。ちなみにAudacityでは1次、2次、4次、6次、8次のButterworth HPF/LPFが用意されている。

周波数から音名とcent表示する JavaScript

周波数から音程をチェックするためのJavaScriptを書いてみた。個人的にたまにやりたくなる計算。以前は関数電卓にプログラムを書いて実行していた。でも、たまにしか使わないので、実行方法とか忘れてしまうのが、たまにきず。そこでJavaScriptの出番。この手の関数電卓規模の計算ってJavaScriptと相性いいかも。簡単に書けて実用的。 周波数を入力すると、その音がABCDEFGの音名で表示される。 Calib. A Hz Frequency Hz Interval Note Cent 簡単な説明 Calib. A は基準となる周波数。普通は440Hz。 Frequency ここに音名を知りたい周波数を入力。 calculate ボタン。これを押すと計算される。 Interval 基準周波数からの音程差を表示。半音が1となる。1オクターブは12となる。 Note 音名を表示。 Cent セントは半音を1/100にした単位。上の音名に対してプラスマイナス50セントの範囲でズレを表示。0に近ければジャストに近い。 下は参考までに、基準音440Hzのときのギターの開放弦の周波数。 1弦開放 E 329.627Hz 2弦開放 B 246.941Hz 3弦開放 G 195.997Hz 4弦開放 D 146.832Hz 5弦開放 A 110.000Hz 6弦開放 E 82.406Hz 中学生ぐらいから学ぶフーリエ変換 目次

FFT 基礎実験 Java

イメージ
FFT(Fast Fourier Transform)高速フーリエ変換も作ってみる。昨日の 音声ファイル用DFT の一部を改造してFFTを組み込む。機能ごとにクラスをきれいに分けて作ると簡単に組み込むことができることを実感。 FFTのアルゴリズムはコンピュータ処理に適した巧妙なしくみになっている。バタフライ演算で計算を減らす工夫がされている。データが多くなればなるほど、DFTとの差が出てくる。DFTだとデータ数Nとすると、N^2の乗算が必要なのに対して、FFTはN log 2 N/2で済むようだ。少ないサンプル数で乗算を数えてみたら、計算式通りではないが、まぁ近い数かな。同じ計算で符号違いも多いので、うまく最適化すれば、より高速になる。実際の実用レベルのFFTではそのように作られているようだ。とりあえず理屈どおりに組み込んで試してみると、DFTに比べて、圧倒的な処理スピードは体感できた。これなら1万サンプル以上でも苦ではない。 音声ファイルにおけるフーリエ変換の細々したことは こっちのDFTページ を見てください。とりあえず結果だけは下のようになった。 sin波1000, 5000, 10000,15000,20000Hzを合成した波形をFFTにかけてみる。出力ファイルをLibreOfficeのCalcでグラフ化。出力を確認。ピンクはdB表示でグリーンはリニア表示。 sound programming 目次はこちら

FIR The Frequency Sampling Method 実験 Java

イメージ
FIRのLPFとHPFを設計してみて、もう少し高度なことをやってみたくなった。ということで、日曜日はThe Frequency Sampling Methodにチャレンジ。特徴としてはLPFやHPFに比べ自由度の高いフィルターが作れるというところ。周波数ごとにフィルターを掛ける割合を微調整できるので、グラフィックイコライザーやパラメトリックイコライザーのようなことが実現できる。解像度を上げていけば市販品をしのぐことも夢ではない。LPF/HPFと同じようにJavaでデジタルフィルタ用の係数を出力するところまで、つまりインパルス応答を得るまで作る。 これを実現するにはフーリエ変換を勉強しないと手が出ない。以前勉強したのだが、すっかり忘れた。またちょっとメモを読み返したりして再勉強。 結論としては、IDFT(離散フーリエ逆変換)の式をプログラミングすることで、実現できそうだ。あとは、やりながら考えるのが手っ取り早い。細かな部分まで完全に理解しようとすると数年かかりそうなので、厳密さは無視して、ガンガンとプログラムを組んでみる。それにしても、この手の日本語情報は少ないなぁ。うまく見つけられないだけなのか? 結局下の英語ページを読みながら、プログラムをする。 http://cnx.org/content/m28292/latest/ h(n)がFIRのタップの係数に相当する。この(n)は無限大個数あるのが理想。でも当然無理なので、オーディオの場合は最低でも数百とかにする。LPFならもっと少なくても良いのだが、HPFを考慮するとまだ足りない。今回はサンプリング周波数44100Hzのオーディオファイルを使う。低域もきれいに加工したいので、タップ数は1万ぐらい欲しくなる。さらに直線位相特性などを考慮すると、その2倍というところだ。ということで2万程度で実験した。 H(k)は周波数域を分解したそれぞれの係数。Hには任意の0~1.0を入れる。自分が欲しい周波数特性をここでコントロールする。(k)を増やすと分解能が上がるので細かく周波数をいじることができる。今回は22050個にした。つまり扱える周波数を22050分割。サンプリング周波数44100Hzの場合、扱える周波数は22050Hzまでなので1Hz単位で制御できることになる。 式にeとかiがある。この手の専門教育

FIR LPF/HPFの係数プログラム Java版

イメージ
昨年JavaScriptで書いたものをJavaへ移植してみた。意外とフィルタ係数関係のアクセスが多いので、2012年はデジタルフィルタ関係、もしくは音響関係を少し充実させようかな? 下のFIRなども、原理や用途など後々解説します。個人的には図書館などで資料を少しあさったり、大学の先生のホームページなどを参考にプログラムしているのだが、説明が難解という印象があるので、中学生ぐらいでも分かるように、まとめていこうかと思っている。ちなみに私は元々文系寄りで、情報等の専門教育は受けたことはないです。すべて独学なので間違っていることもあると思います。たまに質問がくるので、ここでお断りしておきます。学生の方は先生に聞いてください。 プログラムの内容はFIRのLPF/HPFで、 こちらのページ のJavaScript版 ( 120111 窓関数を追加) と基本的には同じ。機能として増やしたのは窓関数をHammingだけでなくHanningも加えたことと、フィルタ係数すべてを配列に格納したところ。実行すると、パラメータの値に応じて、プロンプトにフィルタ係数を出力するようになっているので、自由に書き換えてみてください。そのフィルタ係数をAudacity等に読み込んでみると、下のような波形、つまりインパルス応答になる。 下はLPFの場合。わかる人には馴染み深く、そうでない人はさっぱりの世界。 下はHPF。デルタ関数みたいな地味なかたちだが微妙に波打っている。 参考までにデルタ関数は、1サンプルだけレベルが1になっている。いろいろ便利な関数で、重要なもの。 FIRの係数を求める式 n はタップのn 0 , n 1 , n 2 ・・・で、h(n) はタップn番の時の係数hという意味。ωはカットオフ周波数。0~ π の範囲で設定する。周波数(サンプリング周波数の1/2)の半分なら π /2。1/3であれば π /3。上記はLPFであれば、わりとそのまま使える。HPFは、若干いじることで実現できる。下のソースを見ればどう計算しているか分かると思うけど、ちょっとゴチャゴチャしている。変数も減らして、シンプルにきれいに書き直せばよいのだが、とりあえず動くのでそっとしておく。出来た係数を見比べるとLPFとHPFでは中央値以外はプラスマイナス