FFTを高速化するDFTとFFTの違いは何ですか?


16

私はFFTを理解しようとしていますが、ここに私が持っているものがあります:

波形内の周波数の大きさを見つけるには、2つの異なる位相(sinとcos)で、波形に検索対象の周波数を掛け、それぞれを平均化することにより、周波数を調べる必要があります。フェーズは2つとの関係によって検出され、そのためのコードは次のようなものです。

//simple pseudocode
var wave = [...];                //an array of floats representing amplitude of wave
var numSamples = wave.length;
var spectrum = [1,2,3,4,5,6...]  //all frequencies being tested for.  

function getMagnitudesOfSpectrum() {
   var magnitudesOut = [];
   var phasesOut = [];

   for(freq in spectrum) {
       var magnitudeSin = 0;
       var magnitudeCos = 0;

       for(sample in numSamples) {
          magnitudeSin += amplitudeSinAt(sample, freq) * wave[sample];
          magnitudeCos += amplitudeCosAt(sample, freq) * wave[sample];
       }

       magnitudesOut[freq] = (magnitudeSin + magnitudeCos)/numSamples;
       phasesOut[freq] = //based off magnitudeSin and magnitudeCos
   }

   return magnitudesOut and phasesOut;
}

非常に多くの周波数でこれを非常に迅速に行うために、FFTは多くのトリックを使用します。

FFTをDFTよりもはるかに高速にするために使用されるトリックにはどのようなものがありますか?

PS完成したFFTアルゴリズムをWebで調べてみましたが、すべてのトリックは説明のない1つの美しいコードに凝縮される傾向があります。全体を理解する前にまず必要なのは、これらの効率的な変更のそれぞれを概念として紹介することです。

ありがとうございました。


7
「DFT」はアルゴリズムを指すのではなく、数学的な演算を指します。「FFT」とは、その演算を計算するためのメソッドのクラスを指します。

1
sudoコード例での使用は、コンピューターの世界ではよく知られているコマンドであるため、混乱を招く可能性があることを指摘したかっただけです。あなたはおそらく擬似コードを意味していました。
-rwfeather

1
@nwfeather彼はおそらく「擬似コード」を意味していました。
user207421

回答:


20

ポイントDFT の単純な実装は、基本的にN × N行列による乗算です。これはON 2)の複雑さをもたらします。NN×NON2

最も一般的な高速フーリエ変換(FFT)アルゴリズムの1つは、基数2の Cooley-Tukey Decimation-in-Time FFTアルゴリズムです。これは基本的な分割統治アプローチです。

まず定義する"責め要因":として どこJ

WNej2πN
は虚数単位で、x[n]のDFTX[k]X[k]= N 1 n = 0 x[n]で与えられ ます。j1バツ[k]バツ[n]Nが偶数の 場合(および N
バツ[k]=n=0N1バツ[n]WNkn
Nは整数です)、次のように合計を2つの合計に分割できます X[k]= N / 2 1 n=0x[2n]W 2 k n N + N / 2 1 n=0x[2n+1]W k 2 n + 1 NN2
バツ[k]=n=0N/21バツ[2n]WN2kn+n=0N/21バツ[2n+1]WNk2n+1
ここで、最初の合計は偶数サンプルを扱い、2番目はx [ n ]の奇数サンプルを扱います。定義X E [ N ] X [ 2 N ]及びX O [ N ] X [ 2 N + 1 ]との事実を使用してバツ[n]バツ[n]バツe[n]バツ[2n]バツo[n]バツ[2n+1]
  1. およびWNk2n+1=WN2knWNk
  2. WN2kn=WN/2kn

これはX [ k ]として書き直すことができます ここで、Xe[k]およびXo[k] N

バツ[k]=n=0N/21バツe[n]WN/2kn+WNkn=0N/21バツo[n]WN/2kn=バツe[k]+WNkバツo[k]
バツe[k]バツo[k]それぞれx[n]の偶数および奇数サンプルの 2点 DFT変換。したがって、単一のN点DFTを2つの小さなNに変換しただけです。N2バツ[n]NポイントDFT。これは、計算コストを削減 2NN2N>2
2N22+N<N2
N>2

その後、2つの小さなDFTで同じプロセスを繰り返します。この分割統治アプローチにより、複雑なに到達することができます。これは、単純なDFT実装で持っていたON 2よりもはるかに優れています(leftaroundaboutの回答で大きく説明されています)。ONログNON2


それぞれの変数が何を表しているのかをリストアップしてもらえませんか?私はこれまで、むしろ新たなんだ、そうWjX()Nそしてkまだ私のために定義がありません。
セフリード

