LCOV - code coverage report
Current view: top level - Utility - FFT.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 71 109 65.1 %
Date: 2021-02-18 20:07:22 Functions: 14 22 63.6 %

          Line data    Source code
       1             : /**
       2             :  * \file FFT.cpp
       3             :  */
       4             : 
       5             : #include "FFT.h"
       6             : 
       7             : #include <ATK/config.h>
       8             : #if ATK_USE_FFTW == 1
       9             : #include <fftw3.h>
      10             : #endif
      11             : #if ATK_USE_IPP == 1
      12             : #include <ipp.h>
      13             : #endif
      14             : 
      15             : #include <gsl/gsl>
      16             : 
      17             : #include <algorithm>
      18             : #include <complex>
      19             : #include <cstdlib>
      20             : 
      21             : namespace ATK
      22             : {
      23             :   template<class DataType_>
      24             :   class FFT<DataType_>::FFTImpl
      25             :   {
      26             : #if ATK_USE_FFTW == 1
      27             :     fftw_plan fft_plan;
      28             :     fftw_plan fft_reverse_plan;
      29             :     fftw_complex* input_data;
      30             :     fftw_complex* output_freqs;
      31             : #endif
      32             : #if ATK_USE_IPP == 1
      33             :     Ipp64fc *pSrc;
      34             :     Ipp64fc *pDst;
      35             :     IppsFFTSpec_C_64fc* pFFTSpec;
      36             :     IppsDFTSpec_C_64fc* pDFTSpec;
      37             :     Ipp8u* pFFTSpecBuf;
      38             :     Ipp8u* pFFTInitBuf;
      39             :     Ipp8u* pFFTWorkBuf;
      40             :     bool power_of_two;
      41             : #endif
      42             :   public:
      43         332 :     FFTImpl()
      44             : #if ATK_USE_FFTW == 1
      45         332 :     :fft_plan(nullptr), fft_reverse_plan(nullptr), input_data(nullptr), output_freqs(nullptr)
      46             : #endif
      47             : #if ATK_USE_IPP == 1
      48             :     :pSrc(nullptr), pDst(nullptr), pFFTSpec(nullptr), pDFTSpec(nullptr), pFFTSpecBuf(nullptr), pFFTInitBuf(nullptr), pFFTWorkBuf(nullptr), power_of_two(false)
      49             : #endif
      50             :     {
      51         332 :     }
      52             :     
      53         332 :     ~FFTImpl()
      54             :     {
      55             : #if ATK_USE_FFTW == 1
      56         332 :       fftw_free(input_data);
      57         332 :       fftw_free(output_freqs);
      58         332 :       fftw_destroy_plan(fft_plan);
      59         332 :       fftw_destroy_plan(fft_reverse_plan);
      60             : #endif
      61             : #if ATK_USE_IPP == 1
      62             :       if (pSrc)
      63             :       {
      64             :         ippFree(pSrc);
      65             :       }
      66             :       if (pDst)
      67             :       {
      68             :         ippFree(pDst);
      69             :       }
      70             :       if (pFFTSpec)
      71             :       {
      72             :         ippFree(pFFTSpec);
      73             :       }
      74             :       if (pFFTInitBuf)
      75             :       {
      76             :         ippFree(pFFTInitBuf);
      77             :       }
      78             :       if (pFFTWorkBuf)
      79             :       {
      80             :         ippFree(pFFTWorkBuf);
      81             :       }
      82             : #endif
      83         332 :     }
      84             : 
      85         331 :     void set_size(gsl::index size)
      86             :     {
      87             : #if ATK_USE_FFTW == 1
      88         331 :       fftw_free(input_data);
      89         331 :       fftw_free(output_freqs);
      90         331 :       fftw_destroy_plan(fft_plan);
      91         331 :       fftw_destroy_plan(fft_reverse_plan);
      92             :       
      93         331 :       input_data = fftw_alloc_complex(size);
      94         331 :       output_freqs = fftw_alloc_complex(size);
      95             :       
      96         331 :       fft_plan = fftw_plan_dft_1d(size, input_data, output_freqs, FFTW_FORWARD, FFTW_ESTIMATE);
      97         331 :       fft_reverse_plan = fftw_plan_dft_1d(size, output_freqs, input_data, FFTW_BACKWARD, FFTW_ESTIMATE);
      98             : #endif
      99             : #if ATK_USE_IPP == 1
     100             :       power_of_two = ((size & (size - 1)) == 0);
     101             :       if (pSrc)
     102             :       {
     103             :         ippFree(pSrc);
     104             :       }
     105             :       if (pDst)
     106             :       {
     107             :         ippFree(pDst);
     108             :       }
     109             :       if (pFFTSpec)
     110             :       {
     111             :         ippFree(pFFTSpec);
     112             :       }
     113             :       pFFTSpec = nullptr;
     114             :       if (pDFTSpec)
     115             :       {
     116             :         ippFree(pDFTSpec);
     117             :       }
     118             :       pDFTSpec = nullptr;
     119             :       if (pFFTSpecBuf)
     120             :       {
     121             :         ippFree(pFFTSpecBuf);
     122             :       }
     123             :       if (pFFTInitBuf)
     124             :       {
     125             :         ippFree(pFFTInitBuf);
     126             :       }
     127             :       if (pFFTWorkBuf)
     128             :       {
     129             :         ippFree(pFFTWorkBuf);
     130             :       }
     131             :       int sizeFFTSpec, sizeFFTInitBuf, sizeFFTWorkBuf;
     132             :       if (power_of_two)
     133             :       {
     134             :         ippsFFTGetSize_C_64fc(static_cast<int>(std::lround(std::log(size) / std::log(2))), IPP_FFT_DIV_FWD_BY_N, ippAlgHintAccurate, &sizeFFTSpec, &sizeFFTInitBuf, &sizeFFTWorkBuf);
     135             :       }
     136             :       else
     137             :       {
     138             :         ippsDFTGetSize_C_64fc(static_cast<int>(size), IPP_FFT_DIV_FWD_BY_N, ippAlgHintAccurate, &sizeFFTSpec, &sizeFFTInitBuf, &sizeFFTWorkBuf);
     139             :       }
     140             :       
     141             :       pFFTSpecBuf = ippsMalloc_8u(sizeFFTSpec);
     142             :       pFFTInitBuf = ippsMalloc_8u(sizeFFTInitBuf);
     143             :       pFFTWorkBuf = ippsMalloc_8u(sizeFFTWorkBuf);
     144             :       pSrc = ippsMalloc_64fc(static_cast<int>(size));
     145             :       pDst = ippsMalloc_64fc(static_cast<int>(size));
     146             :       if (power_of_two)
     147             :       {
     148             :         ippsFFTInit_C_64fc(&pFFTSpec, static_cast<int>(std::lround(std::log(size) / std::log(2))), IPP_FFT_DIV_FWD_BY_N, ippAlgHintAccurate, pFFTSpecBuf, pFFTInitBuf);
     149             :       }
     150             :       else
     151             :       {
     152             :         pDFTSpec = (IppsDFTSpec_C_64fc*)ippsMalloc_8u(sizeFFTSpec);
     153             :         ippsDFTInit_C_64fc(static_cast<int>(size), IPP_FFT_DIV_FWD_BY_N, ippAlgHintAccurate, pDFTSpec, pFFTInitBuf);
     154             :       }
     155             :       if (pFFTInitBuf)
     156             :         ippFree(pFFTInitBuf);
     157             :       pFFTInitBuf = nullptr;
     158             : #endif
     159         331 :     }
     160             : 
     161       17106 :     void process(const DataType_* input, gsl::index input_size, gsl::index size) const
     162             :     {
     163             : #if ATK_USE_FFTW == 1
     164       17106 :       double factor = static_cast<double>(size);
     165    41648000 :       for(gsl::index j = 0; j < std::min(input_size, size); ++j)
     166             :       {
     167    41630900 :         input_data[j][0] = input[j] / factor;
     168    41630900 :         input_data[j][1] = 0;
     169             :       }
     170     2134690 :       for(gsl::index j = input_size; j < size; ++j)
     171             :       {
     172     2117590 :         input_data[j][0] = 0;
     173     2117590 :         input_data[j][1] = 0;
     174             :       }
     175       17106 :       fftw_execute(fft_plan);
     176             : #endif
     177             : #if ATK_USE_IPP == 1
     178             :       for (gsl::index j = 0; j < std::min(input_size, size); ++j)
     179             :       {
     180             :         pSrc[j].re = input[j];
     181             :         pSrc[j].im = 0;
     182             :       }
     183             :       for (gsl::index j = input_size; j < size; ++j)
     184             :       {
     185             :         pSrc[j].re = 0;
     186             :         pSrc[j].im = 0;
     187             :       }
     188             :       if (power_of_two)
     189             :       {
     190             :         ippsFFTFwd_CToC_64fc(pSrc, pDst, pFFTSpec, pFFTWorkBuf);
     191             :       }
     192             :       else
     193             :       {
     194             :         ippsDFTFwd_CToC_64fc(pSrc, pDst, pDFTSpec, pFFTWorkBuf);
     195             :       }
     196             : #endif
     197       17106 :     }
     198             :     
     199       16498 :     void process_forward(std::complex<DataType_>* output, gsl::index size) const
     200             :     {
     201     4246760 :       for(gsl::index j = 0; j < size; ++j)
     202             :       {
     203             : #if ATK_USE_FFTW == 1
     204     4230260 :         output[j] = std::complex<DataType_>(output_freqs[j][0], output_freqs[j][1]);
     205             : #endif
     206             : #if ATK_USE_IPP == 1
     207             :         output[j] = std::complex<DataType_>(pDst[j].re, pDst[j].im);
     208             : #endif
     209             :       }
     210       16498 :     }
     211             :     
     212       16402 :     void process_backward(const std::complex<DataType_>* input, DataType_* output, gsl::index input_size, gsl::index size) const
     213             :     {
     214             : #if ATK_USE_FFTW == 1
     215     4213860 :       for(gsl::index j = 0; j < size; ++j)
     216             :       {
     217     4197460 :         output_freqs[j][0] = input[j].real();
     218     4197460 :         output_freqs[j][1] = input[j].imag();
     219             :       }
     220       16402 :       fftw_execute(fft_reverse_plan);
     221     4213860 :       for(gsl::index j = 0; j < input_size; ++j)
     222             :       {
     223     4197460 :         output[j] = input_data[j][0];
     224             :       }
     225             : #endif
     226             : #if ATK_USE_IPP == 1
     227             :       for (gsl::index j = 0; j < size; ++j)
     228             :       {
     229             :         pDst[j].re = input[j].real();
     230             :         pDst[j].im = input[j].imag();
     231             :       }
     232             :       if (power_of_two)
     233             :       {
     234             :         ippsFFTInv_CToC_64fc(pDst, pDst, pFFTSpec, pFFTWorkBuf);
     235             :       }
     236             :       else
     237             :       {
     238             :         ippsDFTInv_CToC_64fc(pDst, pDst, pDFTSpec, pFFTWorkBuf);
     239             :       }
     240             :       for (gsl::index j = 0; j < input_size; ++j)
     241             :       {
     242             :         output[j] = pDst[j].re;
     243             :       }
     244             : #endif
     245       16402 :     }
     246             : 
     247           0 :     void process(const std::complex<DataType_>* input, gsl::index input_size, gsl::index size) const
     248             :     {
     249             : #if ATK_USE_FFTW == 1
     250           0 :       double factor = static_cast<double>(size);
     251           0 :       for (gsl::index j = 0; j < std::min(input_size, size); ++j)
     252             :       {
     253           0 :         input_data[j][0] = std::real(input[j]) / factor;
     254           0 :         input_data[j][1] = std::imag(input[j]) / factor;
     255             :       }
     256           0 :       for (gsl::index j = input_size; j < size; ++j)
     257             :       {
     258           0 :         input_data[j][0] = 0;
     259           0 :         input_data[j][1] = 0;
     260             :       }
     261           0 :       fftw_execute(fft_plan);
     262             : #endif
     263             : #if ATK_USE_IPP == 1
     264             :       for (gsl::index j = 0; j < std::min(input_size, size); ++j)
     265             :       {
     266             :         pSrc[j].re = std::real(input[j]);
     267             :         pSrc[j].im = std::imag(input[j]);
     268             :       }
     269             :       for (gsl::index j = input_size; j < size; ++j)
     270             :       {
     271             :         pSrc[j].re = 0;
     272             :         pSrc[j].im = 0;
     273             :       }
     274             :       if (power_of_two)
     275             :       {
     276             :         ippsFFTFwd_CToC_64fc(pSrc, pDst, pFFTSpec, pFFTWorkBuf);
     277             :       }
     278             :       else
     279             :       {
     280             :         ippsDFTFwd_CToC_64fc(pSrc, pDst, pDFTSpec, pFFTWorkBuf);
     281             :       }
     282             : #endif
     283           0 :     }
     284             :     
     285           0 :     void process_backward(const std::complex<DataType_>* input, std::complex<DataType_>* output, gsl::index input_size, gsl::index size) const
     286             :     {
     287             : #if ATK_USE_FFTW == 1
     288           0 :       for (gsl::index j = 0; j < size; ++j)
     289             :       {
     290           0 :         output_freqs[j][0] = input[j].real();
     291           0 :         output_freqs[j][1] = input[j].imag();
     292             :       }
     293           0 :       fftw_execute(fft_reverse_plan);
     294           0 :       for (gsl::index j = 0; j < input_size; ++j)
     295             :       {
     296           0 :         output[j] = std::complex<DataType_>(input_data[j][0], input_data[j][1]);
     297             :       }
     298             : #endif
     299             : #if ATK_USE_IPP == 1
     300             :       for (gsl::index j = 0; j < size; ++j)
     301             :       {
     302             :         pDst[j].re = input[j].real();
     303             :         pDst[j].im = input[j].imag();
     304             :       }
     305             :       if (power_of_two)
     306             :       {
     307             :         ippsFFTInv_CToC_64fc(pDst, pDst, pFFTSpec, pFFTWorkBuf);
     308             :       }
     309             :       else
     310             :       {
     311             :         ippsDFTInv_CToC_64fc(pDst, pDst, pDFTSpec, pFFTWorkBuf);
     312             :       }
     313             :       for (gsl::index j = 0; j < input_size; ++j)
     314             :       {
     315             :         output[j] = std::complex<DataType_>(pDst[j].re, pDst[j].im);
     316             :       }
     317             : #endif
     318           0 :     }
     319             :     
     320         608 :     void get_amp(std::vector<DataType_>& amp) const
     321             :     {
     322    19760300 :       for(size_t i = 0; i < amp.size(); ++i)
     323             :       {
     324             : #if ATK_USE_FFTW == 1
     325    19759700 :         amp[i] = output_freqs[i][0] * output_freqs[i][0];
     326    19759700 :         amp[i] += output_freqs[i][1] * output_freqs[i][1];
     327    19759700 :         amp[i] = std::sqrt(amp[i]);
     328             : #endif
     329             : #if ATK_USE_IPP == 1
     330             :         amp[i] = pDst[i].re * pDst[i].re;
     331             :         amp[i] += pDst[i].im * pDst[i].im;
     332             :         amp[i] = std::sqrt(amp[i]);
     333             : #endif
     334             :       }
     335         608 :     }
     336             :     
     337           0 :     void get_angle(std::vector<DataType_>& angle) const
     338             :     {
     339           0 :       for(size_t i = 0; i < angle.size(); ++i)
     340             :       {
     341             : #if ATK_USE_FFTW == 1
     342           0 :         angle[i] = std::arg(std::complex<DataType_>(output_freqs[i][0], output_freqs[i][1]));
     343             : #endif
     344             : #if ATK_USE_IPP == 1
     345             :         angle[i] = std::arg(std::complex<DataType_>(pDst[i].re, pDst[i].im));
     346             : #endif
     347             :       }
     348           0 :     }
     349             :   };
     350             : 
     351             :   template<class DataType_>
     352         332 :   FFT<DataType_>::FFT()
     353         332 :   :size(0), impl(std::make_unique<FFTImpl>())
     354             :   {
     355         332 :   }
     356             :   
     357             : 
     358             :   template<class DataType_>
     359         332 :   FFT<DataType_>::~FFT()
     360             :   {
     361         332 :   }
     362             : 
     363             :   template<class DataType_>
     364         332 :   void FFT<DataType_>::set_size(gsl::index size_)
     365             :   {
     366         332 :     if(size == size_)
     367             :     {
     368           1 :       return;
     369             :     }
     370         331 :     size = size_;
     371         331 :     impl->set_size(size);
     372             :   }
     373             : 
     374             :   template<class DataType_>
     375           0 :   gsl::index FFT<DataType_>::get_size() const
     376             :   {
     377           0 :     return size;
     378             :   }
     379             : 
     380             :   template<class DataType_>
     381       17106 :   void FFT<DataType_>::process(const DataType_* input, gsl::index input_size) const
     382             :   {
     383       17106 :     impl->process(input, input_size, size);
     384       17106 :   }
     385             :   
     386             :   template<class DataType_>
     387       16498 :   void FFT<DataType_>::process_forward(const DataType_* input, std::complex<DataType_>* output, gsl::index input_size) const
     388             :   {
     389       16498 :     process(input, input_size);
     390       16498 :     impl->process_forward(output, size);
     391       16498 :   }
     392             : 
     393             :   template<class DataType_>
     394       16402 :   void FFT<DataType_>::process_backward(const std::complex<DataType_>* input, DataType_* output, gsl::index input_size) const
     395             :   {
     396       16402 :     impl->process_backward(input, output, input_size, size);
     397       16402 :   }
     398             : 
     399             :   template<class DataType_>
     400           0 :   void FFT<DataType_>::process(const std::complex<DataType_>* input, gsl::index input_size) const
     401             :   {
     402           0 :     impl->process(input, input_size, size);
     403           0 :   }
     404             : 
     405             :   template<class DataType_>
     406           0 :   void FFT<DataType_>::process_forward(const std::complex<DataType_>* input, std::complex<DataType_>* output, gsl::index input_size) const
     407             :   {
     408           0 :     process(input, input_size);
     409           0 :     impl->process_forward(output, size);
     410           0 :   }
     411             : 
     412             :   template<class DataType_>
     413           0 :   void FFT<DataType_>::process_backward(const std::complex<DataType_>* input, std::complex<DataType_>* output, gsl::index input_size) const
     414             :   {
     415           0 :     impl->process_backward(input, output, input_size, size);
     416           0 :   }
     417             : 
     418             :   template<class DataType_>
     419         608 :   void FFT<DataType_>::get_amp(std::vector<DataType_>& amp) const
     420             :   {
     421         608 :     amp.assign(size / 2 + 1, 0);
     422         608 :     impl->get_amp(amp);
     423         608 :   }
     424             :   
     425             :   template<class DataType_>
     426           0 :   void FFT<DataType_>::get_angle(std::vector<DataType_>& angle) const
     427             :   {
     428           0 :     angle.assign(size / 2 + 1, 0);
     429           0 :     impl->get_angle(angle);
     430           0 :   }
     431             : 
     432             :   template class FFT<double>;
     433             : }

Generated by: LCOV version TK-3.3.0-4-gdba42eea