/home/docs/checkouts/readthedocs.org/user_builds/ratpac/checkouts/latest/src/util/include/RAT/FFTW1DTransformer.hh Source File

Ratpac-two: /home/docs/checkouts/readthedocs.org/user_builds/ratpac/checkouts/latest/src/util/include/RAT/FFTW1DTransformer.hh Source File
Ratpac-two
FFTW1DTransformer.hh
1 
14 #ifndef __RAT_FFTW1DTRANSFORMER_HH__
15 #define __RAT_FFTW1DTRANSFORMER_HH__
16 
17 #include <fftw3.h>
18 
19 #include <RAT/Log.hh>
20 #include <complex>
21 #include <memory>
22 #include <stdexcept>
23 #include <vector>
24 
26  public:
30  enum class direction_t {
31  FORWARD = FFTW_FORWARD,
32  INVERSE = FFTW_BACKWARD
33  };
34 
41  FFTW1DTransformer(size_t size, direction_t direction = direction_t::FORWARD, unsigned flag = FFTW_MEASURE)
42  : fft_size(size), fft_direction(direction) {
43  if (size == 0) {
44  throw std::invalid_argument("FFTW1DTransformer: size must be greater than 0");
45  }
46  if ((size & (size - 1)) != 0) { // bitwise check for power of two
47  RAT::info << "FFTW1DTransformer: size is not a power of two: " << size
48  << ". This may lead to suboptimal performance." << newline;
49  }
50  rbuf = std::unique_ptr<double[], buf_deleter>(fftw_alloc_real(size));
51  cbuf = std::unique_ptr<fftw_complex[], buf_deleter>(fftw_alloc_complex(size / 2 + 1));
52  if (direction == direction_t::FORWARD) {
53  plan = fftw_plan_dft_r2c_1d(static_cast<int>(size), rbuf.get(), cbuf.get(), flag);
54  } else {
55  plan = fftw_plan_dft_c2r_1d(static_cast<int>(size), cbuf.get(), rbuf.get(), flag);
56  }
57 
58  if (!plan) {
59  throw std::runtime_error("FFTW1DTransformer: Failed to create FFTW plan");
60  }
61  }
62 
63  ~FFTW1DTransformer() { fftw_destroy_plan(plan); }
64 
65  size_t GetSize() const { return fft_size; }
66 
68  std::vector<std::complex<double>> transform(const std::vector<double>& input) {
69  if (fft_direction != direction_t::FORWARD) {
70  throw std::runtime_error("FFTW1DTransformer: This transformer is not configured for forward FFT.");
71  }
72 
73  if (input.size() > fft_size) {
74  throw std::invalid_argument("FFTW1DTransformer: Input size exceeds FFT size.");
75  }
76 
77  std::fill(rbuf.get(), rbuf.get() + fft_size, 0.0);
78  std::copy(input.begin(), input.end(), rbuf.get());
79 
80  fftw_execute(plan);
81 
82  // assumes fftw_complex is directly compatible with std::complex<double>
83  return std::vector<std::complex<double>>(reinterpret_cast<std::complex<double>*>(cbuf.get()),
84  reinterpret_cast<std::complex<double>*>(cbuf.get() + fft_size / 2 + 1));
85  }
86 
88  std::vector<double> transform(const std::vector<std::complex<double>>& input) {
89  if (input.size() != fft_size / 2 + 1) {
90  throw std::invalid_argument("FFTW1DTransformer: Input size does not match FFT size for inverse transform.");
91  }
92  ifft(input.data(), rbuf.get());
93  std::vector<double> result(fft_size);
94  for (size_t i = 0; i < fft_size; ++i) {
95  result[i] = rbuf[i];
96  }
97  return result;
98  }
99 
101  void ifft(const std::complex<double>* input, double* output) {
102  if (fft_direction != direction_t::INVERSE) {
103  throw std::runtime_error("FFTW1DTransformer: This transformer is not configured for inverse FFT.");
104  }
105 
106  fftw_execute_dft_c2r(plan, reinterpret_cast<fftw_complex*>(const_cast<std::complex<double>*>(input)), output);
107 
108  // normalize the result
109  for (size_t i = 0; i < fft_size; ++i) {
110  output[i] /= static_cast<double>(fft_size);
111  }
112  }
113 
114  protected:
115  // Deleter for managing i/o buffers.
116  struct buf_deleter {
117  void operator()(double* p) const { fftw_free(p); }
118  void operator()(fftw_complex* p) const { fftw_free(p); }
119  };
120  size_t fft_size;
121  direction_t fft_direction;
122  fftw_plan plan;
123  std::unique_ptr<double[], buf_deleter> rbuf; // for time domain.
124  std::unique_ptr<fftw_complex[], buf_deleter> cbuf; // for frequency domain.
125 };
126 
127 #endif // __RAT_FFTW1DTRANSFORMER_HH__
A class for performing 1D FFTs using the FFTW library.
Definition: FFTW1DTransformer.hh:25
void ifft(const std::complex< double > *input, double *output)
Inverse transformation. Performant version since user can use fftw_malloc to ensure alignment.
Definition: FFTW1DTransformer.hh:101
std::vector< std::complex< double > > transform(const std::vector< double > &input)
Forward transformation.
Definition: FFTW1DTransformer.hh:68
direction_t
Represents the direction of the FFT transformation.
Definition: FFTW1DTransformer.hh:30
@ INVERSE
Forward FFT Transformation. Real to complex.
FFTW1DTransformer(size_t size, direction_t direction=direction_t::FORWARD, unsigned flag=FFTW_MEASURE)
Constructor for FFTW1DTransformer.
Definition: FFTW1DTransformer.hh:41
std::vector< double > transform(const std::vector< std::complex< double >> &input)
Inverse transformation.
Definition: FFTW1DTransformer.hh:88
Definition: FFTW1DTransformer.hh:116