NDEVR
API Documentation
FFT.h
1#pragma once
2#include <NDEVR/Buffer.h>
3#include <NDEVR/Angle.h>
4#include <iostream>
5#include <iomanip>
6#include <complex>
7
8namespace NDEVR
9{
14 template<class t_type>
16 {
17 protected:
26 static void fft(Buffer<std::complex<t_type>>& in_out, Buffer<std::complex<t_type>>& temp, uint04 offset, uint04 size)
27 {
28 // base case
29 if (size == 1)
30 return;
31 if (size % 2 != 0)// Fallback to Basic Discrete Fourier Transform
32 {
33 for (uint04 k = 0; k < size; k++)
34 temp[k + offset] = in_out[k + offset];
35 dft(temp.begin(offset), in_out.begin(offset), size, 1);
36 return;
37 }
38 lib_assert(size % 2 == 0, "Bad FFT");
39
40 uint04 even_offset = offset;
41 uint04 odd_offset = offset + size / 2;
42
43 // compute FFT of even terms
44 for (uint04 k = 0; k < size / 2; k++)
45 temp[k + even_offset] = in_out[2 * k + offset];
46
47 // compute FFT of odd terms
48 for (uint04 k = 0; k < size / 2; k++)
49 temp[k + odd_offset] = in_out[2 * k + 1 + offset];
50
51 fft(temp, in_out, even_offset, size / 2);
52 fft(temp, in_out, odd_offset, size / 2);
53
54 // combine
55 for (uint04 k = 0; k < size / 2; k++)
56 {
57 fltp08 kth = -2.0 * cast<fltp08>(k) * PI<fltp08>() / size;
58 std::complex<t_type> wk(std::cos(kth), std::sin(kth));
59 in_out[k + even_offset] = temp[k + even_offset] + (wk * temp[k + odd_offset]);
60 in_out[k + odd_offset] = temp[k + even_offset] - (wk * temp[k + odd_offset]);
61 }
62 }
63
70 static void dft(const std::complex<t_type> f[], std::complex<t_type> ftilde[], uint04 N, uint04 step)
71 {
72 std::complex<t_type> w = std::polar(1.0, -2.0 * PI<t_type>() / N);
73 std::complex<t_type> wn = 1.0;
74 for (uint04 n = 0; n < N; n++)
75 {
76 if (n > 0) wn *= w;
77 std::complex<t_type> wm = 1.0;
78 ftilde[n] = 0.0;
79 for (uint04 m = 0, mpos = 0; m < N; m++, mpos += step)
80 {
81 if (m > 0) wm *= wn;
82 ftilde[n] += f[mpos] * wm;
83 }
84 }
85 }
86
95 static void ifft(Buffer<std::complex<t_type>>& in_out, Buffer<std::complex<t_type>>& temp, uint04 offset, uint04 size)
96 {
97 // take conjugate
98 for (uint04 i = 0; i < size; i++)
99 in_out[i + offset] = std::conj(in_out[i + offset]);
100
101 // compute forward FFT
102 fft(in_out, temp, offset, size);
103
104 // take conjugate again
105 t_type factor = 1.0 / size;
106 for (uint04 i = 0; i < size; i++)
107 in_out[i + offset] = std::conj(in_out[i + offset]) * factor;
108
109 }
110
111
112
113 //======================================================================
114
121 static void iFFT(const std::complex<t_type> ftilde[], std::complex<t_type> f[], uint04 N)
122 {
123 Buffer<std::complex<t_type>> ftildeConjugate;
124 ftildeConjugate.setSize(N);
125
126 for (uint04 m = 0; m < N; m++)
127 ftildeConjugate[m] = std::conj(ftilde[m]);
128
129 fft(ftildeConjugate, f, N, 1);
130
131 t_type factor = 1.0 / N;
132 for (uint04 m = 0; m < N; m++)
133 f[m] = std::conj(f[m]) * factor;
134
135 }
136 public:
141 static void FT(Buffer<std::complex<t_type>>& in_out)
142 {
144 temp.setSize(in_out.size());
145 fft(in_out, temp, 0, temp.size());
146 }
147
151 static void IFT(Buffer<std::complex<t_type>>& in_out)
152 {
154 temp.setSize(in_out.size());
155 ifft(in_out, temp, 0, temp.size());
156 }
157 };
158
159 /*static Buffer<std::complex<t_type>> fft(const Buffer<std::complex<t_type>>& f) // Fast Fourier Transform
160 {
161 // base case
162 if (f.size() == 1)
163 {
164 return { f[0] };
165 }
166 lib_assert(f.size() % 2 == 0, "Bad FFT");
167
168 Buffer<std::complex<t_type>> buffer;
169 buffer.setSize(f.size() / 2);
170 // compute FFT of even terms
171 for (uint04 k = 0; k < f.size() / 2; k++)
172 buffer[k] = f[2 * k];
173 Buffer<std::complex<t_type>> even_fft = fft(buffer);
174
175 // compute FFT of odd terms
176 for (uint04 k = 0; k < f.size() / 2; k++)
177 buffer[k] = f[2 * k + 1];
178 Buffer<std::complex<t_type>> odd_fft = fft(buffer);
179
180 // combine
181 Buffer<std::complex<t_type>> y;
182 y.setSize(f.size());
183 for (uint04 k = 0; k < f.size() / 2; k++)
184 {
185 fltp08 kth = -2.0 * cast<fltp08>(k) * Angle::PI<fltp08>() / f.size();
186 std::complex<t_type> wk(std::cos(kth), std::sin(kth));
187 y[k ] = even_fft[k] + (wk * odd_fft[k]);
188 y[k + f.size() / 2] = even_fft[k] - (wk * odd_fft[k]);
189 }
190 return y;
191 }
192
193 // compute the inverse FFT of x[], assuming its length n is a power of 2
194 static Buffer<std::complex<t_type>> ifft(const Buffer<std::complex<t_type>>& x)
195 {
196 Buffer<std::complex<t_type>> y;
197 y.setSize(x.size());
198
199 // take conjugate
200 for (uint04 i = 0; i < x.size(); i++)
201 y[i] = std::conj(x[i]);
202
203 // compute forward FFT
204 y = fft(y);
205
206 // take conjugate again
207 t_type factor = 1.0 / x.size();
208 for (uint04 i = 0; i < x.size(); i++)
209 y[i] = std::conj(y[i]) * factor;
210 return y;
211
212 }
213
214 //======================================================================
215
216 static void DFT(const std::complex<t_type> f[], std::complex<t_type> ftilde[], uint04 N, uint04 step) // Basic Discrete Fourier Transform
217 {
218 std::complex<t_type> w = std::polar(1.0, -2.0 * Angle::PI<t_type>() / N);
219 std::complex<t_type> wn = 1.0;
220 for (uint04 n = 0; n < N; n++)
221 {
222 if (n > 0) wn *= w;
223 std::complex<t_type> wm = 1.0;
224 ftilde[n] = 0.0;
225 for (uint04 m = 0, mpos = 0; m < N; m++, mpos += step)
226 {
227 if (m > 0) wm *= wn;
228 ftilde[n] += f[mpos] * wm;
229 }
230 }
231 }
232
233 //======================================================================
234
235 static void iFFT(const std::complex<t_type> ftilde[], std::complex<t_type> f[], uint04 N) // Inverse Fast Fourier Transform
236 {
237 Buffer<std::complex<t_type>> ftildeConjugate;
238 ftildeConjugate.setSize(N);
239
240 for (uint04 m = 0; m < N; m++)
241 ftildeConjugate[m] = std::conj(ftilde[m]);
242
243 FFT(ftildeConjugate, f, N, 1);
244
245 t_type factor = 1.0 / N;
246 for (uint04 m = 0; m < N; m++)
247 f[m] = std::conj(f[m]) * factor;
248
249 }
250 public:
251 static Buffer<std::complex<t_type>> FFT(const Buffer<std::complex<t_type>>& complex, uint04 step = 1)
252 {
253 Buffer<std::complex<t_type>> output;
254 output.setSize(complex.size());
255 FFT(complex.ptr(), output.ptr(), complex.size(), step);
256 return output;
257 }
258 static Buffer<std::complex<t_type>> IFFT(const Buffer<std::complex<t_type>>& complex)
259 {
260 return ifft(complex);
261 }
262 };*/
263}
The equivelent of std::vector but with a bit more control.
Definition Buffer.hpp:58
Provides Fast Fourier Transform logic for converting signals between the time and frequency domains.
Definition FFT.h:16
static void dft(const std::complex< t_type > f[], std::complex< t_type > ftilde[], uint04 N, uint04 step)
Computes the basic Discrete Fourier Transform for arbitrary-length input.
Definition FFT.h:70
static void ifft(Buffer< std::complex< t_type > > &in_out, Buffer< std::complex< t_type > > &temp, uint04 offset, uint04 size)
Computes the inverse FFT by conjugating, applying the forward FFT, then conjugating and scaling the r...
Definition FFT.h:95
static void fft(Buffer< std::complex< t_type > > &in_out, Buffer< std::complex< t_type > > &temp, uint04 offset, uint04 size)
Computes the in-place Fast Fourier Transform using the Cooley-Tukey algorithm.
Definition FFT.h:26
static void IFT(Buffer< std::complex< t_type > > &in_out)
Computes the inverse Fourier Transform on a buffer of complex values in place.
Definition FFT.h:151
static void iFFT(const std::complex< t_type > ftilde[], std::complex< t_type > f[], uint04 N)
Computes the inverse FFT from a frequency-domain array into a time-domain array.
Definition FFT.h:121
static void FT(Buffer< std::complex< t_type > > &in_out)
Computes the forward Fourier Transform on a buffer of complex values in place.
Definition FFT.h:141
The primary namespace for the NDEVR SDK.
uint32_t uint04
-Defines an alias representing a 4 byte, unsigned integer -Can represent exact integer values 0 throu...
double fltp08
Defines an alias representing an 8 byte floating-point number.
static constexpr t_float_type PI()
Returns the value of PI to a given precision.
Definition Angle.h:68
constexpr t_to cast(const Angle< t_from > &value)
Casts an Angle from one backing type to another.
Definition Angle.h:408