Advertisement
Guest User

simple FFT (template, std::complex, C++11, header-only)

a guest
Dec 3rd, 2013
289
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #ifndef FFT_H_INCLUDED
  2. #define FFT_H_INCLUDED
  3.  
  4.  
  5. //   fft.h - template functions for FFT transform
  6. //   The code is derived from LIBROW FFT code (www.librow.com)
  7.  
  8. #include <complex>
  9.  
  10.  
  11. namespace fft {
  12.  
  13.  
  14.     namespace _ {
  15.  
  16.  
  17.         template<typename T> struct ComplexType { typedef std::complex< typename std::remove_reference<typename std::remove_const<T>::type>::type> type;};
  18.         template<typename T> struct ComplexType<std::complex<T>> {typedef typename std::complex<T> type;};
  19.  
  20.         inline void updateTarget(size_t& target, const size_t size)
  21.         {
  22.             size_t Mask = size;
  23.             while (target & (Mask >>= 1))
  24.                 target &= ~Mask;
  25.             target |= Mask;
  26.         }
  27.  
  28.  
  29.  
  30.         //! @return destination's end iterator
  31.         template<typename IterSrc, typename IterDst>
  32.         IterDst rearrange(IterSrc srcFirst, IterSrc srcLast, IterDst dstFirst)
  33.         {
  34.             const size_t size = srcLast - srcFirst;
  35.             size_t target = 0;
  36.             for (; srcFirst != srcLast; ++srcFirst)
  37.             {
  38.                 *(dstFirst + target) = *srcFirst;
  39.                 updateTarget(target, size);
  40.             }
  41.             return dstFirst + size;
  42.         }
  43.  
  44.  
  45.  
  46.         //! Inplace version of rearrange function
  47.         template<typename IterDst>
  48.         void rearrange(IterDst dstFirst, IterDst dstLast)
  49.         {
  50.             size_t target = 0;
  51.             const size_t size = dstLast - dstFirst;
  52.             for (auto i = dstFirst; i != dstLast; ++i)
  53.             {
  54.                 if (target > size_t(i - dstFirst))
  55.                     std::swap(*i, *(dstFirst + target));
  56.                 updateTarget(target, size);
  57.             }
  58.         }
  59.  
  60.  
  61.         //! Actual direct or inverse FFT on rearranged data
  62.         template<typename IterDst>
  63.         void perform(IterDst dstFirst, IterDst dstLast, const bool inverse = false)
  64.         {
  65.             typedef typename std::remove_reference<decltype(*dstFirst)>::type Complex;
  66.             typedef typename Complex::value_type Number;
  67.             const Number pi = inverse ? Number(3.14159265358979323846) : Number(-3.14159265358979323846);
  68.             const size_t size = dstLast - dstFirst;
  69.             for (size_t step = 1; step < size; step <<= 1)
  70.             {
  71.                 const size_t jump = step << 1;
  72.                 const Number delta = pi / Number(step);
  73.                 const Number sine = std::sin(delta * .5);
  74.                 const Complex multiplier(-2. * sine * sine, std::sin(delta));
  75.                 Complex factor(1.);
  76.                 for (size_t group = 0; group < step; ++group)
  77.                 {
  78.                     for (size_t pair = group; pair < size; pair += jump)
  79.                     {
  80.                         const size_t match = pair + step;
  81.                         const Complex product(factor * dstFirst[match]);
  82.                         dstFirst[match] = dstFirst[pair] - product;
  83.                         dstFirst[pair] += product;
  84.                     }
  85.                     factor = multiplier * factor + factor;
  86.                 }
  87.             }
  88.         }
  89.  
  90.         //! Scaling of inverse FFT result
  91.         template<typename IterDst>
  92.         void scale(IterDst dstFirst, IterDst dstLast)
  93.         {
  94.             typedef typename std::remove_reference<decltype(*dstFirst)>::type Complex;
  95.             typedef typename Complex::value_type Number;
  96.             const Number factor = 1. / Number(dstLast - dstFirst);
  97.             for (; dstFirst != dstLast; ++dstFirst)
  98.                 *dstFirst *= factor;
  99.         }
  100.  
  101.  
  102.  
  103.     }
  104.  
  105.     //! Plain FFT
  106.     //! @tparam IterSrc source iterator (read-only, random access), dereferences to numeric type Number1
  107.     //! @tparam IterDst destination iterator (writeable, random access), dereferences to complex<Number2>, Number2 must be constructible from Number1
  108.     //! @pre dstFirst has capacity at least srcLast - srcFirst, and srcLast - srcFirst must be power of 2
  109.     //! @return destination's end iterator
  110.     template<typename IterSrc, typename IterDst>
  111.     IterDst transform (IterSrc srcFirst, IterSrc srcLast, IterDst dstFirst)
  112.     {
  113.         const auto dstLast = ::fft::_::rearrange(srcFirst, srcLast, dstFirst);
  114.         ::fft::_::perform(dstFirst, dstLast);
  115.         return dstLast;
  116.     }
  117.  
  118.     //! In-place FFT
  119.     //! @tparam IterDst destination iterator (writeable, random access), dereferences to complex<Number>
  120.     //! @pre srcLast - srcFirst must be power of 2
  121.     template<typename IterDst>
  122.     void transform (IterDst dstFirst, IterDst dstLast)
  123.     {
  124.         ::fft::_::rearrange(dstFirst, dstLast);
  125.         ::fft::_::perform(dstFirst, dstLast);
  126.     }
  127.  
  128.     //! Inverse FFT
  129.     //! @tparam IterDst destination iterator (writeable, random access), dereferences to complex<Number>
  130.     //! @pre dstFirst has capacity at least srcLast - srcFirst, and srcLast - srcFirst must be power of 2
  131.     template<typename IterDst>
  132.     void inverse (IterDst srcFirst, IterDst srcLast, IterDst dstFirst, const bool doScale = true)
  133.     {
  134.         const auto dstLast = ::fft::_::rearrange(srcFirst, srcLast, dstFirst);
  135.         ::fft::_::perform(dstFirst, dstLast, true);
  136.         if(doScale)
  137.             ::fft::_::scale(dstFirst, dstLast);
  138.     }
  139.  
  140.     //! In-place inverse FFT
  141.     //! @tparam IterDst destination iterator (writeable, random access), dereferences to complex<Number>
  142.     //! @pre srcLast - srcFirst must be power of 2
  143.     template<typename IterDst>
  144.     void inverse (IterDst dstFirst, IterDst dstLast, const bool doScale = true)
  145.     {
  146.         ::fft::_::rearrange(dstFirst, dstLast);
  147.         ::fft::_::perform(dstFirst, dstLast, true);
  148.         if(doScale)
  149.             ::fft::_::scale(dstFirst, dstLast);
  150.     }
  151.  
  152.  
  153. }
  154.  
  155. #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement