14
フーリエ変換に再挑戦 以前理解しようと試みたフーリエ変 換、結局理解できずに終わっていま したが、再度挑戦した記録です。

フーリエ変換に再挑戦•f(t)はサンプリングデータを使えばよいことが分かったので、 DFTを実装してみた。簡単にするためにサンプリング数N

  • Upload
    others

  • View
    1

  • Download
    0

Embed Size (px)

Citation preview

フーリエ変換に再挑戦

以前理解しようと試みたフーリエ変換、結局理解できずに終わっていましたが、再度挑戦した記録です。

フーリエ変換再挑戦の目的・目標

• 以前一度トライして、理解できなかったトラウマがあり、いまだにすっきりしていない。

• PIC16Fを用いて、どれ位の時間でFFTが実行できるか試したい。

• 128サンプリング、50回更新/秒が一つの目標

ADC取込み、FFT、ビットリバース、結果出力を20ms以内

• 実装は、最初はC言語(xc8フリー版)

• 余力があれば、アセンブラで記述する?

• 前回躓いた個所は…、かなり昔なのでもう覚えていないことに気が付いた!気分一新で最初から!

• 今回躓いた箇所は、

フーリエ変換: 意味は、関数f(t)にe-jwtをかけ、-∞~∞の区間で時間積分する。

a

離散フーリエ変換: 意味は、関数f(t)にe-jwtをかけ、x=0~N-1の矩形領域の面積合計を求める。

※赤枠のf(t)は関数!躓いた箇所は、離散フーリエ変換にもf(t)の関数が、出てくること!→ 実際はサンプリングで得た値を用いればよいことが分かった!

f(t)と書いてあるサイトが多く、f(t)のサンプリング値と書いてあるサイトは少なかった… サンプリング値を用いることが分かり、一気に実装に進むことができた!

フーリエ変換と離散フーリエ変換

• つまり、調べたい時間tの関数の値f(t)(サンプリング値)と、e-iwtを掛け合わせて、f(ω)を求めればよい!

• 掛け合わせるとは、f(t)とe-iwtの二つの関数の内積を求めている。

• 内積を求めると、f(t)とe-iwtの関数の相関性を求めること。

• e-iwtは、オイラーの公式からcos(wt)+isin(wt)となる。

• 直交ベクトルと同様、三角関数(cosとsin)は関数が直交。

• 三次元空間での任意のベクトルは、x, y, zの単位ベクトルに係数をかけることで、表現することができることと同じく、時間の関数は、単位関数であるcos(wt)とsin(wt)に係数をかけることで、表現することができる。

• すなわちフーリエ変換(離散フーリエ変換も)は、単位関数の係数を求めるために演算を行っている。

ここまで理解したことのまとめ

• f(t)はサンプリングデータを使えばよいことが分かったので、DFTを実装してみた。簡単にするためにサンプリング数Nは8とすると、DFTを求める行列は下記。

離散フーリエ変換(DFT)の実装検討1

f(ω0)

f(ω1)

f(ω2)

f(ω3)

f(ω4)

f(ω5)

f(ω6)

f(ω7)

W0 W0 W0 W0 W0 W0 W0 W0

W0 W1 W2 W3 W4 W5 W6 W7 W0 W2 W4 W6 W8 W10 W12 W14

W0 W3 W6 W9 W12 W15 W18 W21

W0 W4 W8 W12 W16 W20 W24 W28

W0 W5 W10 W15 W20 W25 W30 W35

W0 W6 W12 W18 W24 W30 W36 W42

W0 W7 W14 W21 W28 W35 W42 W49

f(t0)

f(t1)

f(t2)

f(t3)

f(t4)

f(t5)

f(t6)

f(t7)

=

周期0

周期1

周期2

周期3

周期4

周期6

周期5

周期7

• Wは周期性があり、W8=W0なので、右肩の数字を8の剰余で置き換えると、以下の行列になる。

※2行目(1,2,…,7)と、8行目(7,6,…,1)と数字の並びが逆。

同様に3行目と7行目、4行目と6行目も数字の並びが逆。

離散フーリエ変換(DFT)の実装検討2

f(ω0)

f(ω1)

f(ω2)

f(ω3)

f(ω4)

f(ω5)

f(ω6)

f(ω7)

W0 W0 W0 W0 W0 W0 W0 W0

