3 * Copyright (c) 2001, 2002 Ben Houston [ ben@exocortex.org ]
\r
4 * Exocortex Technologies [ www.exocortex.org ]
\r
5 * All rights reserved.
\r
7 * Redistribution and use in source and binary forms, with or without
\r
8 * modification, are permitted provided that the following conditions are met:
\r
10 * 1. Redistributions of source code must retain the above copyright notice,
\r
11 * this list of conditions and the following disclaimer.
\r
12 * 2. Redistributions in binary form must reproduce the above copyright
\r
13 * notice, this list of conditions and the following disclaimer in the
\r
14 * documentation and/or other materials provided with the distribution.
\r
15 * 3. Neither the name of the <ORGANIZATION> nor the names of its contributors
\r
16 * may be used to endorse or promote products derived from this software
\r
17 * without specific prior written permission.
\r
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
\r
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
\r
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
\r
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
\r
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
\r
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
\r
25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
\r
26 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
\r
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
\r
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
\r
33 using System.Diagnostics;
\r
37 //using Exocortex.Imaging;
\r
39 namespace Exocortex.DSP {
\r
41 // Comments? Questions? Bugs? Tell Ben Houston at ben@exocortex.org
\r
42 // Version: May 4, 2002
\r
45 /// <p>Static functions for doing various Fourier Operations.</p>
\r
47 public class Fourier {
\r
49 //======================================================================================
\r
54 //======================================================================================
\r
56 static private void Swap( ref float a, ref float b ) {
\r
61 static private void Swap( ref double a, ref double b ) {
\r
66 static private void Swap( ref ComplexF a, ref ComplexF b ) {
\r
71 static private void Swap( ref Complex a, ref Complex b ) {
\r
77 //-------------------------------------------------------------------------------------
\r
79 private const int cMaxLength = 4096;
\r
80 private const int cMinLength = 1;
\r
82 private const int cMaxBits = 12;
\r
83 private const int cMinBits = 0;
\r
86 static private bool IsPowerOf2( int x ) {
\r
87 return (x & (x - 1)) == 0;
\r
88 //return ( x == Pow2( Log2( x ) ) );
\r
90 static private int Pow2( int exponent ) {
\r
91 if( exponent >= 0 && exponent < 31 ) {
\r
92 return 1 << exponent;
\r
96 static private int Log2( int x ) {
\r
141 if( x <= 16777216 ) {
\r
142 if( x <= 1048576 ) {
\r
143 if( x <= 262144 ) {
\r
152 if( x <= 4194304 ) {
\r
161 if( x <= 268435456 ) {
\r
162 if( x <= 67108864 ) {
\r
163 if( x <= 33554432 )
\r
167 if( x <= 134217728 )
\r
171 if( x <= 1073741824 ) {
\r
172 if( x <= 536870912 )
\r
176 // since int is unsigned it can never be higher than 2,147,483,647
\r
177 // if( x <= 2147483648 )
\r
183 //-------------------------------------------------------------------------------------
\r
184 //-------------------------------------------------------------------------------------
\r
186 static private int ReverseBits( int index, int numberOfBits ) {
\r
187 Debug.Assert( numberOfBits >= cMinBits );
\r
188 Debug.Assert( numberOfBits <= cMaxBits );
\r
190 int reversedIndex = 0;
\r
191 for( int i = 0; i < numberOfBits; i ++ ) {
\r
192 reversedIndex = ( reversedIndex << 1 ) | ( index & 1 );
\r
193 index = ( index >> 1 );
\r
195 return reversedIndex;
\r
198 //-------------------------------------------------------------------------------------
\r
200 static private int[][] _reversedBits = new int[ cMaxBits ][];
\r
201 static private int[] GetReversedBits( int numberOfBits ) {
\r
202 Debug.Assert( numberOfBits >= cMinBits );
\r
203 Debug.Assert( numberOfBits <= cMaxBits );
\r
204 if( _reversedBits[ numberOfBits - 1 ] == null ) {
\r
205 int maxBits = Fourier.Pow2( numberOfBits );
\r
206 int[] reversedBits = new int[ maxBits ];
\r
207 for( int i = 0; i < maxBits; i ++ ) {
\r
210 for( int j = 0; j < numberOfBits; j ++ ) {
\r
211 newBits = ( newBits << 1 ) | ( oldBits & 1 );
\r
212 oldBits = ( oldBits >> 1 );
\r
214 reversedBits[ i ] = newBits;
\r
216 _reversedBits[ numberOfBits - 1 ] = reversedBits;
\r
218 return _reversedBits[ numberOfBits - 1 ];
\r
221 //-------------------------------------------------------------------------------------
\r
223 static private void ReorderArray( float[] data ) {
\r
224 Debug.Assert( data != null );
\r
226 int length = data.Length / 2;
\r
228 Debug.Assert( Fourier.IsPowerOf2( length ) == true );
\r
229 Debug.Assert( length >= cMinLength );
\r
230 Debug.Assert( length <= cMaxLength );
\r
232 int[] reversedBits = Fourier.GetReversedBits( Fourier.Log2( length ) );
\r
233 for( int i = 0; i < length; i ++ ) {
\r
234 int swap = reversedBits[ i ];
\r
236 Fourier.Swap( ref data[ (i<<1) ], ref data[ (swap<<1) ] );
\r
237 Fourier.Swap( ref data[ (i<<1) + 1 ], ref data[ (swap<<1) + 1 ] );
\r
242 static private void ReorderArray( double[] data ) {
\r
243 Debug.Assert( data != null );
\r
245 int length = data.Length / 2;
\r
247 Debug.Assert( Fourier.IsPowerOf2( length ) == true );
\r
248 Debug.Assert( length >= cMinLength );
\r
249 Debug.Assert( length <= cMaxLength );
\r
251 int[] reversedBits = Fourier.GetReversedBits( Fourier.Log2( length ) );
\r
252 for( int i = 0; i < length; i ++ ) {
\r
253 int swap = reversedBits[ i ];
\r
255 Fourier.Swap( ref data[ i<<1 ], ref data[ swap<<1 ] );
\r
256 Fourier.Swap( ref data[ i<<1 + 1 ], ref data[ swap<<1 + 1 ] );
\r
261 static private void ReorderArray( Complex[] data ) {
\r
262 Debug.Assert( data != null );
\r
264 int length = data.Length;
\r
266 Debug.Assert( Fourier.IsPowerOf2( length ) == true );
\r
267 Debug.Assert( length >= cMinLength );
\r
268 Debug.Assert( length <= cMaxLength );
\r
270 int[] reversedBits = Fourier.GetReversedBits( Fourier.Log2( length ) );
\r
271 for( int i = 0; i < length; i ++ ) {
\r
272 int swap = reversedBits[ i ];
\r
274 Complex temp = data[ i ];
\r
275 data[ i ] = data[ swap ];
\r
276 data[ swap ] = temp;
\r
281 static private void ReorderArray( ComplexF[] data ) {
\r
282 Debug.Assert( data != null );
\r
284 int length = data.Length;
\r
286 Debug.Assert( Fourier.IsPowerOf2( length ) == true );
\r
287 Debug.Assert( length >= cMinLength );
\r
288 Debug.Assert( length <= cMaxLength );
\r
290 int[] reversedBits = Fourier.GetReversedBits( Fourier.Log2( length ) );
\r
291 for( int i = 0; i < length; i ++ ) {
\r
292 int swap = reversedBits[ i ];
\r
294 ComplexF temp = data[ i ];
\r
295 data[ i ] = data[ swap ];
\r
296 data[ swap ] = temp;
\r
301 //======================================================================================
\r
303 private static int[][] _reverseBits = null;
\r
305 private static int _ReverseBits( int bits, int n ) {
\r
306 int bitsReversed = 0;
\r
307 for( int i = 0; i < n; i ++ ) {
\r
308 bitsReversed = ( bitsReversed << 1 ) | ( bits & 1 );
\r
309 bits = ( bits >> 1 );
\r
311 return bitsReversed;
\r
314 private static void InitializeReverseBits( int levels ) {
\r
315 _reverseBits = new int[levels + 1][];
\r
316 for( int j = 0; j < ( levels + 1 ); j ++ ) {
\r
317 int count = (int) Math.Pow( 2, j );
\r
318 _reverseBits[j] = new int[ count ];
\r
319 for( int i = 0; i < count; i ++ ) {
\r
320 _reverseBits[j][i] = _ReverseBits( i, j );
\r
325 private static int _lookupTabletLength = -1;
\r
326 private static double[,][] _uRLookup = null;
\r
327 private static double[,][] _uILookup = null;
\r
328 private static float[,][] _uRLookupF = null;
\r
329 private static float[,][] _uILookupF = null;
\r
331 private static void SyncLookupTableLength( int length ) {
\r
332 Debug.Assert( length < 1024*10 );
\r
333 Debug.Assert( length >= 0 );
\r
334 if( length > _lookupTabletLength ) {
\r
335 int level = (int) Math.Ceiling( Math.Log( length, 2 ) );
\r
336 Fourier.InitializeReverseBits( level );
\r
337 Fourier.InitializeComplexRotations( level );
\r
338 //_cFFTData = new Complex[ Math2.CeilingBase( length, 2 ) ];
\r
339 //_cFFTDataF = new ComplexF[ Math2.CeilingBase( length, 2 ) ];
\r
340 _lookupTabletLength = length;
\r
344 private static int GetLookupTableLength() {
\r
345 return _lookupTabletLength;
\r
348 private static void ClearLookupTables() {
\r
353 _lookupTabletLength = -1;
\r
356 private static void InitializeComplexRotations( int levels ) {
\r
358 //_wRLookup = new float[ levels + 1, 2 ];
\r
359 //_wILookup = new float[ levels + 1, 2 ];
\r
361 _uRLookup = new double[ levels + 1, 2 ][];
\r
362 _uILookup = new double[ levels + 1, 2 ][];
\r
364 _uRLookupF = new float[ levels + 1, 2 ][];
\r
365 _uILookupF = new float[ levels + 1, 2 ][];
\r
368 for( int level = 1; level <= ln; level ++ ) {
\r
372 //float scale = (float)( 1 / Math.Sqrt( 1 << ln ) );
\r
374 // positive sign ( i.e. [M,0] )
\r
378 double angle = (double) Math.PI / M * 1;
\r
379 double wR = (double) Math.Cos( angle );
\r
380 double wI = (double) Math.Sin( angle );
\r
382 _uRLookup[level,0] = new double[ M ];
\r
383 _uILookup[level,0] = new double[ M ];
\r
384 _uRLookupF[level,0] = new float[ M ];
\r
385 _uILookupF[level,0] = new float[ M ];
\r
387 for( int j = 0; j < M; j ++ ) {
\r
388 _uRLookupF[level,0][j] = (float)( _uRLookup[level,0][j] = uR );
\r
389 _uILookupF[level,0][j] = (float)( _uILookup[level,0][j] = uI );
\r
390 double uwI = uR*wI + uI*wR;
\r
391 uR = uR*wR - uI*wI;
\r
398 // negative sign ( i.e. [M,1] )
\r
401 double angle = (double) Math.PI / M * -1;
\r
402 double wR = (double) Math.Cos( angle );
\r
403 double wI = (double) Math.Sin( angle );
\r
405 _uRLookup[level,1] = new double[ M ];
\r
406 _uILookup[level,1] = new double[ M ];
\r
407 _uRLookupF[level,1] = new float[ M ];
\r
408 _uILookupF[level,1] = new float[ M ];
\r
410 for( int j = 0; j < M; j ++ ) {
\r
411 _uRLookupF[level,1][j] = (float)( _uRLookup[level,1][j] = uR );
\r
412 _uILookupF[level,1][j] = (float)( _uILookup[level,1][j] = uI );
\r
413 double uwI = uR*wI + uI*wR;
\r
414 uR = uR*wR - uI*wI;
\r
422 //======================================================================================
\r
423 //======================================================================================
\r
425 static private bool _bufferFLocked = false;
\r
426 static private float[] _bufferF = new float[ 0 ];
\r
428 static private void LockBufferF( int length, ref float[] buffer ) {
\r
429 Debug.Assert( _bufferFLocked == false );
\r
430 _bufferFLocked = true;
\r
431 if( length >= _bufferF.Length ) {
\r
432 _bufferF = new float[ length ];
\r
436 static private void UnlockBufferF( ref float[] buffer ) {
\r
437 Debug.Assert( _bufferF == buffer );
\r
438 Debug.Assert( _bufferFLocked == true );
\r
439 _bufferFLocked = false;
\r
443 private static void LinearFFT( float[] data, int start, int inc, int length, FourierDirection direction ) {
\r
444 Debug.Assert( data != null );
\r
445 Debug.Assert( start >= 0 );
\r
446 Debug.Assert( inc >= 1 );
\r
447 Debug.Assert( length >= 1 );
\r
448 Debug.Assert( ( start + inc * ( length - 1 ) ) * 2 < data.Length );
\r
451 float[] buffer = null;
\r
452 LockBufferF( length * 2, ref buffer );
\r
454 for( int i = 0; i < length * 2; i ++ ) {
\r
455 buffer[ i ] = data[ j ];
\r
459 FFT( buffer, length, direction );
\r
461 // copy from buffer
\r
463 for( int i = 0; i < length; i ++ ) {
\r
464 data[ j ] = buffer[ i ];
\r
467 UnlockBufferF( ref buffer );
\r
470 private static void LinearFFT_Quick( float[] data, int start, int inc, int length, FourierDirection direction ) {
\r
471 /*Debug.Assert( data != null );
\r
472 Debug.Assert( start >= 0 );
\r
473 Debug.Assert( inc >= 1 );
\r
474 Debug.Assert( length >= 1 );
\r
475 Debug.Assert( ( start + inc * ( length - 1 ) ) * 2 < data.Length );*/
\r
478 float[] buffer = null;
\r
479 LockBufferF( length * 2, ref buffer );
\r
481 for( int i = 0; i < length * 2; i ++ ) {
\r
482 buffer[ i ] = data[ j ];
\r
486 FFT_Quick( buffer, length, direction );
\r
488 // copy from buffer
\r
490 for( int i = 0; i < length; i ++ ) {
\r
491 data[ j ] = buffer[ i ];
\r
494 UnlockBufferF( ref buffer );
\r
497 //======================================================================================
\r
498 //======================================================================================
\r
500 static private bool _bufferCFLocked = false;
\r
501 static private ComplexF[] _bufferCF = new ComplexF[ 0 ];
\r
503 static private void LockBufferCF( int length, ref ComplexF[] buffer ) {
\r
504 Debug.Assert( length >= 0 );
\r
505 Debug.Assert( _bufferCFLocked == false );
\r
507 _bufferCFLocked = true;
\r
508 if( length != _bufferCF.Length ) {
\r
509 _bufferCF = new ComplexF[ length ];
\r
511 buffer = _bufferCF;
\r
513 static private void UnlockBufferCF( ref ComplexF[] buffer ) {
\r
514 Debug.Assert( _bufferCF == buffer );
\r
515 Debug.Assert( _bufferCFLocked == true );
\r
517 _bufferCFLocked = false;
\r
521 private static void LinearFFT( ComplexF[] data, int start, int inc, int length, FourierDirection direction ) {
\r
522 Debug.Assert( data != null );
\r
523 Debug.Assert( start >= 0 );
\r
524 Debug.Assert( inc >= 1 );
\r
525 Debug.Assert( length >= 1 );
\r
526 Debug.Assert( ( start + inc * ( length - 1 ) ) < data.Length );
\r
529 ComplexF[] buffer = null;
\r
530 LockBufferCF( length, ref buffer );
\r
532 for( int i = 0; i < length; i ++ ) {
\r
533 buffer[ i ] = data[ j ];
\r
537 FFT( buffer, length, direction );
\r
539 // copy from buffer
\r
541 for( int i = 0; i < length; i ++ ) {
\r
542 data[ j ] = buffer[ i ];
\r
545 UnlockBufferCF( ref buffer );
\r
548 private static void LinearFFT_Quick( ComplexF[] data, int start, int inc, int length, FourierDirection direction ) {
\r
549 /*Debug.Assert( data != null );
\r
550 Debug.Assert( start >= 0 );
\r
551 Debug.Assert( inc >= 1 );
\r
552 Debug.Assert( length >= 1 );
\r
553 Debug.Assert( ( start + inc * ( length - 1 ) ) < data.Length ); */
\r
556 ComplexF[] buffer = null;
\r
557 LockBufferCF( length, ref buffer );
\r
559 for( int i = 0; i < length; i ++ ) {
\r
560 buffer[ i ] = data[ j ];
\r
564 FFT( buffer, length, direction );
\r
566 // copy from buffer
\r
568 for( int i = 0; i < length; i ++ ) {
\r
569 data[ j ] = buffer[ i ];
\r
572 UnlockBufferCF( ref buffer );
\r
575 //======================================================================================
\r
576 //======================================================================================
\r
578 static private bool _bufferCLocked = false;
\r
579 static private Complex[] _bufferC = new Complex[ 0 ];
\r
581 static private void LockBufferC( int length, ref Complex[] buffer ) {
\r
582 Debug.Assert( length >= 0 );
\r
583 Debug.Assert( _bufferCLocked == false );
\r
585 _bufferCLocked = true;
\r
586 if( length >= _bufferC.Length ) {
\r
587 _bufferC = new Complex[ length ];
\r
591 static private void UnlockBufferC( ref Complex[] buffer ) {
\r
592 Debug.Assert( _bufferC == buffer );
\r
593 Debug.Assert( _bufferCLocked == true );
\r
595 _bufferCLocked = false;
\r
599 private static void LinearFFT( Complex[] data, int start, int inc, int length, FourierDirection direction ) {
\r
600 Debug.Assert( data != null );
\r
601 Debug.Assert( start >= 0 );
\r
602 Debug.Assert( inc >= 1 );
\r
603 Debug.Assert( length >= 1 );
\r
604 Debug.Assert( ( start + inc * ( length - 1 ) ) < data.Length );
\r
607 Complex[] buffer = null;
\r
608 LockBufferC( length, ref buffer );
\r
610 for( int i = 0; i < length; i ++ ) {
\r
611 buffer[ i ] = data[ j ];
\r
615 FFT( buffer, length, direction );
\r
617 // copy from buffer
\r
619 for( int i = 0; i < length; i ++ ) {
\r
620 data[ j ] = buffer[ i ];
\r
623 UnlockBufferC( ref buffer );
\r
626 private static void LinearFFT_Quick( Complex[] data, int start, int inc, int length, FourierDirection direction ) {
\r
627 /*Debug.Assert( data != null );
\r
628 Debug.Assert( start >= 0 );
\r
629 Debug.Assert( inc >= 1 );
\r
630 Debug.Assert( length >= 1 );
\r
631 Debug.Assert( ( start + inc * ( length - 1 ) ) < data.Length );*/
\r
634 Complex[] buffer = null;
\r
635 LockBufferC( length, ref buffer );
\r
637 for( int i = 0; i < length; i ++ ) {
\r
638 buffer[ i ] = data[ j ];
\r
642 FFT_Quick( buffer, length, direction );
\r
644 // copy from buffer
\r
646 for( int i = 0; i < length; i ++ ) {
\r
647 data[ j ] = buffer[ i ];
\r
650 UnlockBufferC( ref buffer );
\r
653 //======================================================================================
\r
654 //======================================================================================
\r
657 /// Compute a 1D fast Fourier transform of a dataset of complex numbers (as pairs of float's).
\r
659 /// <param name="data"></param>
\r
660 /// <param name="length"></param>
\r
661 /// <param name="direction"></param>
\r
662 public static void FFT( float[] data, int length, FourierDirection direction ) {
\r
663 Debug.Assert( data != null );
\r
664 Debug.Assert( data.Length >= length*2 );
\r
665 Debug.Assert( Fourier.IsPowerOf2( length ) == true );
\r
667 Fourier.SyncLookupTableLength( length );
\r
669 int ln = Fourier.Log2( length );
\r
672 Fourier.ReorderArray( data );
\r
674 // successive doubling
\r
676 int signIndex = ( direction == FourierDirection.Forward ) ? 0 : 1;
\r
677 for( int level = 1; level <= ln; level ++ ) {
\r
681 float[] uRLookup = _uRLookupF[ level, signIndex ];
\r
682 float[] uILookup = _uILookupF[ level, signIndex ];
\r
684 for( int j = 0; j < M; j ++ ) {
\r
685 float uR = uRLookup[j];
\r
686 float uI = uILookup[j];
\r
688 for( int evenT = j; evenT < length; evenT += N ) {
\r
689 int even = evenT << 1;
\r
690 int odd = ( evenT + M ) << 1;
\r
692 float r = data[ odd ];
\r
693 float i = data[ odd+1 ];
\r
695 float odduR = r * uR - i * uI;
\r
696 float odduI = r * uI + i * uR;
\r
699 i = data[ even+1 ];
\r
701 data[ even ] = r + odduR;
\r
702 data[ even+1 ] = i + odduI;
\r
704 data[ odd ] = r - odduR;
\r
705 data[ odd+1 ] = i - odduI;
\r
712 /// Compute a 1D fast Fourier transform of a dataset of complex numbers (as pairs of float's).
\r
714 /// <param name="data"></param>
\r
715 /// <param name="length"></param>
\r
716 /// <param name="direction"></param>
\r
717 public static void FFT_Quick( float[] data, int length, FourierDirection direction ) {
\r
718 /*Debug.Assert( data != null );
\r
719 Debug.Assert( data.Length >= length*2 );
\r
720 Debug.Assert( Fourier.IsPowerOf2( length ) == true );
\r
722 Fourier.SyncLookupTableLength( length );*/
\r
724 int ln = Fourier.Log2( length );
\r
727 Fourier.ReorderArray( data );
\r
729 // successive doubling
\r
731 int signIndex = ( direction == FourierDirection.Forward ) ? 0 : 1;
\r
732 for( int level = 1; level <= ln; level ++ ) {
\r
736 float[] uRLookup = _uRLookupF[ level, signIndex ];
\r
737 float[] uILookup = _uILookupF[ level, signIndex ];
\r
739 for( int j = 0; j < M; j ++ ) {
\r
740 float uR = uRLookup[j];
\r
741 float uI = uILookup[j];
\r
743 for( int evenT = j; evenT < length; evenT += N ) {
\r
744 int even = evenT << 1;
\r
745 int odd = ( evenT + M ) << 1;
\r
747 float r = data[ odd ];
\r
748 float i = data[ odd+1 ];
\r
750 float odduR = r * uR - i * uI;
\r
751 float odduI = r * uI + i * uR;
\r
754 i = data[ even+1 ];
\r
756 data[ even ] = r + odduR;
\r
757 data[ even+1 ] = i + odduI;
\r
759 data[ odd ] = r - odduR;
\r
760 data[ odd+1 ] = i - odduI;
\r
767 /// Compute a 1D fast Fourier transform of a dataset of complex numbers.
\r
769 /// <param name="data"></param>
\r
770 /// <param name="length"></param>
\r
771 /// <param name="direction"></param>
\r
772 public static void FFT( ComplexF[] data, int length, FourierDirection direction ) {
\r
773 if( data == null ) {
\r
774 throw new ArgumentNullException( "data" );
\r
776 if( data.Length < length ) {
\r
777 throw new ArgumentOutOfRangeException( "length", length, "must be at least as large as 'data.Length' parameter" );
\r
779 if( Fourier.IsPowerOf2( length ) == false ) {
\r
780 throw new ArgumentOutOfRangeException( "length", length, "must be a power of 2" );
\r
783 Fourier.SyncLookupTableLength( length );
\r
785 int ln = Fourier.Log2( length );
\r
788 Fourier.ReorderArray( data );
\r
790 // successive doubling
\r
792 int signIndex = ( direction == FourierDirection.Forward ) ? 0 : 1;
\r
794 for( int level = 1; level <= ln; level ++ ) {
\r
798 float[] uRLookup = _uRLookupF[ level, signIndex ];
\r
799 float[] uILookup = _uILookupF[ level, signIndex ];
\r
801 for( int j = 0; j < M; j ++ ) {
\r
802 float uR = uRLookup[j];
\r
803 float uI = uILookup[j];
\r
805 for( int even = j; even < length; even += N ) {
\r
806 int odd = even + M;
\r
808 float r = data[ odd ].Re;
\r
809 float i = data[ odd ].Im;
\r
811 float odduR = r * uR - i * uI;
\r
812 float odduI = r * uI + i * uR;
\r
814 r = data[ even ].Re;
\r
815 i = data[ even ].Im;
\r
817 data[ even ].Re = r + odduR;
\r
818 data[ even ].Im = i + odduI;
\r
820 data[ odd ].Re = r - odduR;
\r
821 data[ odd ].Im = i - odduI;
\r
829 /// Compute a 1D fast Fourier transform of a dataset of complex numbers.
\r
831 /// <param name="data"></param>
\r
832 /// <param name="length"></param>
\r
833 /// <param name="direction"></param>
\r
834 public static void FFT_Quick( ComplexF[] data, int length, FourierDirection direction ) {
\r
835 /*if( data == null ) {
\r
836 throw new ArgumentNullException( "data" );
\r
838 if( data.Length < length ) {
\r
839 throw new ArgumentOutOfRangeException( "length", length, "must be at least as large as 'data.Length' parameter" );
\r
841 if( Fourier.IsPowerOf2( length ) == false ) {
\r
842 throw new ArgumentOutOfRangeException( "length", length, "must be a power of 2" );
\r
845 Fourier.SyncLookupTableLength( length );*/
\r
847 int ln = Fourier.Log2( length );
\r
850 Fourier.ReorderArray( data );
\r
852 // successive doubling
\r
854 int signIndex = ( direction == FourierDirection.Forward ) ? 0 : 1;
\r
856 for( int level = 1; level <= ln; level ++ ) {
\r
860 float[] uRLookup = _uRLookupF[ level, signIndex ];
\r
861 float[] uILookup = _uILookupF[ level, signIndex ];
\r
863 for( int j = 0; j < M; j ++ ) {
\r
864 float uR = uRLookup[j];
\r
865 float uI = uILookup[j];
\r
867 for( int even = j; even < length; even += N ) {
\r
868 int odd = even + M;
\r
870 float r = data[ odd ].Re;
\r
871 float i = data[ odd ].Im;
\r
873 float odduR = r * uR - i * uI;
\r
874 float odduI = r * uI + i * uR;
\r
876 r = data[ even ].Re;
\r
877 i = data[ even ].Im;
\r
879 data[ even ].Re = r + odduR;
\r
880 data[ even ].Im = i + odduI;
\r
882 data[ odd ].Re = r - odduR;
\r
883 data[ odd ].Im = i - odduI;
\r
891 /// Compute a 1D fast Fourier transform of a dataset of complex numbers.
\r
893 /// <param name="data"></param>
\r
894 /// <param name="direction"></param>
\r
895 public static void FFT( ComplexF[] data, FourierDirection direction ) {
\r
896 if( data == null ) {
\r
897 throw new ArgumentNullException( "data" );
\r
899 Fourier.FFT( data, data.Length, direction );
\r
903 /// Compute a 1D fast Fourier transform of a dataset of complex numbers.
\r
905 /// <param name="data"></param>
\r
906 /// <param name="length"></param>
\r
907 /// <param name="direction"></param>
\r
908 public static void FFT( Complex[] data, int length, FourierDirection direction ) {
\r
909 if( data == null ) {
\r
910 throw new ArgumentNullException( "data" );
\r
912 if( data.Length < length ) {
\r
913 throw new ArgumentOutOfRangeException( "length", length, "must be at least as large as 'data.Length' parameter" );
\r
915 if( Fourier.IsPowerOf2( length ) == false ) {
\r
916 throw new ArgumentOutOfRangeException( "length", length, "must be a power of 2" );
\r
919 Fourier.SyncLookupTableLength( length );
\r
921 int ln = Fourier.Log2( length );
\r
924 Fourier.ReorderArray( data );
\r
926 // successive doubling
\r
928 int signIndex = ( direction == FourierDirection.Forward ) ? 0 : 1;
\r
930 for( int level = 1; level <= ln; level ++ ) {
\r
934 double[] uRLookup = _uRLookup[ level, signIndex ];
\r
935 double[] uILookup = _uILookup[ level, signIndex ];
\r
937 for( int j = 0; j < M; j ++ ) {
\r
938 double uR = uRLookup[j];
\r
939 double uI = uILookup[j];
\r
941 for( int even = j; even < length; even += N ) {
\r
942 int odd = even + M;
\r
944 double r = data[ odd ].Re;
\r
945 double i = data[ odd ].Im;
\r
947 double odduR = r * uR - i * uI;
\r
948 double odduI = r * uI + i * uR;
\r
950 r = data[ even ].Re;
\r
951 i = data[ even ].Im;
\r
953 data[ even ].Re = r + odduR;
\r
954 data[ even ].Im = i + odduI;
\r
956 data[ odd ].Re = r - odduR;
\r
957 data[ odd ].Im = i - odduI;
\r
965 /// Compute a 1D fast Fourier transform of a dataset of complex numbers.
\r
967 /// <param name="data"></param>
\r
968 /// <param name="length"></param>
\r
969 /// <param name="direction"></param>
\r
970 public static void FFT_Quick( Complex[] data, int length, FourierDirection direction ) {
\r
971 /*if( data == null ) {
\r
972 throw new ArgumentNullException( "data" );
\r
974 if( data.Length < length ) {
\r
975 throw new ArgumentOutOfRangeException( "length", length, "must be at least as large as 'data.Length' parameter" );
\r
977 if( Fourier.IsPowerOf2( length ) == false ) {
\r
978 throw new ArgumentOutOfRangeException( "length", length, "must be a power of 2" );
\r
981 Fourier.SyncLookupTableLength( length ); */
\r
983 int ln = Fourier.Log2( length );
\r
986 Fourier.ReorderArray( data );
\r
988 // successive doubling
\r
990 int signIndex = ( direction == FourierDirection.Forward ) ? 0 : 1;
\r
992 for( int level = 1; level <= ln; level ++ ) {
\r
996 double[] uRLookup = _uRLookup[ level, signIndex ];
\r
997 double[] uILookup = _uILookup[ level, signIndex ];
\r
999 for( int j = 0; j < M; j ++ ) {
\r
1000 double uR = uRLookup[j];
\r
1001 double uI = uILookup[j];
\r
1003 for( int even = j; even < length; even += N ) {
\r
1004 int odd = even + M;
\r
1006 double r = data[ odd ].Re;
\r
1007 double i = data[ odd ].Im;
\r
1009 double odduR = r * uR - i * uI;
\r
1010 double odduI = r * uI + i * uR;
\r
1012 r = data[ even ].Re;
\r
1013 i = data[ even ].Im;
\r
1015 data[ even ].Re = r + odduR;
\r
1016 data[ even ].Im = i + odduI;
\r
1018 data[ odd ].Re = r - odduR;
\r
1019 data[ odd ].Im = i - odduI;
\r
1027 /// Compute a 1D real-symmetric fast fourier transform.
\r
1029 /// <param name="data"></param>
\r
1030 /// <param name="direction"></param>
\r
1031 public static void RFFT( float[] data, FourierDirection direction ) {
\r
1032 if( data == null ) {
\r
1033 throw new ArgumentNullException( "data" );
\r
1035 Fourier.RFFT( data, data.Length, direction );
\r
1039 /// Compute a 1D real-symmetric fast fourier transform.
\r
1041 /// <param name="data"></param>
\r
1042 /// <param name="length"></param>
\r
1043 /// <param name="direction"></param>
\r
1044 public static void RFFT( float[] data, int length, FourierDirection direction ) {
\r
1045 if( data == null ) {
\r
1046 throw new ArgumentNullException( "data" );
\r
1048 if( data.Length < length ) {
\r
1049 throw new ArgumentOutOfRangeException( "length", length, "must be at least as large as 'data.Length' parameter" );
\r
1051 if( Fourier.IsPowerOf2( length ) == false ) {
\r
1052 throw new ArgumentOutOfRangeException( "length", length, "must be a power of 2" );
\r
1055 float c1 = 0.5f, c2;
\r
1056 float theta = (float) Math.PI / (length/2);
\r
1058 if( direction == FourierDirection.Forward ) {
\r
1060 FFT( data, length/2, direction );
\r
1067 float wtemp = (float) Math.Sin( 0.5*theta );
\r
1068 float wpr = -2 * wtemp*wtemp;
\r
1069 float wpi =(float) Math.Sin( theta );
\r
1070 float wr = 1 + wpr;
\r
1073 // do / undo packing
\r
1074 for( int i = 1; i < length/4; i ++ ) {
\r
1076 int b = length - 2*i;
\r
1077 float h1r = c1 * ( data[ a ] + data[ b ] );
\r
1078 float h1i = c1 * ( data[ a+1 ] - data[ b+1 ] );
\r
1079 float h2r = -c2 * ( data[ a+1 ] + data[ b+1 ] );
\r
1080 float h2i = c2 * ( data[ a ] - data[ b ] );
\r
1081 data[ a ] = h1r + wr*h2r - wi*h2i;
\r
1082 data[ a+1 ] = h1i + wr*h2i + wi*h2r;
\r
1083 data[ b ] = h1r - wr*h2r + wi*h2i;
\r
1084 data[ b+1 ] = -h1i + wr*h2i + wi*h2r;
\r
1085 wr = (wtemp = wr) * wpr - wi * wpi + wr;
\r
1086 wi = wi * wpr + wtemp * wpi + wi;
\r
1089 if( direction == FourierDirection.Forward ) {
\r
1090 float hir = data[0];
\r
1091 data[0] = hir + data[1];
\r
1092 data[1] = hir - data[1];
\r
1095 float hir = data[0];
\r
1096 data[0] = c1 * ( hir + data[1] );
\r
1097 data[1] = c1 * ( hir - data[1] );
\r
1098 Fourier.FFT( data, length/2, direction );
\r
1103 /// Compute a 2D fast fourier transform on a data set of complex numbers (represented as pairs of floats)
\r
1105 /// <param name="data"></param>
\r
1106 /// <param name="xLength"></param>
\r
1107 /// <param name="yLength"></param>
\r
1108 /// <param name="direction"></param>
\r
1109 public static void FFT2( float[] data, int xLength, int yLength, FourierDirection direction ) {
\r
1110 if( data == null ) {
\r
1111 throw new ArgumentNullException( "data" );
\r
1113 if( data.Length < xLength*yLength*2 ) {
\r
1114 throw new ArgumentOutOfRangeException( "data.Length", data.Length, "must be at least as large as 'xLength * yLength * 2' parameter" );
\r
1116 if( Fourier.IsPowerOf2( xLength ) == false ) {
\r
1117 throw new ArgumentOutOfRangeException( "xLength", xLength, "must be a power of 2" );
\r
1119 if( Fourier.IsPowerOf2( yLength ) == false ) {
\r
1120 throw new ArgumentOutOfRangeException( "yLength", yLength, "must be a power of 2" );
\r
1124 int yInc = xLength;
\r
1126 if( xLength > 1 ) {
\r
1127 Fourier.SyncLookupTableLength( xLength );
\r
1128 for( int y = 0; y < yLength; y ++ ) {
\r
1129 int xStart = y * yInc;
\r
1130 Fourier.LinearFFT_Quick( data, xStart, xInc, xLength, direction );
\r
1134 if( yLength > 1 ) {
\r
1135 Fourier.SyncLookupTableLength( yLength );
\r
1136 for( int x = 0; x < xLength; x ++ ) {
\r
1137 int yStart = x * xInc;
\r
1138 Fourier.LinearFFT_Quick( data, yStart, yInc, yLength, direction );
\r
1144 /// Compute a 2D fast fourier transform on a data set of complex numbers
\r
1146 /// <param name="data"></param>
\r
1147 /// <param name="xLength"></param>
\r
1148 /// <param name="yLength"></param>
\r
1149 /// <param name="direction"></param>
\r
1150 public static void FFT2( ComplexF[] data, int xLength, int yLength, FourierDirection direction ) {
\r
1151 if( data == null ) {
\r
1152 throw new ArgumentNullException( "data" );
\r
1154 if( data.Length < xLength*yLength ) {
\r
1155 throw new ArgumentOutOfRangeException( "data.Length", data.Length, "must be at least as large as 'xLength * yLength' parameter" );
\r
1157 if( Fourier.IsPowerOf2( xLength ) == false ) {
\r
1158 throw new ArgumentOutOfRangeException( "xLength", xLength, "must be a power of 2" );
\r
1160 if( Fourier.IsPowerOf2( yLength ) == false ) {
\r
1161 throw new ArgumentOutOfRangeException( "yLength", yLength, "must be a power of 2" );
\r
1165 int yInc = xLength;
\r
1167 if( xLength > 1 ) {
\r
1168 Fourier.SyncLookupTableLength( xLength );
\r
1169 for( int y = 0; y < yLength; y ++ ) {
\r
1170 int xStart = y * yInc;
\r
1171 Fourier.LinearFFT_Quick( data, xStart, xInc, xLength, direction );
\r
1175 if( yLength > 1 ) {
\r
1176 Fourier.SyncLookupTableLength( yLength );
\r
1177 for( int x = 0; x < xLength; x ++ ) {
\r
1178 int yStart = x * xInc;
\r
1179 Fourier.LinearFFT_Quick( data, yStart, yInc, yLength, direction );
\r
1185 /// Compute a 2D fast fourier transform on a data set of complex numbers
\r
1187 /// <param name="data"></param>
\r
1188 /// <param name="xLength"></param>
\r
1189 /// <param name="yLength"></param>
\r
1190 /// <param name="direction"></param>
\r
1191 public static void FFT2( Complex[] data, int xLength, int yLength, FourierDirection direction ) {
\r
1192 if( data == null ) {
\r
1193 throw new ArgumentNullException( "data" );
\r
1195 if( data.Length < xLength*yLength ) {
\r
1196 throw new ArgumentOutOfRangeException( "data.Length", data.Length, "must be at least as large as 'xLength * yLength' parameter" );
\r
1198 if( Fourier.IsPowerOf2( xLength ) == false ) {
\r
1199 throw new ArgumentOutOfRangeException( "xLength", xLength, "must be a power of 2" );
\r
1201 if( Fourier.IsPowerOf2( yLength ) == false ) {
\r
1202 throw new ArgumentOutOfRangeException( "yLength", yLength, "must be a power of 2" );
\r
1206 int yInc = xLength;
\r
1208 if( xLength > 1 ) {
\r
1209 Fourier.SyncLookupTableLength( xLength );
\r
1210 for( int y = 0; y < yLength; y ++ ) {
\r
1211 int xStart = y * yInc;
\r
1212 Fourier.LinearFFT_Quick( data, xStart, xInc, xLength, direction );
\r
1216 if( yLength > 1 ) {
\r
1217 Fourier.SyncLookupTableLength( yLength );
\r
1218 for( int x = 0; x < xLength; x ++ ) {
\r
1219 int yStart = x * xInc;
\r
1220 Fourier.LinearFFT_Quick( data, yStart, yInc, yLength, direction );
\r
1226 /// Compute a 3D fast fourier transform on a data set of complex numbers
\r
1228 /// <param name="data"></param>
\r
1229 /// <param name="xLength"></param>
\r
1230 /// <param name="yLength"></param>
\r
1231 /// <param name="zLength"></param>
\r
1232 /// <param name="direction"></param>
\r
1233 public static void FFT3( ComplexF[] data, int xLength, int yLength, int zLength, FourierDirection direction ) {
\r
1234 if( data == null ) {
\r
1235 throw new ArgumentNullException( "data" );
\r
1237 if( data.Length < xLength*yLength*zLength ) {
\r
1238 throw new ArgumentOutOfRangeException( "data.Length", data.Length, "must be at least as large as 'xLength * yLength * zLength' parameter" );
\r
1240 if( Fourier.IsPowerOf2( xLength ) == false ) {
\r
1241 throw new ArgumentOutOfRangeException( "xLength", xLength, "must be a power of 2" );
\r
1243 if( Fourier.IsPowerOf2( yLength ) == false ) {
\r
1244 throw new ArgumentOutOfRangeException( "yLength", yLength, "must be a power of 2" );
\r
1246 if( Fourier.IsPowerOf2( zLength ) == false ) {
\r
1247 throw new ArgumentOutOfRangeException( "zLength", zLength, "must be a power of 2" );
\r
1251 int yInc = xLength;
\r
1252 int zInc = xLength * yLength;
\r
1254 if( xLength > 1 ) {
\r
1255 Fourier.SyncLookupTableLength( xLength );
\r
1256 for( int z = 0; z < zLength; z ++ ) {
\r
1257 for( int y = 0; y < yLength; y ++ ) {
\r
1258 int xStart = y * yInc + z * zInc;
\r
1259 Fourier.LinearFFT_Quick( data, xStart, xInc, xLength, direction );
\r
1264 if( yLength > 1 ) {
\r
1265 Fourier.SyncLookupTableLength( yLength );
\r
1266 for( int z = 0; z < zLength; z ++ ) {
\r
1267 for( int x = 0; x < xLength; x ++ ) {
\r
1268 int yStart = z * zInc + x * xInc;
\r
1269 Fourier.LinearFFT_Quick( data, yStart, yInc, yLength, direction );
\r
1274 if( zLength > 1 ) {
\r
1275 Fourier.SyncLookupTableLength( zLength );
\r
1276 for( int y = 0; y < yLength; y ++ ) {
\r
1277 for( int x = 0; x < xLength; x ++ ) {
\r
1278 int zStart = y * yInc + x * xInc;
\r
1279 Fourier.LinearFFT_Quick( data, zStart, zInc, zLength, direction );
\r
1286 /// Compute a 3D fast fourier transform on a data set of complex numbers
\r
1288 /// <param name="data"></param>
\r
1289 /// <param name="xLength"></param>
\r
1290 /// <param name="yLength"></param>
\r
1291 /// <param name="zLength"></param>
\r
1292 /// <param name="direction"></param>
\r
1293 public static void FFT3( Complex[] data, int xLength, int yLength, int zLength, FourierDirection direction ) {
\r
1294 if( data == null ) {
\r
1295 throw new ArgumentNullException( "data" );
\r
1297 if( data.Length < xLength*yLength*zLength ) {
\r
1298 throw new ArgumentOutOfRangeException( "data.Length", data.Length, "must be at least as large as 'xLength * yLength * zLength' parameter" );
\r
1300 if( Fourier.IsPowerOf2( xLength ) == false ) {
\r
1301 throw new ArgumentOutOfRangeException( "xLength", xLength, "must be a power of 2" );
\r
1303 if( Fourier.IsPowerOf2( yLength ) == false ) {
\r
1304 throw new ArgumentOutOfRangeException( "yLength", yLength, "must be a power of 2" );
\r
1306 if( Fourier.IsPowerOf2( zLength ) == false ) {
\r
1307 throw new ArgumentOutOfRangeException( "zLength", zLength, "must be a power of 2" );
\r
1311 int yInc = xLength;
\r
1312 int zInc = xLength * yLength;
\r
1314 if( xLength > 1 ) {
\r
1315 Fourier.SyncLookupTableLength( xLength );
\r
1316 for( int z = 0; z < zLength; z ++ ) {
\r
1317 for( int y = 0; y < yLength; y ++ ) {
\r
1318 int xStart = y * yInc + z * zInc;
\r
1319 Fourier.LinearFFT_Quick( data, xStart, xInc, xLength, direction );
\r
1324 if( yLength > 1 ) {
\r
1325 Fourier.SyncLookupTableLength( yLength );
\r
1326 for( int z = 0; z < zLength; z ++ ) {
\r
1327 for( int x = 0; x < xLength; x ++ ) {
\r
1328 int yStart = z * zInc + x * xInc;
\r
1329 Fourier.LinearFFT_Quick( data, yStart, yInc, yLength, direction );
\r
1334 if( zLength > 1 ) {
\r
1335 Fourier.SyncLookupTableLength( zLength );
\r
1336 for( int y = 0; y < yLength; y ++ ) {
\r
1337 for( int x = 0; x < xLength; x ++ ) {
\r
1338 int zStart = y * yInc + x * xInc;
\r
1339 Fourier.LinearFFT_Quick( data, zStart, zInc, zLength, direction );
\r