mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
Loading...
Searching...
No Matches
psdFilter.hpp
Go to the documentation of this file.
1/** \file psdFilter.hpp
2 * \brief Declares and defines a class for filtering with PSDs
3 * \ingroup signal_processing_files
4 * \author Jared R. Males (jaredmales@gmail.com)
5 *
6 */
7
8//***********************************************************************//
9// Copyright 2015, 2016, 2017, 2018, 2019, 2020 Jared R. Males (jaredmales@gmail.com)
10//
11// This file is part of mxlib.
12//
13// mxlib is free software: you can redistribute it and/or modify
14// it under the terms of the GNU General Public License as published by
15// the Free Software Foundation, either version 3 of the License, or
16// (at your option) any later version.
17//
18// mxlib is distributed in the hope that it will be useful,
19// but WITHOUT ANY WARRANTY; without even the implied warranty of
20// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21// GNU General Public License for more details.
22//
23// You should have received a copy of the GNU General Public License
24// along with mxlib. If not, see <http://www.gnu.org/licenses/>.
25//***********************************************************************//
26
27#ifndef psdFilter_hpp
28#define psdFilter_hpp
29
30#include <vector>
31#include <complex>
32#include <Eigen/Dense>
33
34#include "../mxError.hpp"
35#include "../math/ft/fftT.hpp"
36#include "../improc/eigenCube.hpp"
37
38namespace mx
39{
40namespace sigproc
41{
42
43namespace psdFilterTypes
44{
45
46/// Types for different ranks in psdFilter
47template <typename realT, size_t rank>
48struct arrayT;
49
50template <typename realT>
51struct arrayT<realT, 1>
52{
53 typedef std::vector<realT> realArrayT;
54 typedef std::vector<realT> *realArrayMapT;
55 typedef std::vector<std::complex<realT>> complexArrayT;
56
57 static void clear( realArrayT &arr )
58 {
59 arr.clear();
60 }
61
62 static void clear( complexArrayT &arr )
63 {
64 arr.clear();
65 }
66};
67
68template <typename realT>
69struct arrayT<realT, 2>
70{
71 typedef Eigen::Array<realT, Eigen::Dynamic, Eigen::Dynamic> realArrayT;
72 typedef Eigen::Map<Eigen::Array<realT, Eigen::Dynamic, Eigen::Dynamic>> realArrayMapT;
73
74 typedef Eigen::Array<std::complex<realT>, Eigen::Dynamic, Eigen::Dynamic> complexArrayT;
75
76 static void clear( realArrayT &arr )
77 {
78 arr.resize( 0, 0 );
79 }
80
81 static void clear( complexArrayT &arr )
82 {
83 arr.resize( 0, 0 );
84 }
85};
86
87template <typename realT>
88struct arrayT<realT, 3>
89{
90 typedef improc::eigenCube<realT> realArrayT;
91 typedef improc::eigenCube<realT> *realArrayMapT;
92 typedef improc::eigenCube<std::complex<realT>> complexArrayT;
93
94 static void clear( realArrayT &arr )
95 {
96 arr.resize( 0, 0, 0 );
97 }
98
99 static void clear( complexArrayT &arr )
100 {
101 arr.resize( 0, 0, 0 );
102 }
103};
104
105} // namespace psdFilterTypes
106
107// Forward declaration
108template <typename _realT, size_t rank, int cuda = 0>
109class psdFilter;
110
111/** \defgroup psd_filter PSD Filter
112 * \brief Filtering with a PSD to generate correlated noise.
113 *
114 * \ingroup psds
115 */
116
117/// A class for filtering noise with PSDs
118/** The square-root of the PSD is maintained by this class, either as a pointer to an external array or using internally
119 * allocated memory (which will be de-allocated on destruction).
120 *
121 * PSD Requirements:
122 * - the PSD must be in FFT storage order form. That means including negative frequencies reversed from the end of the
123 * array.
124 * - the PSD used for this needs to be normalized properly, \ref psds "according to the mxlib standard", to produce
125 * filtered noise with the correct statistics.
126 *
127 *
128 * Array type varies based on rank.
129 * - For rank==1, the array type is std::vector<realT>
130 * - for rank==2, the array type is Eigen::Array<realT, -1, -1>
131 * - for rank==3, the array type is mx::improc::eigenCube<realT>
132 * and likewise for the complex types.
133 *
134 * \tparam _realT real floating type
135 * \tparam _rank the rank, or dimension, of the PSD
136 *
137 * \ingroup psd_filter
138 *
139 * \todo once fftT has a plan interface with pointers for working memory, use it.
140 *
141 * \test Scenario: compiling psdFilter. \ref tests_sigproc_psdFilter_compile "[test doc]"
142 */
143template <typename _realT, size_t _rank>
144class psdFilter<_realT, _rank, 0>
145{
146 public:
147 typedef _realT realT; ///< Real floating point type
148 typedef std::complex<_realT> complexT; ///< Complex floating point type.
149
150 static const size_t rank = _rank;
151
153 realArrayT; ///< std::vector for rank==1, Eigen::Array for rank==2, eigenCube for rank==3.
155 realArrayMapT; ///< std::vector for rank==1, Eigen::Map for rank==2, eigenCube for rank==3.
157 complexArrayT; ///< std::vector for rank==1, Eigen::Array for rank==2, eigenCube for rank==3.
158
159 protected:
160 int m_rows{ 0 }; ///< The number of rows in the filter, and the required number of rows in the noise array.
161 int m_cols{ 0 }; ///< The number of columns in the filter, and the required number of columns in the noise array.
162 int m_planes{ 0 }; ///< Then number of planes in the filter.
163
164 realT m_dFreq1{ 1.0 }; ///< The frequency scaling of the x-dimension. Used to scale the output.
165 realT m_dFreq2{ 1.0 }; ///< The frequency scaling of the y-dimension. Used to scale the output.
166 realT m_dFreq3{ 1.0 }; ///< The frequency scaling of the z-dimension. Used to scale the output.
167
168 realArrayT *m_psdSqrt{ nullptr }; ///< Pointer to the real array containing the square root of the PSD.
169 bool m_owner{ false }; ///< Flag indicates whether or not m_psdSqrt was allocated by this instance, and so must be
170 ///< deallocated.
171
172 mutable complexArrayT
173 m_ftWork; ///< Working memory for the FFT. Declared mutable so it can be accessed in the const filter method.
174
175 math::ft::fftT<complexT, complexT, rank, 0> m_fft_fwd; ///< FFT object for the forward transform.
176 math::ft::fftT<complexT, complexT, rank, 0> m_fft_bwd; ///< FFT object for the backward transfsorm.
177
178 public:
179 /// C'tor.
180 /**
181 * \test Verify compilation and initialization of the 3 ranks for psdFilter. \ref tests_sigproc_psdFilter_compile
182 * "[test doc]"
183 */
185
186 /// Destructor
188
189 protected:
190 /// Set the sqaure-root of the PSD to be a pointer to an array containing the square root of the properly normalized
191 /// PSD.
192 /** This does not allocate _npsdSqrt, it merely points to the specified array, which remains your responsibility for
193 * deallocation, etc.
194 *
195 * See the discussion of PSD normalization above.
196 *
197 * This private version handles the actual setting of m_psdSqrt, which is rank independent.
198 *
199 * \returns 0 on success
200 * \returns -1 on error
201 *
202 * \test Verify compilation and initialization of the 3 ranks for psdFilter. \ref tests_sigproc_psdFilter_compile
203 * "[test doc]"
204 */
205 int psdSqrt( realArrayT *npsdSqrt /**< [in] a pointer to an array containing the square root of the PSD. */ );
206
207 /// Set the sqaure-root of the PSD.
208 /** This allocates _npsdSqrt and fills it with the values in the array.
209 *
210 * See the discussion of PSD normalization above.
211 *
212 * This private version handles the actual setting of m_psdSqrt, which is rank independent.
213 *
214 * \returns 0 on success
215 * \returns -1 on error
216 *
217 * \test Verify compilation and initialization of the 3 ranks for psdFilter. \ref tests_sigproc_psdFilter_compile
218 * "[test doc]"
219 */
220 int psdSqrt( const realArrayT &npsdSqrt /**< [in] an array containing the square root of the PSD. */ );
221
222 /// Set the size of the filter.
223 /** Handles allocation of the m_ftWork array and fftw planning.
224 *
225 * Requires m_psdSqrt to be set first. This is called by the psdSqrt() and psd() methods.
226 *
227 * This version compiles when rank==1
228 *
229 * \test Verify compilation and initialization of the 3 ranks for psdFilter. \ref tests_sigproc_psdFilter_compile
230 * "[test doc]"
231 */
232 template <size_t crank = rank>
233 int setSize( typename std::enable_if<crank == 1>::type * = 0 );
234
235 /// Set the size of the filter.
236 /** Handles allocation of the m_ftWork array and fftw planning.
237 *
238 * Requires m_psdSqrt to be set first. This is called by the psdSqrt() and psd() methods.
239 *
240 * This version compiles when rank==2
241 *
242 * \test Verify compilation and initialization of the 3 ranks for psdFilter. \ref tests_sigproc_psdFilter_compile
243 * "[test doc]"
244 */
245 template <size_t crank = rank>
246 int setSize( typename std::enable_if<crank == 2>::type * = 0 );
247
248 /// Set the size of the filter.
249 /** Handles allocation of the m_ftWork array and fftw planning.
250 *
251 * Requires m_psdSqrt to be set first. This is called by the psdSqrt() and psd() methods.
252 *
253 * This version compiles when rank==3
254 *
255 * \test Verify compilation and initialization of the 3 ranks for psdFilter. \ref tests_sigproc_psdFilter_compile
256 * "[test doc]"
257 */
258 template <size_t crank = rank>
259 int setSize( typename std::enable_if<crank == 3>::type * = 0 );
260
261 public:
262 /// Get the number of rows in the filter
263 /**
264 * \returns the current value of m_rows.
265 *
266 * \test Verify compilation and initialization of the 3 ranks for psdFilter. \ref tests_sigproc_psdFilter_compile
267 * "[test doc]"
268 */
269 int rows();
270
271 /// Get the number of columns in the filter
272 /**
273 * \returns the current value of m_cols.
274 *
275 * \test Verify compilation and initialization of the 3 ranks for psdFilter. \ref tests_sigproc_psdFilter_compile
276 * "[test doc]"
277 */
278 int cols();
279
280 /// Get the number of planes in the filter
281 /**
282 * \returns the current value of m_planes.
283 *
284 * \test Verify compilation and initialization of the 3 ranks for psdFilter. \ref tests_sigproc_psdFilter_compile
285 * "[test doc]"
286 */
287 int planes();
288
289 /// Set the sqaure-root of the PSD to be a pointer to an array containing the square root of the properly normalized
290 /// PSD.
291 /** This does not allocate _npsdSqrt, it merely points to the specified array, which remains your responsibility for
292 * deallocation, etc.
293 *
294 * See the discussion of PSD normalization above.
295 *
296 * This version compiles when rank==1
297 *
298 * \returns 0 on success
299 * \returns -1 on error
300 *
301 * \test Verify compilation and initialization of the 3 ranks for psdFilter. \ref tests_sigproc_psdFilter_compile
302 * "[test doc]"
303 */
304 template <size_t crank = rank>
305 int psdSqrt( realArrayT *npsdSqrt, ///< [in] a pointer to an array containing the square root of the PSD.
306 realT df, ///< [in] the frequency spacing
307 typename std::enable_if<crank == 1>::type * = 0 );
308
309 /// Set the square-root of the PSD to be a pointer to an array containing the square root of the properly normalized
310 /// PSD.
311 /** This does not allocate _npsdSqrt, it merely points to the specified array, which remains your responsibility for
312 * deallocation, etc.
313 *
314 * See the discussion of PSD normalization above.
315 *
316 * This version compiles when rank==2
317 *
318 * \returns 0 on success
319 * \returns -1 on error
320 *
321 * \test Verify compilation and initialization of the 3 ranks for psdFilter. \ref tests_sigproc_psdFilter_compile
322 * "[test doc]"
323 */
324 template <size_t crank = rank>
325 int psdSqrt( realArrayT *npsdSqrt, ///< [in] a pointer to an array containing the square root of the PSD.
326 realT dk1, ///< [in] the frequency spacing along dimension 1
327 realT dk2, ///< [in] the frequency spacing along dimension 2
328 typename std::enable_if<crank == 2>::type * = 0 );
329
330 /// Set the sqaure-root of the PSD to be a pointer to an array containing the square root of the properly normalized
331 /// PSD.
332 /** This does not allocate _npsdSqrt, it merely points to the specified array, which remains your responsibility for
333 * deallocation, etc.
334 *
335 * See the discussion of PSD normalization above.
336 *
337 * This version compiles when rank==3
338 *
339 * \returns 0 on success
340 * \returns -1 on error
341 *
342 * \test Verify compilation and initialization of the 3 ranks for psdFilter. \ref tests_sigproc_psdFilter_compile
343 * "[test doc]"
344 */
345 template <size_t crank = rank>
346 int psdSqrt( realArrayT *npsdSqrt, ///< [in] a pointer to an array containing the square root of the PSD.
347 realT dk1, ///< [in] the frequency spacing along dimension 1
348 realT dk2, ///< [in] the frequency spacing along dimension 2
349 realT df, ///< [in] the frequency spacing along dimension 3
350 typename std::enable_if<crank == 3>::type * = 0 );
351
352 /// Set the sqaure-root of the PSD.
353 /** This allocates _npsdSqrt and fills it with th evalues in the array.
354 *
355 * See the discussion of PSD normalization above.
356 *
357 * This version compiles when rank==1
358 *
359 * \returns 0 on success
360 * \returns -1 on error
361 *
362 * \test Verify compilation and initialization of the 3 ranks for psdFilter. \ref tests_sigproc_psdFilter_compile
363 * "[test doc]"
364 */
365 template <size_t crank = rank>
366 int psdSqrt( const realArrayT &npsdSqrt, ///< [in] an array containing the square root of the PSD.
367 realT df, ///< [in] the frequency spacing
368 typename std::enable_if<crank == 1>::type * = 0 );
369
370 /// Set the sqaure-root of the PSD.
371 /** This allocates _npsdSqrt and fills it with th evalues in the array.
372 *
373 * See the discussion of PSD normalization above.
374 *
375 * This version compiles when rank==2
376 *
377 * \returns 0 on success
378 * \returns -1 on error
379 *
380 * \test Verify compilation and initialization of the 3 ranks for psdFilter. \ref tests_sigproc_psdFilter_compile
381 * "[test doc]"
382 */
383 template <size_t crank = rank>
384 int psdSqrt( const realArrayT &npsdSqrt, ///< [in] an array containing the square root of the PSD.
385 realT dk1, ///< [in] the frequency spacing along dimension 1
386 realT dk2, ///< [in] the frequency spacing along dimension 2
387 typename std::enable_if<crank == 2>::type * = 0 );
388
389 /// Set the sqaure-root of the PSD.
390 /** This allocates _npsdSqrt and fills it with th evalues in the array.
391 *
392 * See the discussion of PSD normalization above.
393 *
394 * This version compiles when rank==3
395 *
396 * \returns 0 on success
397 * \returns -1 on error
398 *
399 * \test Verify compilation and initialization of the 3 ranks for psdFilter. \ref tests_sigproc_psdFilter_compile
400 * "[test doc]"
401 */
402 template <size_t crank = rank>
403 int psdSqrt( const realArrayT &npsdSqrt, ///< [in] an array containing the square root of the PSD.
404 realT dk1, ///< [in] the frequency spacing along dimension 1
405 realT dk2, ///< [in] the frequency spacing along dimension 2
406 realT df, ///< [in] the frequency spacing along dimension 3
407 typename std::enable_if<crank == 3>::type * = 0 );
408
409 /// Set the sqaure-root of the PSD from the PSD.
410 /** This allocates _npsdSqrt and fills it with the square root of the values in the array.
411 *
412 * See the discussion of PSD normalization above.
413 *
414 * This version compiles when rank==1
415 *
416 * \returns 0 on success
417 * \returns -1 on error
418 *
419 * \test Verify compilation and initialization of the 3 ranks for psdFilter. \ref tests_sigproc_psdFilter_compile
420 * "[test doc]"
421 */
422 template <size_t crank = rank>
423 int psd( const realArrayT &npsd, ///< [in] an array containing the PSD
424 const realT df, ///< [in] the frequency spacing
425 typename std::enable_if<crank == 1>::type * = 0 );
426
427 /// Set the sqaure-root of the PSD from the PSD.
428 /** This allocates _npsdSqrt and fills it with the square root of the values in the array.
429 *
430 * See the discussion of PSD normalization above.
431 *
432 * This version compiles when rank==2
433 *
434 * \returns 0 on success
435 * \returns -1 on error
436 *
437 * \test Verify compilation and initialization of the 3 ranks for psdFilter. \ref tests_sigproc_psdFilter_compile
438 * "[test doc]"
439 */
440 template <size_t crank = rank>
441 int psd( const realArrayT &npsd, ///< [in] an array containing the PSD
442 const realT dk1, ///< [in] the frequency spacing along dimension 1
443 const realT dk2, ///< [in] the frequency spacing along dimension 2
444 typename std::enable_if<crank == 2>::type * = 0 );
445
446 /// Set the sqaure-root of the PSD from the PSD.
447 /** This allocates _npsdSqrt and fills it with the square root of the values in the array.
448 *
449 * See the discussion of PSD normalization above.
450 *
451 * This version compiles when rank==3
452 *
453 * \returns 0 on success
454 * \returns -1 on error
455 *
456 * \test Verify compilation and initialization of the 3 ranks for psdFilter. \ref tests_sigproc_psdFilter_compile
457 * "[test doc]"
458 */
459 template <size_t crank = rank>
460 int psd( const realArrayT &npsd, ///< [in] an array containing the PSD
461 const realT dk1, ///< [in] the frequency spacing along dimension 1
462 const realT dk2, ///< [in] the frequency spacing along dimension 2
463 const realT df, ///< [in] the frequency spacing along dimension 3
464 typename std::enable_if<crank == 3>::type * = 0 );
465
466 /// De-allocate all working memory and reset to initial state.
467 /**
468 *
469 * \test Verify compilation and initialization of the 3 ranks for psdFilter. \ref tests_sigproc_psdFilter_compile
470 * "[test doc]"
471 */
472 void clear();
473
474 /// Apply the filter.
475 /**
476 * This version compiles when rank==1
477 *
478 * \returns 0 on success
479 * \returns -1 on error
480 *
481 * \test Verify filtering and noise normalization. \ref tests_sigproc_psdFilter_filter "[test doc]"
482 */
483 template <size_t crank = rank>
484 int filter( realArrayT &noise, ///< [in.out] the noise field of size rows() X cols(), which is filtered in-place.
485 realArrayT *noiseIm = nullptr, ///< [out] [optional] an array to fill with the imaginary output of the
486 ///< filter, allowing 2-for-1 calculation.
487 typename std::enable_if<crank == 1>::type * = 0 ) const;
488
489 /// Apply the filter.
490 /**
491 * This version compiles when rank==2
492 *
493 * \returns 0 on success
494 * \returns -1 on error
495 *
496 * \test Verify filtering and noise normalization. \ref tests_sigproc_psdFilter_filter "[test doc]"
497 */
498 template <size_t crank = rank>
499 int filter( realArrayT &noise, ///< [in.out] the noise field of size rows() X cols(), which is filtered in-place.
500 realArrayT *noiseIm = nullptr, ///< [out] [optional] an array to fill with the imaginary output of the
501 ///< filter, allowing 2-for-1 calculation.
502 typename std::enable_if<crank == 2>::type * = 0 ) const;
503
504 /// Apply the filter.
505 /**
506 * This version compiles when rank==2
507 *
508 * \returns 0 on success
509 * \returns -1 on error
510 *
511 */
512 template <size_t crank = rank>
513 int filter( realArrayMapT noise, ///< [in.out] the noise field of size rows() X cols(), which is filtered in-place.
514 realArrayT *noiseIm = nullptr, ///< [out] [optional] an array to fill with the imaginary output of the
515 ///< filter, allowing 2-for-1 calculation.
516 typename std::enable_if<crank == 2>::type * = 0 ) const;
517
518 /// Apply the filter.
519 /**
520 * This version compiles when rank==3
521 *
522 * \returns 0 on success
523 * \returns -1 on error
524 *
525 * \test Verify filtering and noise normalization. \ref tests_sigproc_psdFilter_filter "[test doc]"
526 */
527 template <size_t crank = rank>
528 int filter( realArrayT &noise, ///< [in.out] the noise field of size rows() X cols(), which is filtered in-place.
529 realArrayT *noiseIm = nullptr, ///< [out] [optional] an array to fill with the imaginary output of the
530 ///< filter, allowing 2-for-1 calculation.
531 typename std::enable_if<crank == 3>::type * = 0 ) const;
532
533 /// Apply the filter.
534 /**
535 * \returns 0 on success
536 * \returns -1 on error
537 *
538 * \test Verify filtering and noise normalization. \ref tests_sigproc_psdFilter_filter "[test doc]"
539 */
541 realArrayT &noise /**< [in.out] the noise field of size rows() X cols(), which is filtered in-place. */ ) const;
542
543 /// Apply the filter.
544 /**
545 * \overload
546 *
547 * \returns 0 on success
548 * \returns -1 on error
549 *
550 * \test Verify filtering and noise normalization. \ref tests_sigproc_psdFilter_filter "[test doc]"
551 */
553 realArrayMapT noise /**< [in.out] the noise field of size rows() X cols(), which is filtered in-place. */ )
554 const;
555
556 /// Apply the filter.
557 /**
558 * \returns 0 on success
559 * \returns -1 on error
560 *
561 * \test Verify filtering and noise normalization. \ref tests_sigproc_psdFilter_filter "[test doc]"
562 */
563 int
564 operator()( realArrayT &noise, ///< [in.out] the noise field of size rows() X cols(), which is filtered in-place.
565 realArrayT &noiseIm ///< [out] [optional] an array to fill with the imaginary output of the filter,
566 ///< allowing 2-for-1 calculation.
567 ) const;
568};
569
570template <typename realT, size_t rank>
571psdFilter<realT, rank>::psdFilter()
572{
573}
574
575template <typename realT, size_t rank>
576psdFilter<realT, rank>::~psdFilter()
577{
578 if( m_psdSqrt && m_owner )
579 {
580 delete m_psdSqrt;
581 }
582}
583
584template <typename realT, size_t rank>
585int psdFilter<realT, rank>::psdSqrt( realArrayT *npsdSqrt )
586{
587 if( m_psdSqrt && m_owner )
588 {
589 delete m_psdSqrt;
590 }
591
592 m_psdSqrt = npsdSqrt;
593 m_owner = false;
594
595 setSize();
596
597 return 0;
598}
599
600template <typename realT, size_t rank>
601int psdFilter<realT, rank>::psdSqrt( const realArrayT &npsdSqrt )
602{
603 if( m_psdSqrt && m_owner )
604 {
605 delete m_psdSqrt;
606 }
607
608 m_psdSqrt = new realArrayT;
609
610 ( *m_psdSqrt ) = npsdSqrt;
611 m_owner = true;
612
613 setSize();
614
615 return 0;
616}
617
618template <typename realT, size_t rank>
619template <size_t crank>
620int psdFilter<realT, rank>::setSize( typename std::enable_if<crank == 1>::type * )
621{
622 if( m_psdSqrt == 0 )
623 {
624 mxError( "psdFilter", MXE_PARAMNOTSET, "m_psdSqrt has not been set yet, is still NULL." );
625 return -1;
626 }
627
628 if( m_rows == m_psdSqrt->size() )
629 {
630 return 0;
631 }
632
633 m_rows = m_psdSqrt->size();
634 m_cols = 1;
635 m_planes = 1;
636
637 m_ftWork.resize( m_rows );
638
639 m_fft_fwd.plan( m_rows, math::ft::dir::forward, true );
640
641 m_fft_bwd.plan( m_rows, math::ft::dir::backward, true );
642
643 return 0;
644}
645
646template <typename realT, size_t rank>
647template <size_t crank>
648int psdFilter<realT, rank>::setSize( typename std::enable_if<crank == 2>::type * )
649{
650 if( m_psdSqrt == 0 )
651 {
652 mxError( "psdFilter", MXE_PARAMNOTSET, "m_psdSqrt has not been set yet, is still NULL." );
653 return -1;
654 }
655
656 if( m_rows == m_psdSqrt->rows() && m_cols == m_psdSqrt->cols() )
657 {
658 return 0;
659 }
660
661 m_rows = m_psdSqrt->rows();
662 m_cols = m_psdSqrt->cols();
663 m_planes = 1;
664
665 m_ftWork.resize( m_rows, m_cols );
666
667 m_fft_fwd.plan( m_rows, m_cols, math::ft::dir::forward, true );
668
669 m_fft_bwd.plan( m_rows, m_cols, math::ft::dir::backward, true );
670
671 return 0;
672}
673
674template <typename realT, size_t rank>
675template <size_t crank>
676int psdFilter<realT, rank>::setSize( typename std::enable_if<crank == 3>::type * )
677{
678 if( m_psdSqrt == 0 )
679 {
680 mxError( "psdFilter", MXE_PARAMNOTSET, "m_psdSqrt has not been set yet, is still NULL." );
681 return -1;
682 }
683
684 if( m_rows == m_psdSqrt->rows() && m_cols == m_psdSqrt->cols() && m_planes == m_psdSqrt->planes() )
685 {
686 return 0;
687 }
688
689 m_rows = m_psdSqrt->rows();
690 m_cols = m_psdSqrt->cols();
691 m_planes = m_psdSqrt->planes();
692
693 m_ftWork.resize( m_rows, m_cols, m_planes );
694
695 m_fft_fwd.plan( m_planes, m_rows, m_cols, math::ft::dir::forward, true );
696
697 m_fft_bwd.plan( m_planes, m_rows, m_cols, math::ft::dir::backward, true );
698
699 return 0;
700}
701
702template <typename realT, size_t rank>
703int psdFilter<realT, rank>::rows()
704{
705 return m_rows;
706}
707
708template <typename realT, size_t rank>
709int psdFilter<realT, rank>::cols()
710{
711 return m_cols;
712}
713
714template <typename realT, size_t rank>
715int psdFilter<realT, rank>::planes()
716{
717 return m_planes;
718}
719
720template <typename realT, size_t rank>
721template <size_t crank>
722int psdFilter<realT, rank>::psdSqrt( realArrayT *npsdSqrt, realT df, typename std::enable_if<crank == 1>::type * )
723{
724 m_dFreq1 = df;
725 return psdSqrt( npsdSqrt );
726}
727
728template <typename realT, size_t rank>
729template <size_t crank>
730int psdFilter<realT, rank>::psdSqrt( realArrayT *npsdSqrt,
731 realT dk1,
732 realT dk2,
733 typename std::enable_if<crank == 2>::type * )
734{
735 m_dFreq1 = dk1;
736 m_dFreq2 = dk2;
737 return psdSqrt( npsdSqrt );
738}
739
740template <typename realT, size_t rank>
741template <size_t crank>
742int psdFilter<realT, rank>::psdSqrt(
743 realArrayT *npsdSqrt, realT dk1, realT dk2, realT df, typename std::enable_if<crank == 3>::type * )
744{
745 m_dFreq1 = dk1;
746 m_dFreq2 = dk2;
747 m_dFreq3 = df;
748 return psdSqrt( npsdSqrt );
749}
750
751template <typename realT, size_t rank>
752template <size_t crank>
753int psdFilter<realT, rank>::psdSqrt( const realArrayT &npsdSqrt, realT df, typename std::enable_if<crank == 1>::type * )
754{
755 m_dFreq1 = df;
756 return psdSqrt( npsdSqrt );
757}
758
759template <typename realT, size_t rank>
760template <size_t crank>
761int psdFilter<realT, rank>::psdSqrt( const realArrayT &npsdSqrt,
762 realT dk1,
763 realT dk2,
764 typename std::enable_if<crank == 2>::type * )
765{
766 m_dFreq1 = dk1;
767 m_dFreq2 = dk2;
768 return psdSqrt( npsdSqrt );
769}
770
771template <typename realT, size_t rank>
772template <size_t crank>
773int psdFilter<realT, rank>::psdSqrt(
774 const realArrayT &npsdSqrt, realT dk1, realT dk2, realT df, typename std::enable_if<crank == 3>::type * )
775{
776 m_dFreq1 = dk1;
777 m_dFreq2 = dk2;
778 m_dFreq3 = df;
779 return psdSqrt( npsdSqrt );
780}
781
782template <typename realT, size_t rank>
783template <size_t crank>
784int psdFilter<realT, rank>::psd( const realArrayT &npsd, const realT df1, typename std::enable_if<crank == 1>::type * )
785{
786 if( m_psdSqrt && m_owner )
787 {
788 delete m_psdSqrt;
789 }
790
791 m_psdSqrt = new realArrayT;
792
793 // Vector
794 m_psdSqrt->resize( npsd.size() );
795 for( size_t n = 0; n < npsd.size(); ++n )
796 ( *m_psdSqrt )[n] = sqrt( npsd[n] );
797
798 m_owner = true;
799
800 m_dFreq1 = df1;
801
802 setSize();
803
804 return 0;
805}
806
807template <typename realT, size_t rank>
808template <size_t crank>
809int psdFilter<realT, rank>::psd( const realArrayT &npsd,
810 const realT dk1,
811 const realT dk2,
812 typename std::enable_if<crank == 2>::type * )
813{
814 if( m_psdSqrt && m_owner )
815 {
816 delete m_psdSqrt;
817 }
818
819 m_psdSqrt = new realArrayT;
820
821 ( *m_psdSqrt ) = npsd.sqrt();
822 m_owner = true;
823
824 m_dFreq1 = dk1;
825 m_dFreq2 = dk2;
826
827 setSize();
828
829 return 0;
830}
831
832template <typename realT, size_t rank>
833template <size_t crank>
834int psdFilter<realT, rank>::psd( const realArrayT &npsd,
835 const realT dk1,
836 const realT dk2,
837 const realT df,
838 typename std::enable_if<crank == 3>::type * )
839{
840 if( m_psdSqrt && m_owner )
841 {
842 delete m_psdSqrt;
843 }
844
845 m_psdSqrt = new realArrayT;
846
847 // Cube
848 m_psdSqrt->resize( npsd.rows(), npsd.cols(), npsd.planes() );
849 for( int pp = 0; pp < npsd.planes(); ++pp )
850 {
851 for( int cc = 0; cc < npsd.cols(); ++cc )
852 {
853 for( int rr = 0; rr < npsd.rows(); ++rr )
854 {
855 m_psdSqrt->image( pp )( rr, cc ) = sqrt( npsd.image( pp )( rr, cc ) );
856 }
857 }
858 }
859
860 m_owner = true;
861
862 m_dFreq1 = dk1;
863 m_dFreq2 = dk2;
864 m_dFreq3 = df;
865
866 setSize();
867
868 return 0;
869}
870
871template <typename realT, size_t rank>
872void psdFilter<realT, rank>::clear()
873{
874 // m_ftWork.resize(0,0);
875 psdFilterTypes::arrayT<realT, rank>::clear( m_ftWork );
876
877 m_rows = 0;
878 m_cols = 0;
879 m_planes = 0;
880
881 if( m_psdSqrt && m_owner )
882 {
883 delete m_psdSqrt;
884 m_psdSqrt = 0;
885 }
886}
887
888template <typename realT, size_t rank>
889template <size_t crank>
890int psdFilter<realT, rank>::filter( realArrayT &noise,
891 realArrayT *noiseIm,
892 typename std::enable_if<crank == 1>::type * ) const
893{
894 for( int nn = 0; nn < noise.size(); ++nn )
895 m_ftWork[nn] = complexT( noise[nn], 0 );
896
897 // Transform complex noise to Fourier domain.
898 m_fft_fwd( m_ftWork.data(), m_ftWork.data() );
899
900 // Apply the filter.
901 for( int nn = 0; nn < m_ftWork.size(); ++nn )
902 m_ftWork[nn] *= ( *m_psdSqrt )[nn];
903
904 m_fft_bwd( m_ftWork.data(), m_ftWork.data() );
905
906 // Now take the real part, and normalize.
907 realT norm = sqrt( noise.size() / m_dFreq1 );
908 for( int nn = 0; nn < m_ftWork.size(); ++nn )
909 noise[nn] = m_ftWork[nn].real() / norm;
910
911 if( noiseIm != nullptr )
912 {
913 for( int nn = 0; nn < m_ftWork.size(); ++nn )
914 ( *noiseIm )[nn] = m_ftWork[nn].imag() / norm;
915 }
916
917 return 0;
918}
919
920template <typename realT, size_t rank>
921template <size_t crank>
922int psdFilter<realT, rank>::filter( realArrayT &noise,
923 realArrayT *noiseIm,
924 typename std::enable_if<crank == 2>::type * ) const
925{
926 // Make noise a complex number
927 for( int ii = 0; ii < noise.rows(); ++ii )
928 {
929 for( int jj = 0; jj < noise.cols(); ++jj )
930 {
931 m_ftWork( ii, jj ) = complexT( noise( ii, jj ), 0 );
932 }
933 }
934
935 // Transform complex noise to Fourier domain.
936 m_fft_fwd( m_ftWork.data(), m_ftWork.data() );
937
938 // Apply the filter.
939 m_ftWork *= *m_psdSqrt;
940
941 m_fft_bwd( m_ftWork.data(), m_ftWork.data() );
942
943 realT norm = sqrt( noise.rows() * noise.cols() / ( m_dFreq1 * m_dFreq2 ) );
944
945 // Now take the real part, and normalize.
946 noise = m_ftWork.real() / norm;
947
948 if( noiseIm != nullptr )
949 {
950 *noiseIm = m_ftWork.imag() / norm;
951 }
952
953 return 0;
954}
955
956template <typename realT, size_t rank>
957template <size_t crank>
958int psdFilter<realT, rank>::filter( realArrayMapT noise,
959 realArrayT *noiseIm,
960 typename std::enable_if<crank == 2>::type * ) const
961{
962 // Make noise a complex number
963 for( int ii = 0; ii < noise.rows(); ++ii )
964 {
965 for( int jj = 0; jj < noise.cols(); ++jj )
966 {
967 m_ftWork( ii, jj ) = complexT( noise( ii, jj ), 0 );
968 }
969 }
970
971 // Transform complex noise to Fourier domain.
972 m_fft_fwd( m_ftWork.data(), m_ftWork.data() );
973
974 // Apply the filter.
975 m_ftWork *= *m_psdSqrt;
976
977 m_fft_bwd( m_ftWork.data(), m_ftWork.data() );
978
979 realT norm = sqrt( noise.rows() * noise.cols() / ( m_dFreq1 * m_dFreq2 ) );
980
981 // Now take the real part, and normalize.
982 noise = m_ftWork.real() / norm;
983
984 if( noiseIm != nullptr )
985 {
986 *noiseIm = m_ftWork.imag() / norm;
987 }
988
989 return 0;
990}
991
992template <typename realT, size_t rank>
993template <size_t crank>
994int psdFilter<realT, rank>::filter( realArrayT &noise,
995 realArrayT *noiseIm,
996 typename std::enable_if<crank == 3>::type * ) const
997{
998 // Make noise a complex number
999 for( int pp = 0; pp < noise.planes(); ++pp )
1000 {
1001 for( int ii = 0; ii < noise.rows(); ++ii )
1002 {
1003 for( int jj = 0; jj < noise.cols(); ++jj )
1004 {
1005 m_ftWork.image( pp )( ii, jj ) = complexT( noise.image( pp )( ii, jj ), 0 );
1006 }
1007 }
1008 }
1009
1010 // Transform complex noise to Fourier domain.
1011 m_fft_fwd( m_ftWork.data(), m_ftWork.data() );
1012
1013 // Apply the filter.
1014 for( int pp = 0; pp < noise.planes(); ++pp )
1015 m_ftWork.image( pp ) *= m_psdSqrt->image( pp );
1016
1017 m_fft_bwd( m_ftWork.data(), m_ftWork.data() );
1018
1019 // Now take the real part, and normalize.
1020
1021 realT norm = sqrt( m_rows * m_cols * m_planes / ( m_dFreq1 * m_dFreq2 * m_dFreq3 ) );
1022 for( int pp = 0; pp < noise.planes(); ++pp )
1023 noise.image( pp ) = m_ftWork.image( pp ).real() / norm;
1024
1025 if( noiseIm != nullptr )
1026 {
1027 for( int pp = 0; pp < noise.planes(); ++pp )
1028 noiseIm->image( pp ) = m_ftWork.image( pp ).imag() / norm;
1029 }
1030
1031 return 0;
1032}
1033
1034template <typename realT, size_t rank>
1035int psdFilter<realT, rank>::operator()( realArrayT &noise ) const
1036{
1037 return filter( noise );
1038}
1039
1040template <typename realT, size_t rank>
1041int psdFilter<realT, rank>::operator()( realArrayMapT noise ) const
1042{
1043 return filter( noise );
1044}
1045
1046template <typename realT, size_t rank>
1047int psdFilter<realT, rank>::operator()( realArrayT &noise, realArrayT &noiseIm ) const
1048{
1049 return filter( noise, &noiseIm );
1050}
1051
1052} // namespace sigproc
1053} // namespace mx
1054
1055#endif // psdFilter_hpp
int setSize(typename std::enable_if< crank==1 >::type *=0)
Set the size of the filter.
int operator()(realArrayT &noise, realArrayT &noiseIm) const
Apply the filter.
complexArrayT m_ftWork
Working memory for the FFT. Declared mutable so it can be accessed in the const filter method.
int rows()
Get the number of rows in the filter.
int psd(const realArrayT &npsd, const realT df, typename std::enable_if< crank==1 >::type *=0)
Set the sqaure-root of the PSD from the PSD.
int filter(realArrayMapT noise, realArrayT *noiseIm=nullptr, typename std::enable_if< crank==2 >::type *=0) const
Apply the filter.
psdFilterTypes::arrayT< realT, rank >::complexArrayT complexArrayT
std::vector for rank==1, Eigen::Array for rank==2, eigenCube for rank==3.
int psdSqrt(realArrayT *npsdSqrt, realT df, typename std::enable_if< crank==1 >::type *=0)
math::ft::fftT< complexT, complexT, rank, 0 > m_fft_fwd
FFT object for the forward transform.
int filter(realArrayT &noise, realArrayT *noiseIm=nullptr, typename std::enable_if< crank==3 >::type *=0) const
Apply the filter.
psdFilterTypes::arrayT< realT, rank >::realArrayMapT realArrayMapT
std::vector for rank==1, Eigen::Map for rank==2, eigenCube for rank==3.
int filter(realArrayT &noise, realArrayT *noiseIm=nullptr, typename std::enable_if< crank==1 >::type *=0) const
Apply the filter.
int psdSqrt(realArrayT *npsdSqrt, realT dk1, realT dk2, typename std::enable_if< crank==2 >::type *=0)
int setSize(typename std::enable_if< crank==2 >::type *=0)
Set the size of the filter.
int operator()(realArrayT &noise) const
Apply the filter.
int psd(const realArrayT &npsd, const realT dk1, const realT dk2, typename std::enable_if< crank==2 >::type *=0)
Set the sqaure-root of the PSD from the PSD.
int psdSqrt(realArrayT *npsdSqrt, realT dk1, realT dk2, realT df, typename std::enable_if< crank==3 >::type *=0)
int cols()
Get the number of columns in the filter.
std::complex< _realT > complexT
Complex floating point type.
psdFilterTypes::arrayT< realT, rank >::realArrayT realArrayT
std::vector for rank==1, Eigen::Array for rank==2, eigenCube for rank==3.
int psdSqrt(const realArrayT &npsdSqrt, realT dk1, realT dk2, realT df, typename std::enable_if< crank==3 >::type *=0)
Set the sqaure-root of the PSD.
math::ft::fftT< complexT, complexT, rank, 0 > m_fft_bwd
FFT object for the backward transfsorm.
int setSize(typename std::enable_if< crank==3 >::type *=0)
Set the size of the filter.
void clear()
De-allocate all working memory and reset to initial state.
int filter(realArrayT &noise, realArrayT *noiseIm=nullptr, typename std::enable_if< crank==2 >::type *=0) const
Apply the filter.
_realT realT
Real floating point type.
int operator()(realArrayMapT noise) const
Apply the filter.
int psdSqrt(const realArrayT &npsdSqrt, realT df, typename std::enable_if< crank==1 >::type *=0)
Set the sqaure-root of the PSD.
int psd(const realArrayT &npsd, const realT dk1, const realT dk2, const realT df, typename std::enable_if< crank==3 >::type *=0)
Set the sqaure-root of the PSD from the PSD.
int psdSqrt(const realArrayT &npsdSqrt)
Set the sqaure-root of the PSD.
int psdSqrt(const realArrayT &npsdSqrt, realT dk1, realT dk2, typename std::enable_if< crank==2 >::type *=0)
Set the sqaure-root of the PSD.
int planes()
Get the number of planes in the filter.
@ backward
Specifies the backward transform.
@ forward
Specifies the forward transform.
The mxlib c++ namespace.
Definition mxError.hpp:106
Types for different ranks in psdFilter.
Definition psdFilter.hpp:48