W0 W1 W2 W3 W4 W5 W6 W7 W0 W2 W4 W6 W0 W2 W4 W6

W0 W3 W6 W1 W4 W7 W2 W5

W0 W4 W0 W4 W0 W4 W0 W4

W0 W5 W2 W7 W4 W1 W6 W3

W0 W6 W4 W2 W0 W6 W4 W2

W0 W7 W6 W5 W4 W3 W2 W1

f(t0)

f(t1)

f(t2)

f(t3)

f(t4)

f(t5)

f(t6)

f(t7)

=

DFTとFFTの関係

• DFTを用いて、f(ω)を求めることができるが、サンプル数が多くなると計算量がO(N2)のため実用的ではない。

• FFTはDFTの計算途中に出てくる、周期性や繰り返しをまとめることで、計算量をO(Nlog2(N))に減らす計算方法。

• どれ位の高速化ができるか、8MIPSの超PICで検証。 • 1命令サイクルで、複素数の加減乗除可能

• 1命令サイクルで、二つのオペランドのメモリ読込み、演算、メモリ書出しが可能

• サンプル数: 2^16をDFTで行うと、計算量は2^16*2^16= 2^32=4,294,967,296となり、計算時間は、8MIPS で割ると536.870912秒=約8.94分

• FFTならば、2^16 log2(2^16)= 1,048,576となり、計算時間は、 0.131072秒となり、劇的な短縮が可能になる。

※こんな高性能なPICがあったらいいな!

FFTの計算方法1

• O(N2) の計算量を減らすには、Nの数を減らすことが重要。 t0, t2, t4, t6の行(赤枠)は、前半と後半が同じ形をしている。

t1, t3, t5, t7の行(青枠)は、前半と後半は符号が逆の形をしている。

※W0~W7の回転因子を複素平面のベクトル(赤:sin, 青:cos)で表すと、

W0: , W1: , W2: , W3: , W4: , W5: , W6: , W7:

W0=-W4, W1=-W5, W2=-W6, W3=-W7であることが分かる。

f(ω0)

f(ω1)

f(ω2)

f(ω3)

f(ω4)

f(ω5)

f(ω6)

f(ω7)

W0 W0 W0 W0 W0 W0 W0 W0

W0 W1 W2 W3 W4 W5 W6 W7 W0 W2 W4 W6 W0 W2 W4 W6

W0 W3 W6 W1 W4 W7 W2 W5

W0 W4 W0 W4 W0 W4 W0 W4

W0 W5 W2 W7 W4 W1 W6 W3

W0 W6 W4 W2 W0 W6 W4 W2

W0 W7 W6 W5 W4 W3 W2 W1

f(t0)

f(t1)

f(t2)

f(t3)

f(t4)

f(t5)

f(t6)

f(t7)

=

FFTの計算方法2

• 前頁で行った共通項をまとめることで、偶数行と奇数行のそれぞれのNを4にすることができ、計算量を2^3*2^3=64から、(2^2*2^2)*2=16に減らすことができた。

• 更に作業を行い、最終的には2x2の行列まで分解する。

• 今回の分解は半分ずつ行っているので基数2と呼ばれる方法。他には基数3や基数4、…もある。

• ここまで分解した計算式を視覚的に表現したのがバタフライ演算図になる。

f(ω1)

f(ω3)

f(ω5)

f(ω7)

W0 W1 W2 W3 W0 W3 W6 W1

W0 W5 W2 W7

W0 W7 W6 W5

f(t0)-f(t4)

f(t1)-f(t5)

f(t2)-f(t6)

f(t3)-f(t7)

=

f(ω0)

f(ω2)

f(ω4)

f(ω6)

W0 W0 W0 W0

W0 W2 W4 W6

W0 W4 W0 W4

W0 W6 W4 W2

f(t0)+f(t4)

f(t1)+f(t5)

f(t2)+f(t6)

f(t3)+f(t7)

=

バタフライ演算図の理解

• バタフライ演算図に従って演算を行うことで、FFTが実行できることが分かったので、バタフライ演算図の読み方を理解する。

基数2、周波数間引き

• x(0)+x(4)→x(0)とする。同様にx(1)+x(5)→x(1), x(2)+x(6)→x(2), x(3)+x(7)→x(3)とする。

• x((0)-x(4))*W0→x(4)とする。同様にx((1)-x(5))*W1→x(5), x((2)-x(6))*W2→x(6),

