TB-LAB BLOG

坪川研究室ブログです!適当に更新します!

Androidで周波数を解析してみよう

こんちは,kkです. 今回は自分の研究の根幹である高速フーリエ変換について解説したいと思います. shiro-chanにプログラムを丸ごと保存しておくので参考にしてください. いくつか厳密ではない説明や,おかしいところがあると思いますがご了承ください.

高速フーリエ変換とは

そもそもフーリエ解析とはなんぞやってことで簡単に説明します. ものすごいざっくり言うと,波形データを周波数ごとのレベルに変換することです. レベルというのは強さや音量と置き換えてもいいです(厳密にはダメですが分かりやすくするため).

イメージできるように音で説明します. 例えば太鼓を叩いたり,ギターを弾いたりすると膜や弦が振動します.その振動が空気中を伝わり,音波となって私達の耳に聞こえます. つまり,音も波形データです.

下の図を見てみましょう.

f:id:tb-lab:20150213171325j:plain

1つの波が4つ以上の単純な波(正弦波)で構成されていることが分かると思います. 全ての波形はsin波の重ね合わせで表すことができます. フーリエ解析を行うと,任意の波形がどんな波とどんな波の組み合わせか調べることができます.

だいぶ回りくどくなりましたが,まとめると,フーリエ解析とは音などの波形データにどの周波数がどのくらい含まれているか明らかにしてくれるもので,高速フーリエ変換はデータのポイント数を2n(n=1,2,3…)にすることでフーリエ解析を高速にしたものです.

プログラムの説明

それでは本題です. 下にプログラムのソースコードを載せます. それについて説明します. まず下のプログラムが何をやっているかというと,Androidのマイクが取得した音の中で最も音量の大きい周波数を表示しています.音量という表現は厳密ではありませんが便宜的にこの表現にします. それでは細かい設定を見てみましょう.

初期設定

まずサンプリングレートは44100で設定しています. サンプリングレートとは、アナログ信号をデジタル信号に変換する際に1秒間に実行する標本化(サンプリング)処理の回数のことです. 今回は1秒分の波形データを44100個のデータに分割しています. 1秒を44100個に分割しているので1データあたりの秒数は 1÷44100=0.0000227[秒]になります. この数字が後で意味を持ってくるので覚えておいてください.

次にFFTのポイント数が4096で設定されています. このポイント数とはフーリエ変換に利用するデータの個数のことです. サンプリングしたデータが4096個集まった時,フーリエ変換が行われます. 1データあたり0.0000227秒でそれが4096個集まると0.0000227×4096=0.093秒となります. つまり,約0.1秒分の音の周波数を解析するわけです.

次にデシベルベースラインですが今回は割愛します.別に分からないわけじゃないよ(-_-;)

分解能の説明に移ります. 分解能とは何かを計るときの最小単位になります. 1cmごとに目盛がふってある定規をイメージしてください. この定規は1cm以下の大きさは計ることができません.なのでこの物差しの分解能は1cmとなります. フーリエ変換に話を戻します. 周波数解析の分解能はサンプリングレート÷FFTのポイント数で求めることができます. 今回の場合は44100÷4096=10.76[Hz]となります. 例えば5Hzの成分が最も強い波形があったとしても,分解能が10.76Hzなので正確な値を取得することはできません. 気付いた人もいるかと思いますが分解能の逆数がフーリエ変換を行うデータが集まるまでの時間になります. つまり,分解能を小さくすればするほど1回のフーリエ変換に必要なデータの時間は増えるので,フーリエ変換の精度向上を考えると,自動的に1回のフーリエ変換にかかる時間も増え,処理スピードが遅くなります. 精度と時間はトレードオフの関係にあります.

エンディアン変換

プログラムの47行目から52行目にかけてエンディアン変換をしています. エンディアンとは数値のメモリーへの格納方法のことです. 数値の上位桁がメモリーの下位にあるような場合にビッグエンディアンといい,数値の下位桁がメモリーの下位にあるような場合にリトルエンディアンといいます. 詳しくは自分で調べてみてください. このプログラムでは録音はraw形式で行われていて,データはリトルエンディアンで格納されます. しかし,フーリエ解析を行うプログラムではデータの格納順序はビッグエンディアンを想定しているので,このままフーリエ解析を実行すると不具合が生じてしまいます.

フーリエ変換の実行

フーリエ変換を行うのに大浦版FFTを利用しています. 他にもJTransformsと行ったFFT用のライブラリがありますが大浦版が最も処理スピードが速かったので採用しました. 閑話休題. 55行目ではフーリエ変換を行うクラスを宣言しています. 56から59行目でエンディアン変換した録音データをdouble型の配列に格納しています. 60行目で集まったデータの塊に対してフーリエ解析を行っています. fft.rdft(1, FFTdata)の1つ目の引数を0にすると逆フーリエ変換が,1にするとフーリエ変換が行われます.

そして63行目から73行目にかけて解析した周波数から最も強い周波数を探して,Logに表示しています.以上がこのプログラムの説明になります.

まとめ
  1. 音の取得
  2. エンディアン変換
  3. フーリエ解析
  4. ログの表示

上記の処理を繰り返しているのがこのプログラムです. 今は単純に最大音圧の周波数を表示していますが,カスタマイズすることで色々なことができるようになると思います.

最後に

間違っているところや分からないところあったと思います. そこは自分で調べるか我慢するかしてくださいw 研究室のメンバーはソースを見たり,論文を読んだりすれば多少は納得できると思います. 長文になりましたが,最後まで付き合ってくださったかた感謝しています. ありがと,またね.