CalcMySky  v0.3.1
fourier-interpolation.hpp
1 #ifndef INCLUDE_ONCE_3A48838B_2D1A_4326_9585_2E19F9D300D1
2 #define INCLUDE_ONCE_3A48838B_2D1A_4326_9585_2E19F9D300D1
3 
4 #include <algorithm>
5 #include <unsupported/Eigen/FFT>
6 
7 void fourierInterpolate(float const*const points, const std::size_t inPointCount,
8  std::complex<float>*const intermediate /* must fit interpolationPointCount elements */,
9  float*const interpolated, std::size_t const interpolationPointCount)
10 {
11  if(inPointCount==interpolationPointCount)
12  {
13  std::copy_n(points, inPointCount, interpolated);
14  return;
15  }
16 
17  assert(interpolationPointCount > inPointCount);
18 
19  Eigen::FFT<float> fft;
20  fft.fwd(intermediate, points, inPointCount);
21  if(inPointCount % 2)
22  {
23  const auto fftHalfCount=(inPointCount+1)/2;
24  // Clear upper half of the spectrum. Since Eigen inverse FFT ignores upper half when output
25  // type is real, don't bother preserving it in extended spectrum.
26  std::fill_n(intermediate+fftHalfCount, interpolationPointCount-fftHalfCount, 0);
27  }
28  else
29  {
30  const auto fftHalfCount=inPointCount/2;
31  // Nyquist frequency gets split into two half-amplitude components in the two sides of the spectrum.
32  // So we need to 1) avoid zeroing this spectral component out, and 2) divide both its instances by 2.
33  // In practice, since Eigen ignores upper half of the spectrum when output type of inverse transform
34  // is real, we don't bother saving/moving/dividing the upper entries, and just zero them out too.
35  // So only the lower instance of Nyquist frequency amplitude remains to be divided.
36  const auto numPreservedElems=fftHalfCount+1;
37  std::fill_n(intermediate+numPreservedElems, interpolationPointCount-numPreservedElems, 0);
38  intermediate[fftHalfCount] /= 2;
39  }
40  fft.inv(interpolated, intermediate, interpolationPointCount);
41  for(std::size_t i=0; i<interpolationPointCount; ++i)
42  interpolated[i] *= float(interpolationPointCount)/inPointCount;
43 }
44 
45 #endif