x((3)-x(7))*W3→x(7)とする。

• これを左から順に右に演算を行っていく。N=8ならば、3ステップになる。

• それぞれのステップで求めた演算結果は、x(0)~x(7)に書き戻し可能。(In-Place演算可能)

• 得られたFFTの値は、ビットリバースを行うことでx(0)~x(7)に順に並べることができる。

Step1 Step2 Step3

C言語を用いたFFTの実装

• C言語を用いてFFTのコードを実装を試みた。 • N=2まで分解するループ、N/2まで回すループ、x(n)、x(n+N/2)から値をとり、演算しx(n),

x(n)+N/2に書き戻すループの3重ループで実装。

• バタフライ演算の1単位の演算は、以下となる。

a = n, b = a + N/2

Out(a) = rIn(a) + rIn(b)

iIn(a) + iIn(b)

Out(b) = cos(ωt) * (rIn(a) – rIn(b)) + sin(ωt) * (iIn(a) – iIn(b))

-sin(ωt) * (rIn(a) - rIn(b)) + cos(ωt) * (iIn(a) - iIn(b))

青枠: 実数部、赤枠: 虚数部

• 回転因子は、cosとsinのテーブルをあらかじめ作成し、テーブルを参照することで行う。

• 浮動小数点演算はコストが高いので、固定小数点(Q1.15フォーマット)で計算を行う。

• PIC16F18325上にN=128のサンプル数でFFT演算をシュミレータ上で実施。

MPLAB X IDE v4.05, XC8 v1.44, Fcyc: 8MHz

FFT演算+ビットリバース実行時間: cycle count = 695353 (86.919125 ms)

当初の目標値は全く満たしていない。残念!

dsPICとPIC32での実行時間計測

• PIC16F18325の実行時間が残念な結果に終わったので、下記PICで実行時間を追加計測。

1. dsPIC33FJ64GP802, XC16 v1.33, Fcyc: 8MHz

FFT演算+ビットリバース実行時間: cycle count = 62704 (7.838 ms)

dsPICが実装しているDSPエンジン専用命令(MAC等)は使われていない。これらの命令を使うことで、実行時間の短縮が期待できるが、アセンブラで実装が必要。

2. PIC32MX270F256B, XC32 v1.44, Fcyc: 8MHz

FFT演算+ビットリバース実行時間: cycle count = 61208 (7.651 ms)

参考情報: Fcyc: 50MHzとすると、 1.22416 msで実行可能。

※ PIC16Fと比べると、上記PICは実行命令数が一桁少ない。PIC16FはALUが8bitなので、Q1.15の16bitの計算は荷が重いかも…

アセンブラで実装して、dsPIC, PIC上で動作させるとどれくらいのベンチマークを記録するのだろうか?

今後の予定

• ADCからアナログデータを取り込み、FFTを実行。

• PIC16F18325のFFT結果を表示。

→パワースペクトルを求めるには、複素数の絶対値を求める必要があり、更に処理時間が長くなる。表示手段は別途検討

• 主要機能(Q1.15加算・乗算, FFT)をアセンブラで記述

→アーキテクチャは異なるが、Atmel 16MHz(乗算器あり), N=128、アセンブラ実装の実行時間は、7ms @ELM ChaN

• PIC16にこだわる必要はなく、dsPICやPIC32を使うべきか… 行いたいアプリケーションは、ADCで取り込みFFTで周波数ドメインで観察したい。

参考にしたサイト • サルでも分かるFFT(1)~

http://techtipshoge.blogspot.jp/2011/05/fft1.html

• エクセルを用いたフーリエ変換(FFT)

http://godfoot.world.coocan.jp/fourier-transform.htm

• ELM ChaN

http://elm-chan.org/

• Wikipedia

https://ja.wikipedia.org/wiki/

• やる夫で学ぶディジタル信号処理

http://www.ic.is.tohoku.ac.jp/~swk/lecture/yaruodsp/main.html

• PIC AVR 工作室

http://picavr.uunyan.com/index.html

• FFT (高速フーリエ・コサイン・サイン変換) の概略と設計法

http://www.kurims.kyoto-u.ac.jp/~ooura/fftman/index.html

• FFTを固定小数点化する

http://d.hatena.ne.jp/suikan+blackfin/