/////////////////////////////////////////////////////////////////////////// // Hansi's FFT-Klasse // // (C) 1997 Hansi Reiser, dl9rdz, hsreiser@stud.informatik.uni-erlangen.de // // C++ class for a fast computation of DFT-transforms // // partly derived from: // - my own FFT-routines, (C) 1995 Hansi Reiser // - split-radix-algorithm by H.V. Sorensen, University of Pennsylavania, // hvs@ee.upenn.edu (1987) // - C++ - interface inspired by Jan Ernst's dft.C // // Reference: // - Sanjit K. Mitra, James F. Kaiser: Handbook for Digital Signal // Processing, Jung Wiley&Sons Inc. // - Richard E. Blahut, Algebraic Methods for Signal Processing and // Communications Coding, Springer Verlag // - Sorensen, Heideman, Burrus: "On Computing the split-radix FFT", // IEEE Trans. ASSP, ASSP-34, No. 1, pp 152-156 // - Sorensen, Jones, Heideman, Burrus: "Real-Valued fast Fourier // transform algorithms", IEEE Trans. ASSP, ASSP-35, No. 6, pp 849-864 // // This FFT class is provided AS IS and WITHOUT any WARRENTY or FITNESS // FOR A PARTICULAR PURPOSE // This program may be used and distributed freely provided this header // is included and left intact. /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// // Usage: // The constructor creates an FFT-object for a specific transform length, // several precomputations of often-used values are done upon creation, // which may take some time. therefor, if several transforms of the same // lengths are needed, it is advisable to instantiate on FFT-object for // this length once, and then use that one for all transforms being // perforemd. // // All Transform length NOT a power of 2 are done by the stupid O(N^2) // DFT algorithm. In most cases you could do much better there by other // methods, like the Good-Thomas or Winograd FFT algorithms, mostly based // on the Chinese Remainder Theorem. This package only has been optimized // for transform of length 2^N. Those are perfomed by an highly efficient // split-radix algorithm. // Further-optimized algorithms for computing the FFT of real-valued input // are provided, requiring half the time of complex FFT of same length. // // Basic operations provided: // Vector * FFTer -> Vector performs FFT // Vector / FFTer -> Vector performs inverse FFT // Vector * FFTer -> Vector performs FFT optimized // for real input // FFTer.fft( Vector ) performs in-place FFT // FFTer.ifft( Vector ) performs in-place inverse FFT // FFTer.rfft( Vector ) performs in-place real FFT, imag // parts of input assumed being 0 // Additional operations provided: // Vector * FFTer converted to Vector * FFTer // FFTer * Vector<...> converted to Vector<...> * FFTer // /////////////////////////////////////////////////////////////////////////// // vielleicht kann ja jemand was damit anfagen. wenn ned... macht a // nix :) ich hoff, daß keine allzu groben Bugs mehr drin sind. Der // große C++ - programmierer bin ich ned, drum kannma an dem dem klassen- // interface sicher no vieles besser machn, wenn jemandn was ned passt // kanners mir ja sagn. das ganze wurde unter linux mit der gnu ansi-c++ // libg++ entwicklet (klassen Complex und Vektor). gnu verwendet für // die exponentation statt dem XOR-Operator eine funktion namens pow, // und vector wird klein statt groß geschrieben, sonst sollts keine // größeren Unterschiede geben. (i hab jez nix gegen "`unsere"' complex- // klasse, aber i wolltmi ned lang damit beschäftigen wie man dem g++ // sagt die eigene NICHT zu verwenden :-) #include "hansis_fft.h" #include "stdio.h" #include "math.h" #include "stdlib.h" FFTer::FFTer( int l, int mod ) { int loop=2; // Testen, ob l=2^M ist, und ggf dieses M berechnen len=l; for( loop=2,M=1; loop FFTer::operator*( const Vector& fd ) { return fd * (*this); } Vector FFTer::operator*( const Vector& fd ) { return fd * (*this); } Vector FFTer::operator*( const Vector& fd ) { return fd * (*this); } #define CHECK_SIZE(fd,fft) \ if( int((fd).size()) < fft.len ) { \ fprintf(stderr, "DFT-Vector too small\n"); \ exit(1); \ } Vector operator*( const Vector& fd, const FFTer& fft ) { Vector fr(fft.len); CHECK_SIZE(fd,fft); if(fft.mode) return fft.dft( fd, 0 ); // normale DFT return fft.fftsr( fd ); // schnelle FFT } Vector operator*( const Vector& fd, const FFTer& fft ) { Vector fr(fft.len); CHECK_SIZE(fd,fft); if(fft.mode) return fft.dft( fd, 0 ); // normale DFT return fft.rfftsr( fd ); // schnelle FFT } Vector operator*( const Vector& fd, const FFTer& fft ) { Vector fr(fft.len); CHECK_SIZE(fd,fft); if(fft.mode) return fft.dft( fd, 0 ); // normale DFT return fft.rfftsr( fd ); // schnelle FFT } Vector operator/( const Vector& fd, const FFTer& fft ) { Vector fr(fft.len); CHECK_SIZE(fd, fft); if(fft.mode) return fft.dft( fd, 1 ); // normale inverse DFT return fft.ifftsr( fd ); // schnelle inverse FFT } #endif ////////////////////////////////////////////////////////////////////// //// private Hilfsfunktionen primitiv-DFT, für len != pow(2,M) ////////////////////////////////////////////////////////////////////// #if 0 void FFTer::dft_init() { Complex m(cos(2*M_PI/len), -sin(2*M_PI/len)); int i; Dm=new Complex[len]; for(i=0; i fr(len); for(i=0; i FFTer::dft( const Vector input, int invers ) const { int i, j; Vector fr(len); for(i=0; i>1; n4=n2>>2; fftsr_helper( n2, n4, its, x, x+n4, x+2*n4, x+3*n4, y, y+n4, y+2*n4, y+3*n4 ); its<<=1; } // End-"`Butterflies"' (die noch fehlenden Länge-2-Transformationen) i_start=0; i_delta=4; do { for(i=i_start; i>1; n4=n2>>2; ifftsr_helper(n2, n4, x, x+n4, x+2*n4, x+3*n4, y, y+n4, y+2*n4, y+3*n4); } // Letzte 2er-Stufe i_start=0; i_delta=4; do { for( i=i_start; i>2; rfftsr_helper(n2, n4, x, x+n4, x+2*n4, x+3*n4); } } void FFTer::rfftsr_helper( int n2, int n4, double *x1, double *x2, double *x3, double *x4) const { int n8=n2/8,i_start,i_delta,i,j,i2,jn; double tmp1,tmp2,tmp3,tmp4,tmp5; double E, SS1, SS3, SD1, SD3, CC1, CC3, CD1, CD3; i_start=0; i_delta=n2*2; do { for(i=i_start; i v(LEN), v2; Vector d(LEN); int i; printf("initalisieren...\n"); for(i=0; i