Wkn

19

http://nbviewer.jupyter.org/gist/leftaroundabout/83df89a7d3bdc24373ea470fb50be629

DFT、サイズ16

サイズ16のナイーブDFTでの操作の図

FFT、サイズ16

サイズ16の基数2のFFTの操作の図

複雑さの違いはそれから明らかですよね?


FFTの理解方法は次のとおりです。

FTL2RL2R

RC最も単純なケースは、関数が連続的であり、それを非常に小さな領域に分割して、各領域で基本的に一定である場合です。次に、各STFTには最も強くゼロ番目の項があります。(とにかく減衰する)他の係数を無視すると、各ドメインは単一のデータポイントになります。これらすべての短時間LF制限係数のうち、離散フーリエ変換を使用できます。実際、実際の測定データでFTを実行するときに、まさにそれを実行します。

ただし、測定データは必ずしも基本的な物理量に対応する必要はありません。たとえば、光の強度を測定する場合、実際には周波数がADCでサンプリングするには高すぎる電磁波の振幅を測定しているだけです。しかし明らかに、光波の異常な周波数にもかかわらず、サンプリングされた光強度信号のDFTを計算することができます。

これは、FFTが安価である最も重要な理由として理解できます。

最高レベルから個々の振動サイクル見ようとすることを気にしないでください。代わりに、すでにローカルで前処理された、ある程度高度な情報のみを変換します。

ただし、それだけではありません。FFTの素晴らしい点は、完全なDFTが提供するすべての情報まだ得られることです。つまり、光線の正確な電磁波をサンプリングするときにも取得するすべての情報。これは、フォトダイオード信号を変換することで実現できますか?–それから正確な光周波数を測定できますか?


ν=1/t

全体的に長い時間スパンを持つことにより、周波数の不確実性を絞り込むこともできるはずです。そして、これは、粗い周波数だけでなく、波の位相も局所的に測定する場合、実際に可能です。1000 Hzの信号は、1秒後に見るとまったく同じ位相になることがわかっています。一方、1000.5 Hzの信号は、短いスケールでは区別できませんが、1秒後に位相が反転します。

幸いなことに、その位相情報は単一の複素数に非常にうまく保存できます。これがFFTの仕組みです!それは、多くの小さなローカルな変換から始まります。これらは安価です。1つには、明らかに少量のデータしか使用しないためですが、2つ目は、短期間のためにとにかく周波数を正確に解決できないことを知っているためです。そのような変換の多くを行います。

ただし、これらはフェーズも記録するため、トップレベルで周波数分解能をより正確にすることができます。必要な変換は、それ自体が高周波振動に煩わされず、前処理された低周波データにのみ関係するため、やはり安価です。


うん、この時点で私の議論は少し循環的です。単に再帰と呼びましょう、私たちは大丈夫です...

この関係は量子力学ではありませんが、ハイゼンベルクの不確実性は実際には同じ基本的な理由があります。


2
問題の素敵な絵の描写。:-)
ロバートブリストージョンソン

2
どこにでも繰り返され、実際にどこにも説明されていないダイアグラムを愛してはいけません:)
Mehrdad

1
私はちょうどアンパーの答えを読んだ後、写真を理解しました。
JDługosz

15

WNnkej2πnkN

表示されているパスに注意してください。下の式は、ロバートの式で与えられる周波数ビンX(1)の結果を示しています。

破線は、総和結合がどこにあるかを明確にするためだけに実線と変わりません。

FFTの実装


8

基本的に、合計から直接素朴なDFTを計算する場合:

バツ[k]=n=0N1バツ[n]ej2πnkN

Nej2πnkNNN1バツ[k]kバツ[k+1]

  1. したがって、FFTはいくつかの中間データを保持します。
  2. FFTは、データの中間の組み合わせに同じ係数を使用できるように、回転係数を少し係数化することも利用します。

4

私は視覚的な人です。FFTは、合計のトリックとしてではなく、マトリックスのトリックとして想像することを好みます。

高レベルで説明するには:

単純なDFTは、各出力サンプルを個別に計算し、各計算ですべての入力サンプルを使用します(クラシックN²アルゴリズム)。

一般的なFFTは、DFT定義の対称性とパターンを使用して、「レイヤー」(log Nレイヤー)で計算を実行します。各レイヤーはサンプルごとに一定の時間要件を持ち、N log Nアルゴリズムを作成します。

詳細:

