FFTW.cpp
Go to the documentation of this file.
00001 // This file is part of Eigen, a lightweight C++ template library
00002 // for linear algebra.
00003 //
00004 // Copyright (C) 2009 Mark Borgerding mark a borgerding net
00005 //
00006 // This Source Code Form is subject to the terms of the Mozilla
00007 // Public License v. 2.0. If a copy of the MPL was not distributed
00008 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
00009 
00010 #include "main.h"
00011 #include <unsupported/Eigen/FFT>
00012 
00013 template <typename T> 
00014 std::complex<T> RandomCpx() { return std::complex<T>( (T)(rand()/(T)RAND_MAX - .5), (T)(rand()/(T)RAND_MAX - .5) ); }
00015 
00016 using namespace std;
00017 using namespace Eigen;
00018 
00019 
00020 template < typename T>
00021 complex<long double>  promote(complex<T> x) { return complex<long double>(x.real(),x.imag()); }
00022 
00023 complex<long double>  promote(float x) { return complex<long double>( x); }
00024 complex<long double>  promote(double x) { return complex<long double>( x); }
00025 complex<long double>  promote(long double x) { return complex<long double>( x); }
00026     
00027 
00028     template <typename VT1,typename VT2>
00029     long double fft_rmse( const VT1 & fftbuf,const VT2 & timebuf)
00030     {
00031         long double totalpower=0;
00032         long double difpower=0;
00033         long double pi = acos((long double)-1 );
00034         for (size_t k0=0;k0<(size_t)fftbuf.size();++k0) {
00035             complex<long double> acc = 0;
00036             long double phinc = -2.*k0* pi / timebuf.size();
00037             for (size_t k1=0;k1<(size_t)timebuf.size();++k1) {
00038                 acc +=  promote( timebuf[k1] ) * exp( complex<long double>(0,k1*phinc) );
00039             }
00040             totalpower += numext::abs2(acc);
00041             complex<long double> x = promote(fftbuf[k0]); 
00042             complex<long double> dif = acc - x;
00043             difpower += numext::abs2(dif);
00044             //cerr << k0 << "\t" << acc << "\t" <<  x << "\t" << sqrt(numext::abs2(dif)) << endl;
00045         }
00046         cerr << "rmse:" << sqrt(difpower/totalpower) << endl;
00047         return sqrt(difpower/totalpower);
00048     }
00049 
00050     template <typename VT1,typename VT2>
00051     long double dif_rmse( const VT1 buf1,const VT2 buf2)
00052     {
00053         long double totalpower=0;
00054         long double difpower=0;
00055         size_t n = (min)( buf1.size(),buf2.size() );
00056         for (size_t k=0;k<n;++k) {
00057             totalpower += (numext::abs2( buf1[k] ) + numext::abs2(buf2[k]) )/2.;
00058             difpower += numext::abs2(buf1[k] - buf2[k]);
00059         }
00060         return sqrt(difpower/totalpower);
00061     }
00062 
00063 enum { StdVectorContainer, EigenVectorContainer };
00064 
00065 template<int Container, typename Scalar> struct VectorType;
00066 
00067 template<typename Scalar> struct VectorType<StdVectorContainer,Scalar>
00068 {
00069   typedef vector<Scalar> type;
00070 };
00071 
00072 template<typename Scalar> struct VectorType<EigenVectorContainer,Scalar>
00073 {
00074   typedef Matrix<Scalar,Dynamic,1> type;
00075 };
00076 
00077 template <int Container, typename T>
00078 void test_scalar_generic(int nfft)
00079 {
00080     typedef typename FFT<T>::Complex Complex;
00081     typedef typename FFT<T>::Scalar Scalar;
00082     typedef typename VectorType<Container,Scalar>::type ScalarVector;
00083     typedef typename VectorType<Container,Complex>::type ComplexVector;
00084 
00085     FFT<T> fft;
00086     ScalarVector tbuf(nfft);
00087     ComplexVector freqBuf;
00088     for (int k=0;k<nfft;++k)
00089         tbuf[k]= (T)( rand()/(double)RAND_MAX - .5);
00090 
00091     // make sure it DOESN'T give the right full spectrum answer
00092     // if we've asked for half-spectrum
00093     fft.SetFlag(fft.HalfSpectrum );
00094     fft.fwd( freqBuf,tbuf);
00095     VERIFY((size_t)freqBuf.size() == (size_t)( (nfft>>1)+1) );
00096     VERIFY( fft_rmse(freqBuf,tbuf) < test_precision<T>()  );// gross check
00097 
00098     fft.ClearFlag(fft.HalfSpectrum );
00099     fft.fwd( freqBuf,tbuf);
00100     VERIFY( (size_t)freqBuf.size() == (size_t)nfft);
00101     VERIFY( fft_rmse(freqBuf,tbuf) < test_precision<T>()  );// gross check
00102 
00103     if (nfft&1)
00104         return; // odd FFTs get the wrong size inverse FFT
00105 
00106     ScalarVector tbuf2;
00107     fft.inv( tbuf2 , freqBuf);
00108     VERIFY( dif_rmse(tbuf,tbuf2) < test_precision<T>()  );// gross check
00109 
00110 
00111     // verify that the Unscaled flag takes effect
00112     ScalarVector tbuf3;
00113     fft.SetFlag(fft.Unscaled);
00114 
00115     fft.inv( tbuf3 , freqBuf);
00116 
00117     for (int k=0;k<nfft;++k)
00118         tbuf3[k] *= T(1./nfft);
00119 
00120 
00121     //for (size_t i=0;i<(size_t) tbuf.size();++i)
00122     //    cout << "freqBuf=" << freqBuf[i] << " in2=" << tbuf3[i] << " -  in=" << tbuf[i] << " => " << (tbuf3[i] - tbuf[i] ) <<  endl;
00123 
00124     VERIFY( dif_rmse(tbuf,tbuf3) < test_precision<T>()  );// gross check
00125 
00126     // verify that ClearFlag works
00127     fft.ClearFlag(fft.Unscaled);
00128     fft.inv( tbuf2 , freqBuf);
00129     VERIFY( dif_rmse(tbuf,tbuf2) < test_precision<T>()  );// gross check
00130 }
00131 
00132 template <typename T>
00133 void test_scalar(int nfft)
00134 {
00135   test_scalar_generic<StdVectorContainer,T>(nfft);
00136   //test_scalar_generic<EigenVectorContainer,T>(nfft);
00137 }
00138 
00139 
00140 template <int Container, typename T>
00141 void test_complex_generic(int nfft)
00142 {
00143     typedef typename FFT<T>::Complex Complex;
00144     typedef typename VectorType<Container,Complex>::type ComplexVector;
00145 
00146     FFT<T> fft;
00147 
00148     ComplexVector inbuf(nfft);
00149     ComplexVector outbuf;
00150     ComplexVector buf3;
00151     for (int k=0;k<nfft;++k)
00152         inbuf[k]= Complex( (T)(rand()/(double)RAND_MAX - .5), (T)(rand()/(double)RAND_MAX - .5) );
00153     fft.fwd( outbuf , inbuf);
00154 
00155     VERIFY( fft_rmse(outbuf,inbuf) < test_precision<T>()  );// gross check
00156     fft.inv( buf3 , outbuf);
00157 
00158     VERIFY( dif_rmse(inbuf,buf3) < test_precision<T>()  );// gross check
00159 
00160     // verify that the Unscaled flag takes effect
00161     ComplexVector buf4;
00162     fft.SetFlag(fft.Unscaled);
00163     fft.inv( buf4 , outbuf);
00164     for (int k=0;k<nfft;++k)
00165         buf4[k] *= T(1./nfft);
00166     VERIFY( dif_rmse(inbuf,buf4) < test_precision<T>()  );// gross check
00167 
00168     // verify that ClearFlag works
00169     fft.ClearFlag(fft.Unscaled);
00170     fft.inv( buf3 , outbuf);
00171     VERIFY( dif_rmse(inbuf,buf3) < test_precision<T>()  );// gross check
00172 }
00173 
00174 template <typename T>
00175 void test_complex(int nfft)
00176 {
00177   test_complex_generic<StdVectorContainer,T>(nfft);
00178   test_complex_generic<EigenVectorContainer,T>(nfft);
00179 }
00180 /*
00181 template <typename T,int nrows,int ncols>
00182 void test_complex2d()
00183 {
00184     typedef typename Eigen::FFT<T>::Complex Complex;
00185     FFT<T> fft;
00186     Eigen::Matrix<Complex,nrows,ncols> src,src2,dst,dst2;
00187 
00188     src = Eigen::Matrix<Complex,nrows,ncols>::Random();
00189     //src =  Eigen::Matrix<Complex,nrows,ncols>::Identity();
00190 
00191     for (int k=0;k<ncols;k++) {
00192         Eigen::Matrix<Complex,nrows,1> tmpOut;
00193         fft.fwd( tmpOut,src.col(k) );
00194         dst2.col(k) = tmpOut;
00195     }
00196 
00197     for (int k=0;k<nrows;k++) {
00198         Eigen::Matrix<Complex,1,ncols> tmpOut;
00199         fft.fwd( tmpOut,  dst2.row(k) );
00200         dst2.row(k) = tmpOut;
00201     }
00202 
00203     fft.fwd2(dst.data(),src.data(),ncols,nrows);
00204     fft.inv2(src2.data(),dst.data(),ncols,nrows);
00205     VERIFY( (src-src2).norm() < test_precision<T>() );
00206     VERIFY( (dst-dst2).norm() < test_precision<T>() );
00207 }
00208 */
00209 
00210 
00211 void test_return_by_value(int len)
00212 {
00213     VectorXf in;
00214     VectorXf in1;
00215     in.setRandom( len );
00216     VectorXcf out1,out2;
00217     FFT<float> fft;
00218 
00219     fft.SetFlag(fft.HalfSpectrum );
00220 
00221     fft.fwd(out1,in);
00222     out2 = fft.fwd(in);
00223     VERIFY( (out1-out2).norm() < test_precision<float>() );
00224     in1 = fft.inv(out1);
00225     VERIFY( (in1-in).norm() < test_precision<float>() );
00226 }
00227 
00228 void test_FFTW()
00229 {
00230   CALL_SUBTEST( test_return_by_value(32) );
00231   //CALL_SUBTEST( ( test_complex2d<float,4,8> () ) ); CALL_SUBTEST( ( test_complex2d<double,4,8> () ) );
00232   //CALL_SUBTEST( ( test_complex2d<long double,4,8> () ) );
00233   CALL_SUBTEST( test_complex<float>(32) ); CALL_SUBTEST( test_complex<double>(32) ); 
00234   CALL_SUBTEST( test_complex<float>(256) ); CALL_SUBTEST( test_complex<double>(256) ); 
00235   CALL_SUBTEST( test_complex<float>(3*8) ); CALL_SUBTEST( test_complex<double>(3*8) ); 
00236   CALL_SUBTEST( test_complex<float>(5*32) ); CALL_SUBTEST( test_complex<double>(5*32) ); 
00237   CALL_SUBTEST( test_complex<float>(2*3*4) ); CALL_SUBTEST( test_complex<double>(2*3*4) ); 
00238   CALL_SUBTEST( test_complex<float>(2*3*4*5) ); CALL_SUBTEST( test_complex<double>(2*3*4*5) ); 
00239   CALL_SUBTEST( test_complex<float>(2*3*4*5*7) ); CALL_SUBTEST( test_complex<double>(2*3*4*5*7) ); 
00240 
00241   CALL_SUBTEST( test_scalar<float>(32) ); CALL_SUBTEST( test_scalar<double>(32) ); 
00242   CALL_SUBTEST( test_scalar<float>(45) ); CALL_SUBTEST( test_scalar<double>(45) ); 
00243   CALL_SUBTEST( test_scalar<float>(50) ); CALL_SUBTEST( test_scalar<double>(50) ); 
00244   CALL_SUBTEST( test_scalar<float>(256) ); CALL_SUBTEST( test_scalar<double>(256) ); 
00245   CALL_SUBTEST( test_scalar<float>(2*3*4*5*7) ); CALL_SUBTEST( test_scalar<double>(2*3*4*5*7) ); 
00246   
00247   #ifdef EIGEN_HAS_FFTWL
00248   CALL_SUBTEST( test_complex<long double>(32) );
00249   CALL_SUBTEST( test_complex<long double>(256) );
00250   CALL_SUBTEST( test_complex<long double>(3*8) );
00251   CALL_SUBTEST( test_complex<long double>(5*32) );
00252   CALL_SUBTEST( test_complex<long double>(2*3*4) );
00253   CALL_SUBTEST( test_complex<long double>(2*3*4*5) );
00254   CALL_SUBTEST( test_complex<long double>(2*3*4*5*7) );
00255   
00256   CALL_SUBTEST( test_scalar<long double>(32) );
00257   CALL_SUBTEST( test_scalar<long double>(45) );
00258   CALL_SUBTEST( test_scalar<long double>(50) );
00259   CALL_SUBTEST( test_scalar<long double>(256) );
00260   CALL_SUBTEST( test_scalar<long double>(2*3*4*5*7) );
00261   #endif
00262 }


shape_reconstruction
Author(s): Roberto Martín-Martín
autogenerated on Sat Jun 8 2019 18:30:58