#include "fftservintf.h" /*! \class SOPHYA::FFTServerInterface \ingroup NTools Defines the interface for FFT (Fast Fourier Transform) operations. Definitions : - Sampling period \b T - Sampling frequency \b fs=1/T - Total number of samples \b N - Frequency step in Fourier space \b =fs/N=1/(N*T) - Component frequencies - k=0 -> 0 - k=1 -> 1/(N*T) - k -> k/(N*T) - k=N/2 -> 1/(2*T) (Nyquist frequency) - k>N/2 -> k/(N*T) (or negative frequency -(N-k)/(N*T)) For a sampling period T=1, the computed Fourier components correspond to : \verbatim 0 1/N 2/N ... 1/2 1/2+1/N 1/2+2/N ... 1-2/N 1-1/N 0 1/N 2/N ... 1/2 ... -2/N -1/N \endverbatim For complex one-dimensional transforms: \f[ out(i) = F_{norm} \Sigma_{j} \ e^{-2 \pi \sqrt{-1} \ i \ j} \ {\rm (forward)} \f] \f[ out(i) = F_{norm} \Sigma_{j} \ e^{2 \pi \sqrt{-1} \ i \ j} \ {\rm (backward)} \f] i,j= 0..N-1 , where N is the input or the output array size. For complex multi-dimensional transforms: \f[ out(i1,i2,...,id) = F_{norm} \Sigma_{j1} \Sigma_{j2} ... \Sigma_{jd} \ e^{-2 \pi \sqrt{-1} \ i1 \ j1} ... e^{-2 \pi \sqrt{-1} \ id \ jd} \ {\rm (forward)} \f] \f[ out(i1,i2,...,id) = F_{norm} \Sigma_{j1} \Sigma_{j2} ... \Sigma_{jd} \ e^{2 \pi \sqrt{-1} \ i1 \ j1} ... e^{2 \pi \sqrt{-1} \ id \ jd} \ {\rm (backward)} \f] For real forward transforms, the input array is real, and the output array complex, with Fourier components up to k=N/2. For real backward transforms, the input array is complex and the output array is real. */ /* --Methode-- */ FFTServerInterface::FFTServerInterface(string info) { _info = info; _fgnorm = true; } /* --Methode-- */ FFTServerInterface::~FFTServerInterface() { } // ----------------- Transforme pour les double ------------------- /* --Methode-- */ //! Forward Fourier transform for double precision complex data /*! \param in : Input complex array \param out : Output complex array */ void FFTServerInterface::FFTForward(TArray< complex > const &, TArray< complex > &) { throw NotAvailableOperation("FFTServer::FFTForward(TArray...) Unsupported operation !"); } /* --Methode-- */ //! Backward (inverse) Fourier transform for double precision complex data /*! \param in : Input complex array \param out : Output complex array */ void FFTServerInterface::FFTBackward(TArray< complex > const &, TArray< complex > &) { throw NotAvailableOperation("FFTServer::FFTBackward(TArray...) Unsupported operation !"); } /* --Methode-- */ //! Forward Fourier transform for double precision real input data /*! \param in : Input real array \param out : Output complex array */ void FFTServerInterface::FFTForward(TArray< r_8 > const &, TArray< complex > &) { throw NotAvailableOperation("FFTServer::FFTForward(TArray...) Unsupported operation !"); } /* --Methode-- */ //! Backward (inverse) Fourier transform for double precision real output data /*! \param in : Input complex array \param out : Output real array \param usoutsz : if true, use the output array size for computing the inverse FFT. */ void FFTServerInterface::FFTBackward(TArray< complex > const &, TArray< r_8 > &, bool) { throw NotAvailableOperation("FFTServer::FFTBackward(TArray...) Unsupported operation !"); } // ----------------- Transforme pour les float ------------------- /* --Methode-- */ //! Forward Fourier transform for complex data /*! \param in : Input complex array \param out : Output complex array */ void FFTServerInterface::FFTForward(TArray< complex > const &, TArray< complex > &) { throw NotAvailableOperation("FFTServer::FFTForward(TArray r_4 ... ) Unsupported operation !"); } /* --Methode-- */ //! Backward (inverse) Fourier transform for complex data /*! \param in : Input complex array \param out : Output complex array */ void FFTServerInterface::FFTBackward(TArray< complex > const &, TArray< complex > &) { throw NotAvailableOperation("FFTServer::FFTBackward(TArray r_4 ... ) Unsupported operation !"); } /* --Methode-- */ //! Forward Fourier transform for real input data /*! \param in : Input real array \param out : Output complex array */ void FFTServerInterface::FFTForward(TArray< r_4 > const &, TArray< complex > &) { throw NotAvailableOperation("FFTServer::FFTForward(TArray r_4 ... ) Unsupported operation !"); } /* --Methode-- */ //! Backward (inverse) Fourier transform for real output data /*! \param in : Input complex array \param out : Output real array \param usoutsz : if true, use the output array size for computing the inverse FFT. */ void FFTServerInterface::FFTBackward(TArray< complex > const &, TArray< r_4 > &, bool) { throw NotAvailableOperation("FFTServer::FFTBackward(TArray r_4 ... ) Unsupported operation !"); } // ----------------- Transformation de normalisation pour les energies ------------------- /* --Methode-- */ //! Compute the transform to be applied to "fftx=FFT(x)" so that "x" and "FFT(x)" have the same energy /*! \return The factor to be applied to the FFT energy such that we get the same energy as for the x. \verbatim fftx is computed by: FFTForward(x,fftx) Energy of x : Ex = sum{|x(i)|^2} i=0,x.Size()-1 Energy of fftx : Efftx = sum{|fftx(i)^2|} i=0,fftx.Size()-1 ( usually x.Size() != fftx.Size() ) ------------------------------------------------------------------- | TransfEnergyFFT return A and B such that : Ex = A * Efftx + B | | and Norm such that : Ex = Norm * Efftx | ------------------------------------------------------------------- To normalize the fftx vector apply : "fftx *= sqrt(Norm)" \endverbatim */ r_8 FFTServerInterface::TransfEnergyFFT (TVector< complex > const& x, TVector< complex > const& fftx, r_8& A, r_8& B) { B=0.; if(getNormalize()) A = x.Size(); else A = 1./x.Size(); r_8 norm = A; return norm; } //! Compute the transform to be applied to "fftx=FFT(x)" so that "x" and "FFT(x)" have the same energy r_8 FFTServerInterface::TransfEnergyFFT (TVector< complex > const & x, TVector< complex > const & fftx, r_8& A, r_8& B) { B=0.; if(getNormalize()) A = x.Size(); else A = 1./x.Size(); r_8 norm = A; return norm; } //! Compute the transform to be applied to "fftx=FFT(x)" so that "x" and "FFT(x)" have the same energy r_8 FFTServerInterface::TransfEnergyFFT (TVector< r_8 > const & x, TVector< complex > const & fftx, r_8& A, r_8& B) { A= 2.; B= - abs(fftx(0)*fftx(0)); if(x.Size()%2 == 0) B -= abs(fftx(fftx.Size()-1)*fftx(fftx.Size()-1)); if(getNormalize()) {A *= x.Size(); B *= x.Size();} else {A /= x.Size(); B /= x.Size();} r_8 norm = 0.; for(int_4 i=0;i0.) norm = (A*norm+B)/norm; return norm; } //! Compute the transform to be applied to "fftx=FFT(x)" so that "x" and "FFT(x)" have the same energy r_8 FFTServerInterface::TransfEnergyFFT (TVector< r_4 > const & x, TVector< complex > const & fftx, r_8& A, r_8& B) { A= 2.; B= - abs(fftx(0)*fftx(0)); if(x.Size()%2 == 0) B -= abs(fftx(fftx.Size()-1)*fftx(fftx.Size()-1)); if(getNormalize()) {A *= x.Size(); B *= x.Size();} else {A /= x.Size(); B /= x.Size();} r_8 norm = 0.; for(int_4 i=0;i0.) norm = (A*norm+B)/norm; return norm; } /* --Methode-- */ /*! \class SOPHYA::FFTArrayChecker \ingroup NTools Service class for checking array size and resizing output arrays, to be used by FFTServer classes */ template FFTArrayChecker::FFTArrayChecker(string msg, bool checkpack, bool onedonly) { _msg = msg + " FFTArrayChecker::"; _checkpack = checkpack; _onedonly = onedonly; } /* --Methode-- */ template FFTArrayChecker::~FFTArrayChecker() { } template T FFTArrayChecker::ZeroThreshold() { return(0); } r_8 FFTArrayChecker< r_8 >::ZeroThreshold() { return(1.e-18); } r_4 FFTArrayChecker< r_4 >::ZeroThreshold() { return(1.e-9); } /* --Methode-- */ template int FFTArrayChecker::CheckResize(TArray< complex > const & in, TArray< complex > & out) { int k; string msg; if (in.Size() < 1) { msg = _msg + "CheckResize(complex in, complex out) - Unallocated input array !"; throw(SzMismatchError(msg)); } if (_checkpack) if ( !in.IsPacked() ) { msg = _msg + "CheckResize(complex in, complex out) - Not packed input array !"; throw(SzMismatchError(msg)); } int ndg1 = 0; for(k=0; k 1) ndg1++; if (_onedonly) if (ndg1 > 1) { msg = _msg + "CheckResize(complex in, complex out) - Only 1-D array accepted !"; throw(SzMismatchError(msg)); } out.ReSize(in); // sa_size_t sz[BASEARRAY_MAXNDIMS]; // for(k=0; k int FFTArrayChecker::CheckResize(TArray< T > const & in, TArray< complex > & out) { int k; string msg; if (in.Size() < 1) { msg = _msg + "CheckResize(real in, complex out) - Unallocated input array !"; throw(SzMismatchError(msg)); } if (_checkpack) if ( !in.IsPacked() ) { msg = _msg + "CheckResize(real in, complex out) - Not packed input array !"; throw(SzMismatchError(msg)); } int ndg1 = 0; for(k=0; k 1) ndg1++; if (_onedonly) if (ndg1 > 1) { msg = _msg + "CheckResize(real in, complex out) - Only 1-D array accepted !"; throw(SzMismatchError(msg)); } sa_size_t sz[BASEARRAY_MAXNDIMS]; // if (ndg1 > 1) { sz[0] = in.Size(0)/2+1; for(k=1; k int FFTArrayChecker::CheckResize(TArray< complex > const & in, TArray< T > & out, bool usoutsz) { int k; string msg; if (in.Size() < 1) { msg = _msg + "CheckResize(complex in, real out) - Unallocated input array !"; throw(SzMismatchError(msg)); } if (_checkpack) if ( !in.IsPacked() ) { msg = _msg + "CheckResize(complex in, real out) - Not packed input array !"; throw(SzMismatchError(msg)); } int ndg1 = 0; for(k=0; k 1) ndg1++; if (_onedonly) if (ndg1 > 1) { msg = _msg + "CheckResize(complex in, real out) - Only 1-D array accepted !"; throw(SzMismatchError(msg)); } if (usoutsz) { // We have to use output array size bool fgerr = false; if (ndg1 > 1) { if (in.Size(0) != out.Size(0)/2+1) fgerr = true; } else { if (in.Size(in.MaxSizeKA()) != out.Size(in.MaxSizeKA())/2+1) fgerr = true; } if (fgerr) { msg = _msg + "CheckResize(complex in, real out) - Incompatible in-out sizes !"; throw(SzMismatchError(msg)); } } else { // We have to resize the output array sa_size_t sz[BASEARRAY_MAXNDIMS]; if (ndg1 > 1) { sz[0] = 2*in.Size(0)-1; for(k=1; k thr) ) ? 2*n-1 : 2*n-2; sz[in.MaxSizeKA()] = ncs; } out.ReSize(in.NbDimensions(), sz); } return(ndg1); } #ifdef __CXX_PRAGMA_TEMPLATES__ #pragma define_template FFTArrayChecker #pragma define_template FFTArrayChecker #endif #if defined(ANSI_TEMPLATES) || defined(GNU_TEMPLATES) template class FFTArrayChecker; template class FFTArrayChecker; #endif