EE 356 Notes on the Fast Fourier Transform The discrete Fourier transform (DFT) and its inverse are given by: N −1 F ( k ) = ∑ f ( n) ⋅ e −j 2πkn N Discrete Fourier Transform n =0 f ( n) = 2πkn 1 N −1 j F (k ) e N ∑ N k =0 Inverse Discrete Fourier Transform The variable n is the discrete counter in the time domain and the variable k is the discrete counter in the frequency domain. In both cases there are N samples. From the equations we see that to compute the DFT we need to do N complex multiplies for each value of k and there are N such values. The DFT requires N2 complex multiplications. A reasonable sized sound file could easily have 100,000 samples requiring 1010 complex multiplications. The fast Fourier transform is an algorithm for the efficient evaluation of the DFT. The number of complex multiplications required for N samples using the FFT is proportional to N rather than N2. The C# code below is an implementation of the FFT. It relies on the Complex number class which follows. The data file is in the d[] matrix which is complex. For sound files, all the values in the data file will be real with zero imaginary parts. N is the number of samples and must be a power of 2. N = 2p. The result is a complex number returned in the d[] matrix. You can plot the magnitude and/or the phase angle of the complex result vs. frequency. The result will have N samples in frequency space equally divided between 0 and fs/2 where fs is the sample frequency of the sound file. private void FFT(Complex[] d,int N,int p) {int i, j = 1, k, L; int ip; int exp2L; Complex u = new Complex(0, 0); Complex W = new Complex(0, 0); Complex t = new Complex(0, 0); for(i=1;i<N;i++) {if(i < j) Swap(ref d[i-1], ref d[j-1]); k = N/2; while(k < j) {j = j - k; k = k/2; } j = j + k; } for(L=1;L<=p;L++) {exp2L = (int)Math.Pow(2, L)/2; u.Real = 1;u.Imag = 0; W.Real = Math.Cos(Math.PI/exp2L); W.Imag = -Math.Sin(Math.PI/exp2L); for(j=1;j<=exp2L;j++) {for(i=j;i<=N;i=i+2*exp2L) {ip = i + exp2L; t = d[ip-1]*u; d[ip-1] = d[i-1] - t; d[i-1] = d[i-1] + t; } u = u*W; } } } private void Swap(ref Complex x, ref Complex y) {Complex tmp = new Complex(x.Real, x.Imag); x.Real = y.Real;x.Imag = y.Imag; y.Real = tmp.Real;y.Imag = tmp.Imag; } class Complex {public Complex() {real = 0; imag = 0; } public Complex(double x, double y) {real = x; imag = y; } private double real; private double imag; // public double Real {get {return real;} set {real = value;} } public double Imag {get {return imag;} set {imag = value;} } public double Magnitude() {double tmp; tmp = Math.Sqrt(Real*Real + Imag*Imag); return tmp; } public static Complex {Complex cTmp = new cTmp.real = x.real cTmp.imag = x.imag return cTmp; } public static Complex {Complex cTmp = new cTmp.real = x.real cTmp.imag = x.imag return cTmp; } operator+(Complex x, Complex y) Complex(); + y.real; + y.imag; operator-(Complex x, Complex y) Complex(); - y.real; - y.imag; } public static Complex operator*(Complex x, Complex y) {Complex cTmp = new Complex(); cTmp.real = x.Real*y.Real - x.Imag*y.Imag; cTmp.imag = x.Real*y.Imag + x.Imag*y.Real; return cTmp; }