これらの対称性を視覚化する1つの方法は、DFTを、すべての複素指数のNxN行列を掛けた1×N行列入力として見ることです。「基数2」のケースから始めましょう。マトリックスの偶数行と奇数行(偶数と奇数の入力サンプルに対応)を分割し、それらを合計して同じ最終結果を得る2つの別個のマトリックス乗算と見なします。

これらの行列を見てみましょう。最初の行列では、左半分は右半分と同じです。他方では、右半分は左半分x -1です。つまり、これらの行列の左半分を乗算に使用し、右半分を1または-1で乗算することで安価に作成するだけです。次に、2番目の行列が各列で同じ係数だけ最初の行列と異なることを確認します。そのため、それを因数分解して入力に乗算し、偶数サンプルと奇数サンプルの両方が同じマトリックスを使用するようにします最初。最後のステップでは、この結果のN / 2×N / 2行列がN / 2 DFT行列と同一であり、DFTが恒等関数である1×1行列に到達するまでこれを何度も繰り返すことができます。

基数2を超えて一般化するには、3行ごとに分割し、列の3つのチャンク、または4番目ごとなどを見ることができます。

プライムサイズの入力の場合、ゼロパッド、FFT、および切り捨てを適切に行う方法がありますが、それはこの答えの範囲を超えています。

参照:http : //whoiskylefinn.com/MatrixFFT.html


プライムFFTさまざまなFFT。ゼロパッドを使用することが唯一のオプションではありません。申し訳ありませんが、ゼロパディングが過剰に使用されています。ちょっとした質問ですが、「サンプルごとに一定時間の要件がある各レイヤー」が何を意味するのか理解できません。説明できれば素晴らしいでしょう。

1
申し訳ありませんが、ゼロパディングが道であると言うつもりはありませんでした。そして、「レイヤー」は、再帰、またはN DFTから2 N / 2 DFTへの変換を意味します。サンプルごとに一定の時間がある場合、このステップはO(N)です。
-kylefinn

これまでのところ、すべての説明の中で、これは複雑な問題を単純にするのに最も近いようです。しかし、欠けている大きなことは、これらのマトリックスの例です。たまたま持っていますか?
セフリード

このアップロード、助けるべきである:whoiskylefinn.com/MatrixFFT.html
kylefinn

1

DFTはブルートフォースN ^ 2行列乗算を行います。

FFTは巧妙なトリックを実行し、行列の特性を活用して(行列の乗算を一般化して)計算コストを削減します。

最初に小さなDFTを見てみましょう。

W = fft(eye(4));

x = rand(4,1)+ 1j * rand(4,1);

X_ref = fft(x);

X = W * x;

assert(max(abs(X-X_ref))<1e-7)

素晴らしいので、FFT関数から行列を埋めることにより、MATLABのFFTWライブラリへの呼び出しを小さな4x4(複素数)行列乗算で置き換えることができます。それでは、このマトリックスはどのように見えるのでしょうか?

N = 4、

Wn = exp(-1j * 2 * pi / N)、

f =((0:N-1) '*(0:N-1))

f =

 0     0     0     0
 0     1     2     3
 0     2     4     6
 0     3     6     9

W = Wn。^ f

W =

1 1 1 1

1 -i -1 i

1 -1 1 -1

1 i -1 -i

各要素は、+ 1、-1、+ 1j、-1jのいずれかです。これは明らかに、完全に複雑な乗算を回避できることを意味します。さらに、最初の列は同じです。つまり、xの最初の要素に同じ係数を何度も掛けています。

クロネッカーテンソル積、「回転因子」、および反転されたバイナリ表現に応じてインデックスが変更される置換行列はコンパクトであり、FFTがスパース行列演算のセットとしてどのように計算されるかについての代替視点を提供します。

以下の行は、単純な周波数のデシメーション(DIF)基数2のフォワードFFTです。手順は煩雑に思えるかもしれませんが、実世界でインプレースFFTがどのように実装される傾向があるかを公平に表現しながら、順方向/逆方向FFT、radix4 / split-radix、または時間の間引きに再利用すると便利です。私は信じている。

N = 4;

x = randn(N、1)+ 1j * randn(N、1);

T1 = exp(-1j * 2 * pi *([zeros(1、N / 2)、0:(N / 2-1)])。 '/ N)、

M0 = kron(eye(2)、fft(eye(2)))、

M1 = kron(fft(eye(2))、eye(2))、

X = bitrevorder(x。 '* M1 * diag(T1)* M0)、

X_ref = fft(x)

assert(max(abs(X(:)-X_ref(:)))<1e-6)

CF Van Loanには、このテーマに関するすばらしい本があります。


弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.