#include "sopnamsp.h" #include "fftpserver.h" #include "fftpackc.h" #include /*! \class SOPHYA::FFTPackServer \ingroup NTools An implementation of FFTServerInterface based on fftpack, for one dimensional arrays. The class calls the c library ``fftpack'', which is accessible and documented at http://www.netlib.org/fftpack/. However, the class functions do not necessarily correspond with the equivalent fftpack function. For example, fftpack "forward" transformations are in fact inverse fourier transformations. Due to the way that fftpack manages its work arrays, an object can run faster if the length of the input arrays does not change. For example, if you need to do a series of FFT's of differing length, it may be more efficient to create an fftserver object for each length. \code #include "fftpserver.h" // ... TVector in(32); TVector< complex > out; in = RandomSequence(); FFTPackServer ffts; ffts.setNormalize(true); // To have normalized transforms cout << " FFTServer info string= " << ffts.getInfo() << endl; cout << "in= " << in << endl; cout << " Calling ffts.FFTForward(in, out) : " << endl; ffts.FFTForward(in, out); cout << "out= " << out << endl; \endcode */ //! Constructor - If preserve_input==true, input arrays will not be overwritten. FFTPackServer::FFTPackServer(bool preserve_input) : FFTServerInterface("FFTPackServer using extended FFTPack (C-version) package") , ckR4("FFTPackServer: ", true, true) , ckR8("FFTPackServer: ", true, true), _preserve_input(preserve_input) { //the working array and its size for the different //possible numerical types sz_rfft = 0; ws_rfft = NULL; sz_dfft = 0; ws_dfft = NULL; sz_cfft = 0; ws_cfft = NULL; sz_cdfft = 0; ws_cdfft = NULL; } FFTPackServer::~FFTPackServer() { if (ws_rfft) delete[] ws_rfft; if (ws_dfft) delete[] ws_dfft; if (ws_cfft) delete[] ws_cfft; if (ws_cdfft) delete[] ws_cdfft; } FFTServerInterface * FFTPackServer::Clone() { return (new FFTPackServer(_preserve_input) ); } void FFTPackServer::FFTForward(TArray< complex > & in, TArray< complex > & out) { ckR8.CheckResize(in, out); out = in; fftf(out.Size(), out.Data()); if (getNormalize()) out *= (1./(r_8)(in.Size())); } void FFTPackServer::FFTBackward(TArray< complex > & in, TArray< complex > & out) { ckR8.CheckResize(in, out); out = in; fftb(out.Size(), out.Data()); } void FFTPackServer::FFTForward(TArray< complex > & in, TArray< complex > & out) { ckR4.CheckResize(in, out); out = in; fftf(out.Size(), out.Data()); if (getNormalize()) out *= (1./(r_4)(in.Size())); } void FFTPackServer::FFTBackward(TArray< complex > & in, TArray< complex > & out) { ckR4.CheckResize(in, out); out = in; fftb(out.Size(), out.Data()); } void FFTPackServer::FFTForward(TArray< r_4 > & in, TArray< complex > & out) { ckR4.CheckResize(in, out); bool share = (_preserve_input) ? false : true; TArray< r_4 > inout(in, share); fftf(inout.Size(), inout.Data()); ReShapetoCompl(inout, out); if (getNormalize()) out *= complex((1./(r_4)(in.Size())), 0.); } void FFTPackServer::FFTBackward(TArray< complex > & in, TArray< r_4 > & out, bool usoutsz) { ckR4.CheckResize(in, out, usoutsz); ReShapetoReal(in, out, usoutsz); fftb(out.Size(), out.Data()); } void FFTPackServer::FFTForward(TArray< r_8 > & in, TArray< complex > & out) { ckR8.CheckResize(in, out); bool share = (_preserve_input) ? false : true; TArray< r_8 > inout(in, share); fftf(inout.Size(), inout.Data()); ReShapetoCompl(inout, out); if (getNormalize()) out *= complex((1./(r_8)(in.Size())), 0.); } void FFTPackServer::FFTBackward(TArray< complex > & in, TArray< r_8 > & out, bool usoutsz) { ckR8.CheckResize(in, out, usoutsz); ReShapetoReal(in, out, usoutsz); fftb(out.Size(), out.Data()); } template void FFTPack_ReShapetoReal(TArray< complex > const & ina, TArray< T > & outa, bool usz) { TVector< complex > in(ina); TVector< T > out(outa); sa_size_t n = in.NElts(); sa_size_t ncs; if (usz) { if ( (out.NElts() != 2*n-1) && (out.NElts() != 2*n-2) ) throw SzMismatchError("FFTPack_ReShapetoReal(..., true) - Wrong output array size "); ncs = out.NElts(); } else { T thr = FFTArrayChecker::ZeroThreshold(); ncs = ( (in(n-1).imag() < -thr) || (in(n-1).imag() > thr) ) ? 2*n-1 : 2*n-2; if (out.NElts() != ncs) { cerr << "DEBUG-FFTPack_ReShapetoReal() ncs = " << ncs << " out.NElts()= " << out.NElts() << endl; throw SzMismatchError("FFTPack_ReShapetoReal() - Wrong output array size !"); } } sa_size_t k; out(0) = in(0).real(); for(k=1;k void FFTPack_ReShapetoCompl(TArray< T > const & ina, TArray< complex > & outa) { TVector< T > in(ina); TVector< complex > out(outa); sa_size_t n = in.NElts(); sa_size_t ncs = n/2+1; sa_size_t nc = (n%2 != 0) ? n/2+1 : n/2; if (out.NElts() != ncs) { cerr << "DBG-ReShapetoCompl() ncs=" << ncs << " out.NElts()= " << out.NElts() << endl; throw SzMismatchError("FFTPack_ReShapetoCompl() - Wrong output array size !"); } out(0) = complex (in(0),0.); for(int k=1;k (in(2*k-1), in(2*k)); if (n%2 == 0) out(ncs-1) = complex(in(n-1), 0.); return; } void FFTPackServer::ReShapetoReal(TArray< complex > const & in, TArray< r_8 > & out, bool usz) { FFTPack_ReShapetoReal(in, out, usz); } void FFTPackServer::ReShapetoCompl(TArray< r_8 > const & in, TArray< complex > & out) { FFTPack_ReShapetoCompl(in, out); } void FFTPackServer::ReShapetoReal(TArray< complex > const & in, TArray< r_4 > & out, bool usz) { FFTPack_ReShapetoReal(in, out, usz); } void FFTPackServer::ReShapetoCompl(TArray< r_4 > const & in, TArray< complex > & out) { FFTPack_ReShapetoCompl(in, out); } void FFTPackServer::checkint_rfft(int_4 l) { if (sz_rfft == l) return; //checkint functions check and reallocate //memory for the work arrays when performing if (ws_rfft) delete[] ws_rfft; //a transform sz_rfft = l; ws_rfft = new r_4[2*l+15]; rffti_(&l, ws_rfft); } void FFTPackServer::checkint_cfft(int_4 l) { if (sz_cfft == l) return; if (ws_cfft) delete[] ws_cfft; sz_cfft = l; ws_cfft = new r_4[4*l+15]; cffti_(&l, ws_cfft); } void FFTPackServer::checkint_dfft(int_4 l) { if (sz_dfft == l) return; if (ws_dfft) delete[] ws_dfft; sz_dfft = l; ws_dfft = new r_8[2*l+15]; dffti_(&l, ws_dfft); } void FFTPackServer::checkint_cdfft(int_4 l) { if (sz_cdfft == l) return; if (ws_cdfft) delete[] ws_cdfft; sz_cdfft = l; ws_cdfft = new r_8[4*l+15]; cdffti_(&l, ws_cdfft); } /* In general forward transformations are resorted since fftpack functions return inverse transformations */ void FFTPackServer::fftf(int_4 l, r_4* inout) { checkint_rfft(l); rfftf_(&l, inout, ws_rfft); // for (int k= 2;k<=(l+1)/2;k++) inout[2*k-2]=-inout[2*k-2]; } void FFTPackServer::fftf(int_4 l, r_8* inout) { checkint_dfft(l); dfftf_(&l, inout, ws_dfft); // for (int k= 2;k<=(l+1)/2;k++) inout[2*k-2]=-inout[2*k-2]; } void FFTPackServer::fftf(int_4 l, complex* inout) { checkint_cfft(l); cfftf_(&l, (r_4 *)(inout), ws_cfft); } void FFTPackServer::fftf(int_4 l, complex* inout) { checkint_cdfft(l); cdfftf_(&l, (r_8*)(inout), ws_cdfft); } void FFTPackServer::fftb(int_4 l, r_4* inout) { checkint_rfft(l); rfftb_(&l, inout, ws_rfft); } void FFTPackServer::fftb(int_4 l, r_8* inout) { checkint_dfft(l); dfftb_(&l, inout, ws_dfft); } void FFTPackServer::fftb(int_4 l, complex* inout) { checkint_cfft(l); cfftb_(&l, (r_4 *)(inout), ws_cfft); } void FFTPackServer::fftb(int_4 l, complex* inout) { checkint_cdfft(l); cdfftb_(&l, (r_8 *)(inout), ws_cdfft); }