SigPack - the C++ signal processing library
 
Loading...
Searching...
No Matches
fftw.h
Go to the documentation of this file.
1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at http://mozilla.org/MPL/2.0/.
4#ifndef SP_FFTW_H
5#define SP_FFTW_H
6#include <fftw3.h>
7
8namespace sp
9{
18
25class FFTW
26{
27 private:
28 fftw_plan pl_fft;
29 fftw_plan pl_ifft;
30 fftw_plan pl_fft_cx;
31 fftw_plan pl_ifft_cx;
32 unsigned int N;
33 unsigned int R, C;
34 int alg;
38 public:
44 FFTW( unsigned int _N, int _alg = FFTW_ESTIMATE )
45 {
46 N = _N;
47 R = 0;
48 C = 0;
49 alg = _alg;
50 export_alg = FFTW_PATIENT;
51 pl_fft = NULL;
52 pl_ifft = NULL;
53 pl_fft_cx = NULL;
54 pl_ifft_cx = NULL;
55 }
56
63 FFTW( unsigned int _R, unsigned int _C, int _alg )
64 {
65 R = _R;
66 C = _C;
67 N = 0;
68 alg = _alg;
69 export_alg = FFTW_PATIENT;
70 pl_fft = NULL;
71 pl_ifft = NULL;
72 pl_fft_cx = NULL;
73 pl_ifft_cx = NULL;
74 }
75
80 {
81 if( pl_fft != NULL )
82 fftw_destroy_plan( pl_fft );
83 if( pl_ifft != NULL )
84 fftw_destroy_plan( pl_ifft );
85 if( pl_fft_cx != NULL )
86 fftw_destroy_plan( pl_fft_cx );
87 if( pl_ifft_cx != NULL )
88 fftw_destroy_plan( pl_ifft_cx );
89 fftw_cleanup();
90 }
91
97 void fft_cx( arma::cx_vec& x, arma::cx_vec& Pxx )
98 {
99 fftw_complex* in = reinterpret_cast<fftw_complex*>( x.memptr() );
100 fftw_complex* out = reinterpret_cast<fftw_complex*>( Pxx.memptr() );
101 if( pl_fft_cx == NULL )
102 {
103 pl_fft_cx = fftw_plan_dft_1d( N, in, out, FFTW_FORWARD, alg );
104 if( pl_fft_cx == NULL )
105 {
106 err_handler( "Unable to create complex data FFTW plan" );
107 }
108 }
109 fftw_execute_dft( pl_fft_cx, in, out );
110 }
111
117 arma::cx_vec fft_cx( arma::cx_vec& x )
118 {
119 arma::cx_vec Pxx( N );
120 fft_cx( x, Pxx );
121 return Pxx;
122 }
123
129 void ifft_cx( arma::cx_vec& Pxx, arma::cx_vec& x )
130 {
131 fftw_complex* in = reinterpret_cast<fftw_complex*>( Pxx.memptr() );
132 fftw_complex* out = reinterpret_cast<fftw_complex*>( x.memptr() );
133 if( pl_ifft_cx == NULL )
134 {
135 pl_ifft_cx = fftw_plan_dft_1d( N, in, out, FFTW_BACKWARD, alg );
136 if( pl_ifft_cx == NULL )
137 {
138 err_handler( "Unable to create complex data IFFTW plan" );
139 }
140 }
141 fftw_execute_dft( pl_ifft_cx, in, out );
142 x /= N;
143 }
144
150 arma::cx_vec ifft_cx( arma::cx_vec& Pxx )
151 {
152 arma::cx_vec x( N );
153 ifft_cx( Pxx, x );
154 return x;
155 }
156
162 void fft( arma::vec& x, arma::cx_vec& Pxx )
163 {
164 double* in = x.memptr();
165 fftw_complex* out = reinterpret_cast<fftw_complex*>( Pxx.memptr() );
166 if( pl_fft == NULL )
167 {
168 pl_fft = fftw_plan_dft_r2c_1d( N, in, out, alg );
169 if( pl_fft == NULL )
170 {
171 err_handler( "Unable to create real data FFTW plan" );
172 }
173 }
174
175 fftw_execute_dft_r2c( pl_fft, in, out );
176 int offset = static_cast<int>( ceil( N / 2.0 ) );
177 int n_elem = N - offset;
178 for( int i = 0; i < n_elem; ++i )
179 {
180 Pxx( offset + i ) = std::conj( Pxx( n_elem - i ) );
181 }
182 }
183
188 arma::cx_vec fft( arma::vec& x )
189 {
190 arma::cx_vec Pxx( N );
191 fft( x, Pxx );
192 return Pxx;
193 }
194
200 void ifft( arma::cx_vec& Pxx, arma::vec& x )
201 {
202 fftw_complex* in = reinterpret_cast<fftw_complex*>( Pxx.memptr() );
203 double* out = x.memptr();
204 if( pl_ifft == NULL )
205 {
206 pl_ifft = fftw_plan_dft_c2r_1d( N, in, out, alg );
207 if( pl_ifft == NULL )
208 {
209 err_handler( "Unable to create real data IFFTW plan" );
210 }
211 }
212 fftw_execute_dft_c2r( pl_ifft, in, out );
213 x /= N;
214 }
215
221 arma::vec ifft( arma::cx_vec& Pxx )
222 {
223 arma::vec x( N );
224 ifft( Pxx, x );
225 return x;
226 }
227
233 void fft2( arma::mat& x, arma::cx_mat& Pxx )
234 {
235 arma::cx_mat Ptmp( R / 2 + 1, C, arma::fill::ones );
236 double* in = x.memptr();
237 fftw_complex* out = reinterpret_cast<fftw_complex*>( Ptmp.memptr() );
238 if( pl_fft == NULL )
239 {
240 pl_fft = fftw_plan_dft_r2c_2d( C, R, in, out,
241 alg ); // Column to row-major order trick: switch C and R
242 if( pl_fft == NULL )
243 {
244 err_handler( "Unable to create real data FFTW plan" );
245 }
246 }
247
248 fftw_execute_dft_r2c( pl_fft, in, out );
249
250 // Reshape Pxx - upper half
251 std::complex<double>* ptr = reinterpret_cast<std::complex<double>*>( out );
252 const unsigned int Roff = R / 2 + 1;
253 for( unsigned int r = 0; r < Roff; r++ )
254 {
255 for( unsigned int c = 0; c < C; c++ )
256 {
257 Pxx( r, c ) = ptr[r + c * Roff];
258 }
259 }
260 // Reshape Pxx - conj symmetry
261 for( unsigned int r = Roff; r < R; r++ )
262 {
263 Pxx( r, 0 ) = conj( ptr[R - r] );
264 for( unsigned int c = 1; c < C; c++ )
265 {
266 Pxx( r, c ) = conj( ptr[R - r + ( C - c ) * Roff] );
267 }
268 }
269 }
270
275 arma::cx_mat fft2( arma::mat& x )
276 {
277 arma::cx_mat Pxx( R, C, arma::fill::ones );
278 fft2( x, Pxx );
279 return Pxx;
280 }
281
287 void ifft2( arma::cx_mat& Pxx, arma::mat& x )
288 {
289 // Reshape to row-major format
290 unsigned int Roff = R / 2 + 1;
291 arma::cx_mat Ptmp( Roff, C );
292 std::complex<double>* ptr = reinterpret_cast<std::complex<double>*>( Ptmp.memptr() );
293 for( unsigned int r = 0; r < Roff; r++ )
294 {
295 for( unsigned int c = 0; c < C; c++ )
296 {
297 ptr[r + c * Roff] = Pxx( r, c );
298 }
299 }
300
301 fftw_complex* in = reinterpret_cast<fftw_complex*>( Ptmp.memptr() );
302 double* out = x.memptr();
303 if( pl_ifft == NULL )
304 {
305 pl_ifft = fftw_plan_dft_c2r_2d( C, R, in, out, alg );
306 if( pl_ifft == NULL )
307 {
308 err_handler( "Unable to create real data IFFTW plan" );
309 }
310 }
311 fftw_execute_dft_c2r( pl_ifft, in, out );
312 x /= ( R * C );
313 }
314
320 arma::mat ifft2( arma::cx_mat& Pxx )
321 {
322 arma::mat x( R, C );
323 ifft2( Pxx, x );
324 return x;
325 }
326
331 void import_wisdom_string( const std::string wisd )
332 {
333 int res = fftw_import_wisdom_from_string( wisd.c_str() );
334 if( res == 0 )
335 err_handler( "Unable to import wisdom from string!" );
336 }
337
342 void import_wisdom_file( const std::string fname )
343 {
344 int res = fftw_import_wisdom_from_filename( fname.c_str() );
345 if( res == 0 )
346 err_handler( "Unable to import wisdom from file!" );
347 }
348
353 void export_wisdom_fft( const std::string fname )
354 {
355 fftw_plan pl_w = NULL;
356 double* x_r;
357 fftw_complex* x_cx1;
358
359 if( R == 0 || C == 0 ) // 1D
360 {
361 x_r = fftw_alloc_real( N );
362 x_cx1 = fftw_alloc_complex( N );
363
364 // Replan using wisdom
365 pl_w = fftw_plan_dft_r2c_1d( N, x_r, x_cx1, export_alg );
366 }
367 else // 2D
368 {
369 x_r = fftw_alloc_real( R * C );
370 x_cx1 = fftw_alloc_complex( R * C );
371
372 // Replan using wisdom
373 pl_w = fftw_plan_dft_r2c_2d( C, R, x_r, x_cx1, export_alg );
374 }
375 if( pl_w == NULL )
376 {
377 err_handler( "Unable to create real data FFTW plan" );
378 }
379
380 // Export
381 if( fftw_export_wisdom_to_filename( fname.c_str() ) == 0 )
382 {
383 err_handler( "Could not export wisdom to file!" );
384 }
385
386 fftw_destroy_plan( pl_w );
387 fftw_free( x_r );
388 fftw_free( x_cx1 );
389 }
390
395 void export_wisdom_ifft( const std::string fname )
396 {
397 fftw_plan pl_w = NULL;
398 double* x_r;
399 fftw_complex* x_cx1;
400
401 if( R == 0 || C == 0 ) // 1D
402 {
403 x_r = fftw_alloc_real( N );
404 x_cx1 = fftw_alloc_complex( N );
405
406 // Replan using wisdom
407 pl_w = fftw_plan_dft_c2r_1d( N, x_cx1, x_r, export_alg );
408 }
409 else // 2D
410 {
411 x_r = fftw_alloc_real( R * C );
412 x_cx1 = fftw_alloc_complex( R * C );
413
414 // Replan using wisdom
415 pl_w = fftw_plan_dft_c2r_2d( C, R, x_cx1, x_r, export_alg );
416 }
417
418 if( pl_w == NULL )
419 {
420 err_handler( "Unable to create real data FFTW plan" );
421 }
422
423 // Export
424 if( fftw_export_wisdom_to_filename( fname.c_str() ) == 0 )
425 {
426 err_handler( "Could not export wisdom to file!" );
427 }
428
429 fftw_destroy_plan( pl_w );
430 fftw_free( x_r );
431 fftw_free( x_cx1 );
432 }
433
438 void export_wisdom_fft_cx( const std::string fname )
439 {
440 fftw_plan pl_w = NULL;
441 fftw_complex *x_cx1, *x_cx2;
442
443 if( R == 0 || C == 0 ) // 1D
444 {
445 x_cx1 = fftw_alloc_complex( N );
446 x_cx2 = fftw_alloc_complex( N );
447
448 // Replan using wisdom
449 pl_w = fftw_plan_dft_1d( N, x_cx1, x_cx2, FFTW_FORWARD, export_alg );
450 }
451 else
452 {
453 x_cx1 = fftw_alloc_complex( R * C );
454 x_cx2 = fftw_alloc_complex( R * C );
455
456 // Replan using wisdom
457 pl_w = fftw_plan_dft_2d( C, R, x_cx1, x_cx2, FFTW_FORWARD, export_alg );
458 }
459
460 if( pl_w == NULL )
461 {
462 err_handler( "Unable to create complex data FFTW plan" );
463 }
464
465 // Export
466 if( fftw_export_wisdom_to_filename( fname.c_str() ) == 0 )
467 {
468 err_handler( "Could not export wisdom to file!" );
469 }
470
471 fftw_destroy_plan( pl_w );
472 fftw_free( x_cx1 );
473 fftw_free( x_cx2 );
474 }
475
480 void export_wisdom_ifft_cx( const std::string fname )
481 {
482 fftw_plan pl_w = NULL;
483 fftw_complex *x_cx1, *x_cx2;
484
485 if( R == 0 || C == 0 ) // 1D
486 {
487 x_cx1 = fftw_alloc_complex( N );
488 x_cx2 = fftw_alloc_complex( N );
489
490 // Replan using wisdom
491 pl_w = fftw_plan_dft_1d( N, x_cx2, x_cx1, FFTW_BACKWARD, export_alg );
492 }
493 else
494 {
495 x_cx1 = fftw_alloc_complex( R * C );
496 x_cx2 = fftw_alloc_complex( R * C );
497
498 // Replan using wisdom
499 pl_w = fftw_plan_dft_2d( C, R, x_cx2, x_cx1, FFTW_BACKWARD, export_alg );
500 }
501 if( pl_w == NULL )
502 {
503 err_handler( "Unable to create complex data IFFTW plan" );
504 }
505
506 // Export
507 if( fftw_export_wisdom_to_filename( fname.c_str() ) == 0 )
508 {
509 err_handler( "Could not export wisdom to file!" );
510 }
511
512 fftw_destroy_plan( pl_w );
513 fftw_free( x_cx1 );
514 fftw_free( x_cx2 );
515 }
516};
517
519
520} // namespace sp
521#endif
FFTW class.
Definition fftw.h:26
void ifft_cx(arma::cx_vec &Pxx, arma::cx_vec &x)
Inverse FFT.
Definition fftw.h:129
fftw_plan pl_fft_cx
Complex FFTW plan.
Definition fftw.h:30
int alg
plans](http://fftw.org/fftw3_doc/Planner-Flags.html#Planner-Flags)
Definition fftw.h:34
arma::cx_vec fft(arma::vec &x)
FFT of real input.
Definition fftw.h:188
FFTW(unsigned int _N, int _alg=FFTW_ESTIMATE)
Constructor.
Definition fftw.h:44
fftw_plan pl_ifft
Real IFFTW plan.
Definition fftw.h:29
arma::mat ifft2(arma::cx_mat &Pxx)
Inverse FFT.
Definition fftw.h:320
arma::cx_mat fft2(arma::mat &x)
FFT of real 2D input.
Definition fftw.h:275
FFTW(unsigned int _R, unsigned int _C, int _alg)
Constructor.
Definition fftw.h:63
void export_wisdom_ifft_cx(const std::string fname)
Export complex IFFT wisdom to file.
Definition fftw.h:480
unsigned int R
Definition fftw.h:33
arma::vec ifft(arma::cx_vec &Pxx)
Inverse FFT.
Definition fftw.h:221
void export_wisdom_fft_cx(const std::string fname)
Export complex FFT wisdom to file.
Definition fftw.h:438
~FFTW()
Destructor.
Definition fftw.h:79
fftw_plan pl_ifft_cx
Complex IFFTW plan.
Definition fftw.h:31
void fft2(arma::mat &x, arma::cx_mat &Pxx)
FFT of real 2D input.
Definition fftw.h:233
unsigned int C
FFT 2D dims.
Definition fftw.h:33
arma::cx_vec fft_cx(arma::cx_vec &x)
FFT of complex input.
Definition fftw.h:117
void ifft(arma::cx_vec &Pxx, arma::vec &x)
Inverse FFT.
Definition fftw.h:200
void export_wisdom_ifft(const std::string fname)
Export real IFFT wisdom to file.
Definition fftw.h:395
void export_wisdom_fft(const std::string fname)
Export real FFT wisdom to file.
Definition fftw.h:353
arma::cx_vec ifft_cx(arma::cx_vec &Pxx)
Inverse FFT.
Definition fftw.h:150
void import_wisdom_file(const std::string fname)
Import wisdom from file.
Definition fftw.h:342
fftw_plan pl_fft
Real FFTW plan.
Definition fftw.h:28
unsigned int N
FFT length.
Definition fftw.h:32
int export_alg
Alg used for exporting wisdom.
Definition fftw.h:37
void fft(arma::vec &x, arma::cx_vec &Pxx)
FFT of real input.
Definition fftw.h:162
void import_wisdom_string(const std::string wisd)
Import wisdom from string.
Definition fftw.h:331
void ifft2(arma::cx_mat &Pxx, arma::mat &x)
Inverse 2D FFT.
Definition fftw.h:287
void fft_cx(arma::cx_vec &x, arma::cx_vec &Pxx)
FFT of complex input.
Definition fftw.h:97
#define err_handler(msg)
Definition base.h:212
Definition base.h:8