/** * Initialize class to perform FFT of specified size. * * @param logN Log2 of FFT length. e.g. for 512 pt FFT, logN = 9. */ public void init( uint logN) { m_logN = logN; m_N = (uint)(1 << (int)m_logN); // Allocate elements for linked list of complex numbers. m_X = new FFTElement[m_N]; for (uint k = 0; k < m_N; k++) { m_X[k] = new FFTElement(); } // Set up "next" pointers. for (uint k = 0; k < m_N - 1; k++) { m_X[k].next = m_X[k + 1]; } // Specify target for bit reversal re-ordering. for (uint k = 0; k < m_N; k++) { m_X[k].revTgt = BitReverse(k, logN); } }
private void InitThread() { lock (this) { uint logN = log; m_logN = logN; m_N = (uint)(1 << (int)m_logN); // Allocate elements for linked list of complex numbers. m_X = new FFTElement[m_N]; for (uint k = 0; k < m_N; k++) { m_X[k] = new FFTElement(); } // Set up "next" pointers. for (uint k = 0; k < m_N - 1; k++) { m_X[k].next = m_X[k + 1]; } // Specify target for bit reversal re-ordering. for (uint k = 0; k < m_N; k++) { m_X[k].revTgt = BitReverse(k, logN); } myInstance = instances; instances++; //Debug.Log ("done init " + myInstance); } }
/// <summary> /// Initialize the FFT. Must call first and this anytime the FFT setup changes. /// </summary> /// <param name="inputDataLength"></param> /// <param name="zeroPaddingLength"></param> public FFT Initialize(UInt32 inputDataLength, UInt32 zeroPaddingLength = 0) { mN = inputDataLength; // Find the power of two for the total FFT size up to 2^32 bool foundIt = false; for (mLogN = 1; mLogN <= 32; mLogN++) { double n = Math.Pow(2.0, mLogN); if ((inputDataLength + zeroPaddingLength) == n) { foundIt = true; break; } } if (foundIt == false) { throw new ArgumentOutOfRangeException("inputDataLength + zeroPaddingLength was not an even power of 2! FFT cannot continue."); } // Set global parameters. mLengthTotal = inputDataLength + zeroPaddingLength; mLengthHalf = (mLengthTotal / 2) + 1; // Set the overall scale factor for all the terms mFFTScale = Math.Sqrt(2) / (double)(mLengthTotal); // Natural FFT Scale Factor // Window Scale Factor mFFTScale *= ((double)mLengthTotal) / (double)inputDataLength; // Zero Padding Scale Factor // Allocate elements for linked list of complex numbers. mX = new FFTElement[mLengthTotal]; for (UInt32 k = 0; k < (mLengthTotal); k++) { mX[k] = new FFTElement(); } // Set up "next" pointers. for (UInt32 k = 0; k < (mLengthTotal) - 1; k++) { mX[k].next = mX[k + 1]; } // Specify target for bit reversal re-ordering. for (UInt32 k = 0; k < (mLengthTotal); k++) { mX[k].revTgt = DSP.Util.BitReverse(k, mLogN); } return(this); }
public void Initialize(uint inputDataLength, uint zeroPaddingLength = 0) { mN = inputDataLength; bool foundIt = false; for (mLogN = 1; mLogN <= 32; mLogN++) { double n = Math.Pow(2.0, mLogN); if ((inputDataLength + zeroPaddingLength) == n) { foundIt = true; break; } } if (foundIt == false) { throw new ArgumentOutOfRangeException("inputDataLength + zeroPaddingLength não foi uma potência igual a 2! A FFT não pode continuar."); } mLengthTotal = inputDataLength + zeroPaddingLength; mLengthHalf = (mLengthTotal / 2) + 1; mFFTScale = Math.Sqrt(2) / mLengthTotal; mFFTScale *= mLengthTotal / (double)inputDataLength; mX = new FFTElement[mLengthTotal]; for (uint k = 0; k < (mLengthTotal); k++) { mX[k] = new FFTElement(); } for (uint k = 0; k < (mLengthTotal) - 1; k++) { mX[k].next = mX[k + 1]; } for (uint k = 0; k < (mLengthTotal); k++) { mX[k].revTgt = BitReverse(k, mLogN); } }
/** * Initialize class to perform FFT of specified size. * * @param logN Log2 of FFT length. e.g. for 512 pt FFT, logN = 9. */ public void init( uint logN ) { m_logN = logN; m_N = (uint)(1 << (int)m_logN); // Allocate elements for linked list of complex numbers. m_X = new FFTElement[m_N]; for (uint k = 0; k < m_N; k++) m_X[k] = new FFTElement(); // Set up "next" pointers. for (uint k = 0; k < m_N-1; k++) m_X[k].next = m_X[k+1]; // Specify target for bit reversal re-ordering. for (uint k = 0; k < m_N; k++ ) m_X[k].revTgt = BitReverse(k,logN); }
public Complex[] Execute(double[] timeSeries) { uint numFlies = mLengthTotal >> 1; uint span = mLengthTotal >> 1; uint spacing = mLengthTotal; uint wIndexStep = 1; FFTElement x = mX[0]; uint k = 0; for (uint i = 0; i < mN; i++) { x.re = timeSeries[k]; x.im = 0.0; x = x.next; k++; } if (mN != mLengthTotal) { for (uint i = mN; i < mLengthTotal; i++) { x.re = 0.0; x.im = 0.0; x = x.next; } } for (uint stage = 0; stage < mLogN; stage++) { double wAngleInc = wIndexStep * -2.0 * Math.PI / (mLengthTotal); double wMulRe = Math.Cos(wAngleInc); double wMulIm = Math.Sin(wAngleInc); for (uint start = 0; start < (mLengthTotal); start += spacing) { FFTElement xTop = mX[start]; FFTElement xBot = mX[start + span]; double wRe = 1.0; double wIm = 0.0; for (uint flyCount = 0; flyCount < numFlies; ++flyCount) { double xTopRe = xTop.re; double xTopIm = xTop.im; double xBotRe = xBot.re; double xBotIm = xBot.im; xTop.re = xTopRe + xBotRe; xTop.im = xTopIm + xBotIm; xBotRe = xTopRe - xBotRe; xBotIm = xTopIm - xBotIm; xBot.re = xBotRe * wRe - xBotIm * wIm; xBot.im = xBotRe * wIm + xBotIm * wRe; xTop = xTop.next; xBot = xBot.next; double tRe = wRe; wRe = wRe * wMulRe - wIm * wMulIm; wIm = tRe * wMulIm + wIm * wMulRe; } } numFlies >>= 1; span >>= 1; spacing >>= 1; wIndexStep <<= 1; } x = mX[0]; Complex[] unswizzle = new Complex[mLengthTotal]; while (x != null) { uint target = x.revTgt; unswizzle[target] = new Complex(x.re * mFFTScale, x.im * mFFTScale); x = x.next; } Complex[] result = new Complex[mLengthHalf]; Array.Copy(unswizzle, result, mLengthHalf); result[0] = new Complex(result[0].Real / Math.Sqrt(2), 0.0); result[mLengthHalf - 1] = new Complex(result[mLengthHalf - 1].Real / Math.Sqrt(2), 0.0); return(result); }
/** * Performs in-place complex FFT. * * @param xRe Real part of input/output - horizontal * @param xIm Imaginary part of input/output -vertical * @param inverse If true, do an inverse FFT */ public void run( double[] xRe, double[] xIm, bool inverse = false) { uint numFlies = m_N >> 1; // Number of butterflies per sub-FFT uint span = m_N >> 1; // Width of the butterfly uint spacing = m_N; // Distance between start of sub-FFTs uint wIndexStep = 1; // Increment for twiddle table index // Copy data into linked complex number objects // If it's an IFFT, we divide by N while we're at it FFTElement x = m_X[0]; uint k = 0; double scale = inverse ? 1.0 / m_N : 1.0; while (x != null) { x.re = scale * xRe[k]; x.im = scale * xIm[k]; x = x.next; k++; } // For each stage of the FFT for (uint stage = 0; stage < m_logN; stage++) { // Compute a multiplier factor for the "twiddle factors". // The twiddle factors are complex unit vectors spaced at // regular angular intervals. The angle by which the twiddle // factor advances depends on the FFT stage. In many FFT // implementations the twiddle factors are cached, but because // array lookup is relatively slow in C#, it's just // as fast to compute them on the fly. double wAngleInc = wIndexStep * 2.0 * Math.PI / m_N; if (inverse == false) { wAngleInc *= -1; } double wMulRe = Math.Cos(wAngleInc); double wMulIm = Math.Sin(wAngleInc); for (uint start = 0; start < m_N; start += spacing) { FFTElement xTop = m_X[start]; FFTElement xBot = m_X[start + span]; double wRe = 1.0; double wIm = 0.0; // For each butterfly in this stage for (uint flyCount = 0; flyCount < numFlies; ++flyCount) { // Get the top & bottom values double xTopRe = xTop.re; double xTopIm = xTop.im; double xBotRe = xBot.re; double xBotIm = xBot.im; // Top branch of butterfly has addition xTop.re = xTopRe + xBotRe; xTop.im = xTopIm + xBotIm; // Bottom branch of butterly has subtraction, // followed by multiplication by twiddle factor xBotRe = xTopRe - xBotRe; xBotIm = xTopIm - xBotIm; xBot.re = xBotRe * wRe - xBotIm * wIm; xBot.im = xBotRe * wIm + xBotIm * wRe; // Advance butterfly to next top & bottom positions xTop = xTop.next; xBot = xBot.next; // Update the twiddle factor, via complex multiply // by unit vector with the appropriate angle // (wRe + j wIm) = (wRe + j wIm) x (wMulRe + j wMulIm) double tRe = wRe; wRe = wRe * wMulRe - wIm * wMulIm; wIm = tRe * wMulIm + wIm * wMulRe; } } numFlies >>= 1; // Divide by 2 by right shift span >>= 1; spacing >>= 1; wIndexStep <<= 1; // Multiply by 2 by left shift } // The algorithm leaves the result in a scrambled order. // Unscramble while copying values from the complex // linked list elements back to the input/output vectors. x = m_X[0]; while (x != null) { uint target = x.revTgt; xRe[target] = x.re; xIm[target] = x.im; x = x.next; } }
/// <summary> /// Executes a FFT /// </summary> /// <param name="series"></param> /// <returns>Complex[] Spectrum</returns> private Complex[] Execute(Complex[] series, bool direct = true) { UInt32 numFlies = mLengthTotal >> 1; // Number of butterflies per sub-FFT UInt32 span = mLengthTotal >> 1; // Width of the butterfly UInt32 spacing = mLengthTotal; // Distance between start of sub-FFTs UInt32 wIndexStep = 1; // Increment for twiddle table index Debug.Assert(series.Length <= mLengthTotal, "The input timeSeries length was greater than the total number of points that was initialized. FFT.Execute()"); // Copy data into linked complex number objects FFTElement x = mX[0]; UInt32 k = 0; for (UInt32 i = 0; i < mN; i++) { x.re = series[k].Real; x.im = series[k].Imaginary; x = x.next; k++; } // If zero padded, clean the 2nd half of the linked list from previous results if (mN != mLengthTotal) { for (UInt32 i = mN; i < mLengthTotal; i++) { x.re = 0.0; x.im = 0.0; x = x.next; } } // For each stage of the FFT for (UInt32 stage = 0; stage < mLogN; stage++) { // Compute a multiplier factor for the "twiddle factors". // The twiddle factors are complex unit vectors spaced at // regular angular intervals. The angle by which the twiddle // factor advances depends on the FFT stage. In many FFT // implementations the twiddle factors are cached, but because // array lookup is relatively slow in C#, it's just // as fast to compute them on the fly. double wAngleInc = wIndexStep * -2.0 * Math.PI / (mLengthTotal); double wMulRe = Math.Cos(wAngleInc); double wMulIm = Math.Sin(wAngleInc); for (UInt32 start = 0; start < (mLengthTotal); start += spacing) { FFTElement xTop = mX[start]; FFTElement xBot = mX[start + span]; double wRe = 1.0; double wIm = 0.0; // For each butterfly in this stage for (UInt32 flyCount = 0; flyCount < numFlies; ++flyCount) { // Get the top & bottom values double xTopRe = xTop.re; double xTopIm = xTop.im; double xBotRe = xBot.re; double xBotIm = xBot.im; // Top branch of butterfly has addition xTop.re = xTopRe + xBotRe; xTop.im = xTopIm + xBotIm; // Bottom branch of butterfly has subtraction, // followed by multiplication by twiddle factor xBotRe = xTopRe - xBotRe; xBotIm = xTopIm - xBotIm; xBot.re = xBotRe * wRe - xBotIm * wIm; xBot.im = xBotRe * wIm + xBotIm * wRe; // Advance butterfly to next top & bottom positions xTop = xTop.next; xBot = xBot.next; // Update the twiddle factor, via complex multiply // by unit vector with the appropriate angle // (wRe + j wIm) = (wRe + j wIm) x (wMulRe + j wMulIm) double tRe = wRe; wRe = wRe * wMulRe - wIm * wMulIm; wIm = tRe * wMulIm + wIm * wMulRe; } } numFlies >>= 1; // Divide by 2 by right shift span >>= 1; spacing >>= 1; wIndexStep <<= 1; // Multiply by 2 by left shift } // The algorithm leaves the result in a scrambled order. // Unscramble while copying values from the complex // linked list elements to a complex output vector & properly apply scale factors. x = mX[0]; Complex[] unswizzle = new Complex[mLengthTotal]; while (x != null) { UInt32 target = x.revTgt; unswizzle[target] = direct ? new Complex(x.re * mFFTScale, x.im * mFFTScale) : new Complex(x.im, x.re); x = x.next; } Complex[] result = new Complex[mLengthTotal]; Array.Copy(unswizzle, result, mLengthTotal); if (direct) { // DC and Fs/2 Points are scaled differently, since they have only a real part result[0] = new Complex(result[0].Real / Math.Sqrt(2), 0.0); result[mLengthHalf - 1] = new Complex(result[mLengthHalf - 1].Real / Math.Sqrt(2), 0.0); } else { result = result.Multiply(1 / System.Math.Sqrt(2)); } return(result); }