/*! \file pifft_p.h * \brief Class for FFT, IFFT and Hilbert transformations */ /* PIP - Platform Independent Primitives Private header for fftw3 Ivan Pelipenko peri4ko@yandex.ru, Andrey Bychkov work.a.b@yandex.ru This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #ifndef PIFFT_P_H #define PIFFT_P_H #include "pivector.h" #include "picout.h" #if defined(PIP_FFTW) || defined(PIP_FFTWf) || defined(PIP_FFTWl) || defined(PIP_FFTWq) # include "fftw3.h" #else # define FFTW_FORWARD 0 # define FFTW_BACKWARD 0 # define FFTW_ESTIMATE 0 # define FFTW_MEASURE 0 #endif template class PIFFTW_Private { public: explicit PIFFTW_Private() { plan = 0; //#ifndef PIP_FFTW // piCout << "[PIFFTW]" << "Warning: PIFFTW is disabled, to enable install libfftw3-dev library and build pip with -DFFTW=1"; //#endif p_makeThreadSafe(); } ~PIFFTW_Private() {p_destroyPlan(plan);} const PIVector > & calcFFT(const PIVector > & in) { if (prepare != PlanParams(in.size(), fo_complex)) { p_out.resize(in.size()); //piCout << "[PIFFTW]" << "creating plan"; p_createPlan_c2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_FORWARD, FFTW_ESTIMATE | FFTW_UNALIGNED); prepare = PlanParams(in.size(), fo_complex); } p_executePlan_c2c(plan, in.data(), p_out.data()); return p_out; } const PIVector > & calcFFT(const PIVector & in) { if (prepare != PlanParams(in.size(), fo_real)) { p_out.resize(in.size()); //piCout << "[PIFFTW]" << "creating plan"; p_createPlan_r2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_ESTIMATE | FFTW_UNALIGNED); prepare = PlanParams(in.size(), fo_real); } p_executePlan_r2c(plan, in.data(), p_out.data()); return p_out; } const PIVector > & calcFFTinverse(const PIVector > & in) { if (prepare != PlanParams(in.size(), fo_inverse)) { p_out.resize(in.size()); //piCout << "[PIFFTW]" << "creating plan"; p_createPlan_c2c_1d(plan, in.size(), in.data(), p_out.data(), FFTW_BACKWARD, FFTW_ESTIMATE | FFTW_UNALIGNED); prepare = PlanParams(in.size(), fo_inverse); } p_executePlan_c2c(plan, in.data(), p_out.data()); return p_out; } enum FFT_Operation {fo_real, fo_complex, fo_inverse}; void preparePlan(int size, int op) { p_inr.clear(); p_in.clear(); p_out.clear(); switch ((FFT_Operation)op) { case fo_real: p_inr.resize(size); p_out.resize(size); p_createPlan_r2c_1d(plan, size, p_inr.data(), p_out.data(), FFTW_MEASURE | FFTW_UNALIGNED); break; case fo_complex: p_in.resize(size); p_out.resize(size); p_createPlan_c2c_1d(plan, size, p_in.data(), p_out.data(), FFTW_FORWARD, FFTW_MEASURE | FFTW_UNALIGNED); break; case fo_inverse: p_in.resize(size); p_out.resize(size); p_createPlan_c2c_1d(plan, size, p_in.data(), p_out.data(), FFTW_BACKWARD, FFTW_MEASURE | FFTW_UNALIGNED); break; default: size = 0; break; } prepare = PlanParams(size, (FFT_Operation)op); } inline void p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) {} inline void p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) {} inline void p_executePlan(void * plan) {} inline void p_executePlan_c2c(void * plan, const void * in, void * out) {} inline void p_executePlan_r2c(void * plan, const void * in, void * out) {} inline void p_destroyPlan(void *& plan) {} inline void p_makeThreadSafe() {} struct PlanParams { PlanParams() {size = 0; op = fo_complex;} PlanParams(int size_, FFT_Operation op_) {size = size_; op = op_;} bool isValid() {return size > 0;} bool operator ==(const PlanParams & v) const {return (v.size == size) && (v.op == op);} bool operator !=(const PlanParams & v) const {return !(*this == v);} int size; FFT_Operation op; }; PIVector > p_in; PIVector p_inr; PIVector > p_out; void * plan; PlanParams prepare; }; #ifdef PIP_FFTWf template<> inline void PIFFTW_Private::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) { plan = fftwf_plan_dft_1d(size, (fftwf_complex *)in, (fftwf_complex *)out, dir, flags);} template<> inline void PIFFTW_Private::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) { plan = fftwf_plan_dft_r2c_1d(size, (float *)in, (fftwf_complex *)out, flags);} template<> inline void PIFFTW_Private::p_executePlan(void * plan) {fftwf_execute((fftwf_plan)plan);} template<> inline void PIFFTW_Private::p_executePlan_c2c(void * plan, const void * in, void * out) {fftwf_execute_dft((fftwf_plan)plan, (fftwf_complex *)in, (fftwf_complex *)out);} template<> inline void PIFFTW_Private::p_executePlan_r2c(void * plan, const void * in, void * out) {fftwf_execute_dft_r2c((fftwf_plan)plan, (float *)in, (fftwf_complex *)out);} template<> inline void PIFFTW_Private::p_destroyPlan(void *& plan) {if (plan) fftwf_destroy_plan((fftwf_plan)plan); plan = 0;} # ifdef PIP_FFTWf_THREADSAFE template<> inline void PIFFTW_Private::p_makeThreadSafe() {fftwf_make_planner_thread_safe();} # endif #endif // PIP_FFTWf #ifdef PIP_FFTW template<> inline void PIFFTW_Private::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) { plan = fftw_plan_dft_1d(size, (fftw_complex *)in, (fftw_complex *)out, dir, flags);} template<> inline void PIFFTW_Private::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) { plan = fftw_plan_dft_r2c_1d(size, (double *)in, (fftw_complex *)out, flags);} template<> inline void PIFFTW_Private::p_executePlan(void * plan) {fftw_execute((fftw_plan)plan);} template<> inline void PIFFTW_Private::p_executePlan_c2c(void * plan, const void * in, void * out) {fftw_execute_dft((fftw_plan)plan, (fftw_complex *)in, (fftw_complex *)out);} template<> inline void PIFFTW_Private::p_executePlan_r2c(void * plan, const void * in, void * out) {fftw_execute_dft_r2c((fftw_plan)plan, (double *)in, (fftw_complex *)out);} template<> inline void PIFFTW_Private::p_destroyPlan(void *& plan) {if (plan) fftw_destroy_plan((fftw_plan)plan); plan = 0;} # ifdef PIP_FFTW_THREADSAFE template<> inline void PIFFTW_Private::p_makeThreadSafe() {fftw_make_planner_thread_safe();} # endif #endif // PIP_FFTW #ifdef PIP_FFTWl template<> inline void PIFFTW_Private::p_createPlan_c2c_1d(void *& plan, int size, const void * in, void * out, int dir, int flags) { plan = fftwl_plan_dft_1d(size, (fftwl_complex *)in, (fftwl_complex *)out, dir, flags);} template<> inline void PIFFTW_Private::p_createPlan_r2c_1d(void *& plan, int size, const void * in, void * out, int flags) { plan = fftwl_plan_dft_r2c_1d(size, (ldouble *)in, (fftwl_complex *)out, flags);} template<> inline void PIFFTW_Private::p_executePlan(void * plan) {fftwl_execute((fftwl_plan)plan);} template<> inline void PIFFTW_Private::p_executePlan_c2c(void * plan, const void * in, void * out) {fftwl_execute_dft((fftwl_plan)plan, (fftwl_complex *)in, (fftwl_complex *)out);} template<> inline void PIFFTW_Private::p_executePlan_r2c(void * plan, const void * in, void * out) {fftwl_execute_dft_r2c((fftwl_plan)plan, (ldouble *)in, (fftwl_complex *)out);} template<> inline void PIFFTW_Private::p_destroyPlan(void *& plan) {if (plan) fftwl_destroy_plan((fftwl_plan)plan); plan = 0;} # ifdef PIP_FFTWl_THREADSAFE template<> inline void PIFFTW_Private::p_makeThreadSafe() {fftwl_make_planner_thread_safe();} # endif #endif // PIP_FFTWl #endif // PIFFT_H