Line data Source code
1 : /** \file fourierModes.hpp
2 : * \author Jared R. Males
3 : * \brief Functions for generating 2D Fourier modes
4 : * \ingroup signal_processing_files
5 : *
6 : */
7 :
8 : //***********************************************************************//
9 : // Copyright 2015, 2016, 2017 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 fourierModes_hpp
28 : #define fourierModes_hpp
29 :
30 : #include <vector>
31 : #include <algorithm>
32 :
33 : #include "../mxlib.hpp"
34 :
35 : #include "../math/constants.hpp"
36 : #include "../math/geo.hpp"
37 :
38 : namespace mx
39 : {
40 :
41 : namespace sigproc
42 : {
43 :
44 : /**
45 : * \ingroup fourier_basis
46 : *
47 : * \todo need to handle references and r-values so this works directly with Eigen arrays.
48 : *
49 : * @{
50 : */
51 :
52 : /** \def MX_FOURIER_BASIC
53 : * \brief Signifies the basic sine/cosine Fourier basis.
54 : */
55 : #define MX_FOURIER_BASIC 0
56 :
57 : /** \def MX_FOURIER_MODIFIED
58 : * \brief Signifies the modified Fourier basis.
59 : */
60 : #define MX_FOURIER_MODIFIED 1
61 :
62 : /// Populate a single cosine mode
63 : /** Makes a 2D image of the cosine mode:
64 : \f[
65 : M_c(\vec{q}) = \cos\left( 2\pi\frac{m}{D}u + 2\pi\frac{n}{D}v \right)
66 : \f]
67 : * where
68 : \f[
69 : \vec{q} = u \hat{u} + v \hat{v}
70 : \f]
71 : * and \f$ D \f$ is taken to be the maximum of the number of columns and rows in the image.
72 : *
73 : * \retval 0 on success
74 : *
75 : * \tparam typeN is an Eigen-like reference type.
76 : */
77 : template <class typeN>
78 : int makeFourierModeC( typeN im, ///< [out] is an Eigen-like image
79 : typename typeN::Scalar m, ///< [in] specifies the spatial frequency in the u direction
80 : typename typeN::Scalar n ///< [in] n specifies the spatial frequency in the v direction
81 : )
82 : {
83 : typedef typename typeN::Scalar realT;
84 :
85 : int dim1 = im.cols();
86 : int dim2 = im.rows();
87 :
88 : realT uc, vc, u, v, D;
89 :
90 : uc = 0.5 * ( dim1 - 1.0 );
91 : vc = 0.5 * ( dim2 - 1.0 );
92 :
93 : D = std::max( dim1, dim2 );
94 :
95 : for( int i = 0; i < dim1; ++i )
96 : {
97 : u = i - uc;
98 : for( int j = 0; j < dim2; ++j )
99 : {
100 : v = j - vc;
101 :
102 : im( i, j ) = cos( math::two_pi<realT>() / D * ( m * u + n * v ) );
103 : }
104 : }
105 :
106 : return 0;
107 : }
108 :
109 : /// Populate a single sine mode
110 : /** Makes a 2D image of the cosine mode:
111 : \f[
112 : M_s(\vec{q}) = \sin\left( 2\pi\frac{m}{D}u + 2\pi\frac{n}{D}v \right)
113 : \f]
114 : * where
115 : \f[
116 : \vec{q} = u \hat{u} + v \hat{v}
117 : \f]
118 : * and \f$ D \f$ is taken to be the maximum of the number of columns and rows in the image.
119 : * \param [out] im is an Eigen-like image
120 : * \param [in] m specifies the spatial frequency in the u direction
121 : * \param [in] n specifies the spatial frequency in the v direction
122 : *
123 : * \retval 0 on success
124 : *
125 : * \tparam typeN is an Eigen-like reference type.
126 : */
127 : template <class typeN>
128 : int makeFourierModeS( typeN im, typename typeN::Scalar m, typename typeN::Scalar n )
129 : {
130 : typedef typename typeN::Scalar realT;
131 :
132 : int dim1 = im.cols();
133 : int dim2 = im.rows();
134 :
135 : realT uc, vc, u, v, D;
136 :
137 : uc = 0.5 * ( dim1 - 1.0 );
138 : vc = 0.5 * ( dim2 - 1.0 );
139 :
140 : D = std::max( dim1, dim2 );
141 :
142 : for( int i = 0; i < dim1; ++i )
143 : {
144 : u = i - uc;
145 : for( int j = 0; j < dim2; ++j )
146 : {
147 : v = j - vc;
148 :
149 : im( i, j ) = sin( math::two_pi<realT>() / D * ( m * u + n * v ) );
150 : }
151 : }
152 :
153 : return 0;
154 : }
155 :
156 : /// Populate a single basic Fourier mode
157 : /** Makes a 2D image of the basic sine or cosine mode. Calls \ref makeFourierModeC and \ref makeFourierModeS.
158 : *
159 : * \param [out] im is an Eigen-like image
160 : * \param [in] m specifies the spatial frequency in the u direction
161 : * \param [in] n specifies the spatial frequency in the v direction
162 : * \param [in] p species sine (-1) or cosine (+1)
163 : *
164 : * \retval 0 on success
165 : *
166 : * \tparam typeN is an Eigen-like reference type.
167 : */
168 : template <class typeN>
169 : int makeFourierMode( typeN im, typename typeN::Scalar m, typename typeN::Scalar n, int p )
170 : {
171 : if( p == -1 )
172 : return makeFourierModeS( im, m, n );
173 :
174 : if( p == 1 )
175 : return makeFourierModeC( im, m, n );
176 :
177 : internal::mxlib_error_report( error_t::invalidarg, "p must be +1 (cosine) or -1 (sine)." );
178 :
179 : return -1;
180 : }
181 :
182 : /// Populate a single modified Fourier mode
183 : /** Makes a 2D image of the modified fourier mode:
184 : \f[
185 : M_p(\vec{q}) = \cos\left( 2\pi \frac{m}{D}u + 2\pi\frac{n}{D}v \right) + p \sin\left( 2\pi\frac{m}{D}u +
186 : 2\pi\frac{n}{D}v \right) \f]
187 : * where \f$ p = \pm 1 \f$, \f$ \vec{q} = u \hat{u} + v \hat{v} \f$,
188 : * and \f$ D \f$ is taken to be the maximum of the number of columns in the image.
189 : *
190 : * \param [out] im is an Eigen-like image
191 : * \param [in] m specifies the spatial frequency in the u direction
192 : * \param [in] n specifies the spatial frequency in the v direction
193 : * \param [in] p is +/- 1 specifying which modified Fourier mode
194 : *
195 : * \retval 0 on success
196 : *
197 : * \tparam typeN is an Eigen-like reference type.
198 : */
199 : template <class typeN>
200 : int makeModifiedFourierMode(
201 : typeN im, typename typeN::Scalar m, typename typeN::Scalar n, int p, typename typeN::Scalar ang = 0 )
202 : {
203 : typedef typename typeN::Scalar realT;
204 :
205 : if( p != 1 && p != -1 )
206 : {
207 : internal::mxlib_error_report( error_t::invalidarg, "p must be +1 or -1." );
208 : return -1;
209 : }
210 :
211 : int dim1 = im.cols();
212 : int dim2 = im.rows();
213 :
214 : realT xc, yc, x, y, arg, D;
215 :
216 : xc = 0.5 * ( dim1 - 1.0 );
217 : yc = 0.5 * ( dim2 - 1.0 );
218 :
219 : D = std::max( dim1, dim2 );
220 :
221 : realT c_ang, s_ang;
222 : if( ang != 0 )
223 : {
224 : c_ang = cos( math::dtor( ang ) );
225 : s_ang = sin( math::dtor( ang ) );
226 : }
227 :
228 : for( int i = 0; i < dim1; ++i )
229 : {
230 :
231 : for( int j = 0; j < dim2; ++j )
232 : {
233 : x = i - xc;
234 : y = j - yc;
235 :
236 : if( ang != 0 )
237 : {
238 : realT x0 = x * c_ang - y * s_ang;
239 : realT y0 = x * s_ang + y * c_ang;
240 :
241 : x = x0;
242 : y = y0;
243 : }
244 :
245 : arg = math::two_pi<realT>() / D * ( m * x + n * y );
246 :
247 : im( i, j ) = cos( arg ) + p * sin( arg );
248 : }
249 : }
250 :
251 : return 0;
252 : }
253 :
254 : /// Populate a single modified Fourier +1 mode
255 : /** See \ref makeModifiedFourierMode.
256 : *
257 : * \param [out] im is an Eigen-like image
258 : * \param [in] m specifies the spatial frequency in the u direction
259 : * \param [in] n specifies the spatial frequency in the v direction
260 : *
261 : * \tparam typeN is an Eigen-like reference type.
262 : */
263 : template <class typeN>
264 : int makeModifiedFourierModeP( typeN im,
265 : typename typeN::Scalar m,
266 : typename typeN::Scalar n,
267 : typename typeN::Scalar ang = 0 )
268 : {
269 : return makeModifiedFourierMode( im, m, n, 1, ang );
270 : }
271 :
272 : /// Populate a single modified Fourier -1 mode
273 : /** See \ref makeModifiedFourierMode.
274 : *
275 : * \param [out] im is an Eigen-like image
276 : * \param [in] m specifies the spatial frequency in the u direction
277 : * \param [in] n specifies the spatial frequency in the v direction
278 : *
279 : * \tparam typeN is an Eigen-like reference type.
280 : */
281 : template <class typeN>
282 : int makeModifiedFourierModeM( typeN im,
283 : typename typeN::Scalar m,
284 : typename typeN::Scalar n,
285 : typename typeN::Scalar ang = 0 )
286 : {
287 : return makeModifiedFourierMode( im, m, n, -1, ang );
288 : }
289 :
290 : /// Structure to contain the parameters of a Fourier mode.
291 : struct fourierModeDef
292 : {
293 : int m; ///< Spatial frequency m index
294 : int n; ///< Spatial frequency n index
295 : int p; ///< +/- 1 for modified Fourier modes, -1==>sine, +1==>cosine for basic Fourier modes.
296 :
297 : /// Constructor
298 16 : fourierModeDef()
299 16 : {
300 16 : m = 0;
301 16 : n = 0;
302 16 : p = 0;
303 16 : }
304 : };
305 :
306 : /// Sorting functor for modes according to the Poyner and Veran (2005) standard.
307 : /** Follows the conventions of Poyneer & Veran (2005) \cite poyneer_and_veran_2005
308 : *
309 : * \param[in] spf1 is an object of type \ref fourierModeDef to compare with spf2
310 : * \param[in] spf2 is an object of type \ref fourierModeDef to compare with spf1
311 : *
312 : * \returns the result of (spf1 < spf2) according to the above rules.
313 : */
314 0 : bool comp_fourierModeDef_PandV( const fourierModeDef &spf1, const fourierModeDef &spf2 )
315 : {
316 0 : double fr1 = spf1.m * spf1.m + spf1.n * spf1.n;
317 0 : double fr2 = spf2.m * spf2.m + spf2.n * spf2.n;
318 :
319 0 : if( fr1 == fr2 )
320 : {
321 0 : if( spf1.n == spf2.n )
322 : {
323 0 : if( spf1.m == spf2.m )
324 0 : return ( spf1.p < spf2.p );
325 : else
326 0 : return ( spf1.m < spf2.m );
327 : }
328 0 : return ( spf1.n < spf2.n );
329 : }
330 :
331 : // Otherwise sort by lowest absolute value
332 0 : return ( fr1 < fr2 );
333 : }
334 :
335 : /// Generate a Poyneer and Veran spatial frequency grid.
336 : /** Follows the convention of Poyneer and Veran (2005) \cite poyneer_and_veran_2005
337 : * \todo use push_back instead of resize
338 : * \param spf
339 : * \param N is the linear number of degrees of freedom.
340 : */
341 0 : int makeFourierModeFreqs_PandV( std::vector<fourierModeDef> &spf, int N )
342 : {
343 0 : int Nmodes = N * N;
344 :
345 0 : spf.resize( Nmodes );
346 :
347 : int _k, _l;
348 0 : int modeCount = 0;
349 0 : for( int ll = 0; ll <= N; ++ll )
350 : {
351 0 : for( int l = ll, k = 0; l >= 0; --l, ++k )
352 : {
353 0 : if( modeCount >= Nmodes )
354 : {
355 0 : internal::mxlib_error_report( error_t::sizeerr, "mode count exceeded expected number of modes" );
356 0 : return -1;
357 : }
358 :
359 0 : if( k == 0 && l > .5 * N )
360 0 : continue;
361 :
362 0 : if( k > .5 * N && ( l == 0 || l >= N - k ) )
363 0 : continue;
364 :
365 0 : if( k > 0.5 * N )
366 0 : _k = k - N;
367 : else
368 0 : _k = k;
369 :
370 0 : if( l > 0.5 * N )
371 0 : _l = l - N;
372 : else
373 0 : _l = l;
374 :
375 : // There is always a cosine mode
376 0 : spf[modeCount].m = _k;
377 0 : spf[modeCount].n = _l;
378 0 : spf[modeCount].p = 1;
379 :
380 0 : ++modeCount;
381 :
382 : // Make sure it isn't one of the corners, then populate the sine mode
383 0 : if( !( ( k == 0 && l == 0 ) || ( k == 0.5 * N && l == 0 ) || ( k == 0 && l == 0.5 * N ) ||
384 0 : ( k == 0.5 * N && l == 0.5 * N ) ) )
385 : {
386 0 : spf[modeCount].m = _k;
387 0 : spf[modeCount].n = _l;
388 0 : spf[modeCount].p = -1;
389 0 : ++modeCount;
390 : }
391 : }
392 : }
393 :
394 0 : std::sort( spf.begin(), spf.end(), comp_fourierModeDef_PandV );
395 :
396 0 : return 0;
397 : }
398 :
399 : /// Sorting functor for modes according to the mx::AO standard.
400 : /** Given a spatial frequency vector \f$ \vec{k} = k_u \hat{u} + k_v \hat{v} \f$, sorts first by
401 : * \f$ | \vec{k} | \f$, then by the angle from the u axis. Results in mode numbers increasing radially
402 : * and counter-clockwise from the \f$ u \f$ axis.
403 : *
404 : * \param[in] spf1 is an object of type \ref fourierModeDef to compare with spf2
405 : * \param[in] spf2 is an object of type \ref fourierModeDef to compare with spf1
406 : *
407 : * \returns the result of (spf1 < spf2) according to the above rules.
408 : */
409 0 : bool comp_fourierModeDef( const fourierModeDef &spf1, const fourierModeDef &spf2 )
410 : {
411 0 : double k1 = spf1.m * spf1.m + spf1.n * spf1.n;
412 0 : double k2 = spf2.m * spf2.m + spf2.n * spf2.n;
413 :
414 0 : if( k1 == k2 )
415 : {
416 : // Now compare by angle
417 0 : double a1 = atan2( spf1.n, spf1.m );
418 0 : if( a1 < 0 )
419 0 : a1 += math::two_pi<double>();
420 :
421 0 : double a2 = atan2( spf2.n, spf2.m );
422 0 : if( a2 < 0 )
423 0 : a2 += math::two_pi<double>();
424 :
425 0 : if( a1 == a2 )
426 0 : return ( spf1.p < spf2.p );
427 :
428 0 : return ( a1 < a2 );
429 : }
430 :
431 : // Otherwise sort by lowest absolute value
432 0 : return ( k1 < k2 );
433 : }
434 :
435 : /// Generate a circular spatial frequency grid.
436 : /** \todo use push_back instead of resize
437 : *
438 : * \param spf
439 : * \param N is the linear number of degrees of freedom. The number of modes is ((N+1)(N+1) - 1).
440 : */
441 0 : int makeFourierModeFreqs_Circ( std::vector<fourierModeDef> &spf, int N )
442 : {
443 : int krad;
444 : int Nmodes;
445 :
446 0 : krad = floor( 0.5 * N );
447 :
448 0 : Nmodes = 0.25 * math::pi<double>() * N * N * 1.1; // The 1.1 is a buffer
449 :
450 0 : spf.resize( Nmodes );
451 :
452 0 : int modeCount = 0;
453 :
454 0 : for( int m = -krad; m <= krad; ++m )
455 : {
456 0 : int nmax = sqrt( krad * krad - m * m );
457 :
458 0 : for( int n = 0; n <= nmax; ++n )
459 : {
460 0 : if( n == 0 && m <= 0 )
461 0 : continue;
462 :
463 0 : for( int p = -1; p <= 1; p += 2 )
464 : {
465 0 : if( modeCount >= Nmodes )
466 : {
467 0 : internal::mxlib_error_report( error_t::sizeerr, "mode count exceeded expected number of modes" );
468 0 : return -1;
469 : }
470 :
471 0 : spf[modeCount].m = m;
472 0 : spf[modeCount].n = n;
473 0 : spf[modeCount].p = p;
474 0 : ++modeCount;
475 : }
476 : }
477 : }
478 :
479 : // Erase any extra modes (there will bedue to the buffer).
480 0 : spf.erase( spf.begin() + modeCount, spf.end() );
481 :
482 : // And now sort it
483 0 : std::sort( spf.begin(), spf.end(), comp_fourierModeDef );
484 :
485 0 : return 0;
486 : }
487 :
488 : /// Calculate the index of a Fourier mode given its (m,n,p) coordinates.
489 : /** The index increases counter-clockwise from the m axis in squares, with p==-1 being even and p==1 being odd.
490 : *
491 : * \param [in] m is the m spatial frequency coordinate
492 : * \param [in] n is the n spatial frequency coordinage
493 : * \param [in] p is the parity, +/-1, for sine or cosine or specifiying the modified Fourier mode.
494 : *
495 : * \returns the index of the Fourier mode on success
496 : * \returns -1 on an error.
497 : */
498 0 : int fourierModeNumber( int m, int n, int p )
499 : {
500 :
501 0 : if( p != -1 && p != 1 )
502 : {
503 0 : internal::mxlib_error_report( error_t::invalidarg, "p must +/-1" );
504 0 : return -1;
505 : }
506 :
507 0 : if( m == 0 && n == 0 )
508 : {
509 0 : internal::mxlib_error_report( error_t::invalidarg, "piston is ignored" );
510 0 : return -1;
511 : }
512 :
513 0 : int m0 = std::max( abs( m ), abs( n ) );
514 :
515 0 : int i0 = 2 * ( m0 * m0 - m0 );
516 :
517 : // int di0= 4*m0;
518 :
519 : int di;
520 :
521 0 : if( m == m0 )
522 : {
523 0 : di = n;
524 : }
525 0 : else if( m == -m0 )
526 : {
527 0 : di = 4 * m0 - n;
528 : }
529 : else
530 : {
531 0 : di = 2 * m0 - m;
532 : }
533 :
534 0 : return 2 * ( i0 + di ) + ( 1 + p ) / 2;
535 : }
536 :
537 : /// Calculate the (m,n,p) coordinates of a Fourier mode given its index.
538 : /** The index increases counter-clockwise from the m axis in squares, with p==-1 being even and p==1 being odd.
539 : *
540 : * \returns 0 on success, a negative number otherwise
541 : */
542 16 : int fourierModeCoordinates(
543 : int &m, ///< [out] is the m spatial frequency coordinate
544 : int &n, ///< [out] is the n spatial frequency coordinage
545 : int &p, ///< [out] is the parity, +/-1, for sine or cosine or specifiying the modified Fourier mode.
546 : int i ) ///< [in] is the mode index.
547 : {
548 16 : if( i < 0 )
549 : {
550 0 : internal::mxlib_error_report( error_t::invalidarg, "i must be >= 0" );
551 0 : m = 0;
552 0 : n = 0;
553 0 : p = 0;
554 0 : return -1; /// \retval -1 if i < 0
555 : }
556 :
557 16 : int ii = ( i ) / 2;
558 :
559 16 : int m0 = 1;
560 :
561 32 : while( 2 * ( m0 * m0 - m0 ) <= ii )
562 16 : ++m0;
563 16 : --m0;
564 :
565 16 : int di = ii - 2 * ( m0 * m0 - m0 );
566 :
567 16 : if( di <= m0 )
568 : {
569 8 : m = m0;
570 8 : n = di;
571 : }
572 8 : else if( di <= 3 * m0 )
573 : {
574 8 : m = 2 * m0 - di;
575 8 : n = m0;
576 : }
577 : else
578 : {
579 0 : m = -m0;
580 0 : n = 4 * m0 - di;
581 : }
582 :
583 16 : p = -1 + 2 * ( i % 2 );
584 :
585 16 : return 0;
586 : }
587 :
588 : /// Generate a rectangular spatial frequency grid.
589 : /**
590 : * \param spf is a vector of fourierModeDef structures, which will be resized and populated.
591 : * \param N is the linear number of degrees of freedom. The number of modes is ((N+1)(N+1) - 1).
592 : */
593 2 : int makeFourierModeFreqs_Rect( std::vector<fourierModeDef> &spf, int N )
594 : {
595 2 : int Ndx = floor( 0.5 * ( N ) );
596 :
597 2 : int Nmodes = 2 * ( ( 2 * Ndx + 1 ) * ( Ndx + 1 ) - ( Ndx + 1 ) );
598 :
599 2 : spf.resize( Nmodes );
600 :
601 : int m, n, p;
602 :
603 18 : for( int i = 0; i < Nmodes; ++i )
604 : {
605 16 : fourierModeCoordinates( m, n, p, i );
606 :
607 16 : spf[i].m = m;
608 16 : spf[i].n = n;
609 16 : spf[i].p = p;
610 : }
611 :
612 2 : return 0;
613 : }
614 :
615 : /// Fill in a cube with a Fourier basis.
616 : /** Fills the cube with either the basic or modified Fourier basis for the modes specified.
617 : *
618 : *
619 : * \tparam cubeT is an eigen-like cube, e.g. \ref mx::improc::eigenCube.
620 : */
621 : template <typename cubeT>
622 : int fillFourierBasis( cubeT &cube, /**< [out] will be allocated to hold and
623 : will be filled with the modes*/
624 : int dim, /**< [in] is the linear size of the maps*/
625 : std::vector<fourierModeDef> spf, /**< [in] is a vector of mode definitions
626 : to use for each mode*/
627 : int basisType, /**< [in] is either MX_FOURIER_MODIFIED or MX_FOURIER_BASIC*/
628 : typename cubeT::Scalar ang = 0 /**< [in] */
629 : )
630 : {
631 : int Nmodes = spf.size();
632 :
633 : cube.resize( dim, dim, Nmodes );
634 :
635 : for( int j = 0; j < Nmodes; ++j )
636 : {
637 : if( basisType == MX_FOURIER_MODIFIED )
638 : {
639 : if( makeModifiedFourierMode( cube.image( j ), spf[j].m, spf[j].n, spf[j].p, ang ) < 0 )
640 : return -1;
641 : }
642 : else
643 : {
644 : if( makeFourierMode( cube.image( j ), spf[j].m, spf[j].n, spf[j].p ) < 0 )
645 : return -1;
646 : }
647 : }
648 :
649 : return 0;
650 : }
651 :
652 : /// Generate a rectangular modified Fourier basis with the Poyneer and Veran ordering.
653 : /** Fills the cube with modes generated by \ref makeFourierMode or \ref makeModifiedFourierMode using the mode grid
654 : * generated by \ref makeFourierModeFreqs_PandV. This follows the convention of Poyneer and Veran (2005)
655 : * \cite poyneer_and_veran_2005 for mode numbering.
656 : *
657 : * \param[out] cube will be allocated to hold and will be filled with the modes
658 : * \param[in] dim is the linear size of the maps, each is
659 : * \param[in] N is the linear number of degrees of freedom. The number of modes is ((N+1)(N+1) - 1).
660 : * \param[in] basisType is either MX_FOURIER_MODIFIED or MX_FOURIER_BASIC
661 : *
662 : * \tparam cubeT is an eigen-like cube, e.g. \ref mx::improc::eigenCube.
663 : */
664 : template <typename cubeT>
665 : int makeFourierBasis_PandV( cubeT &cube, int dim, int N, int basisType )
666 : {
667 : std::vector<fourierModeDef> spf;
668 :
669 : if( makeFourierModeFreqs_PandV( spf, N ) < 0 )
670 : {
671 : return -1;
672 : }
673 :
674 : return fillFourierBasis( cube, dim, spf, basisType );
675 : }
676 :
677 : /// Generate a circular Fourier basis.
678 : /** Fills the cube with modes generated by \ref makeFourierMode or \ref makeModifiedFourierMode using the mode grid
679 : * generated by \ref makeFourierModeFreqs_Circ.
680 : *
681 : * \param[out] cube will be allocated to hold and will be filled with the modes
682 : * \param[in] dim is the linear size of the maps, each is
683 : * \param[in] N is the linear number of degrees of freedom. The number of modes is ((N+1)(N+1) - 1).
684 : * \param[in] basisType is either MX_FOURIER_MODIFIED or MX_FOURIER_BASIC
685 : *
686 : * \tparam cubeT is an eigen-like cube, e.g. \ref mx::improc::eigenCube.
687 : */
688 : template <typename cubeT>
689 : int makeFourierBasis_Circ( cubeT &cube, int dim, int N, int basisType )
690 : {
691 : std::vector<fourierModeDef> spf;
692 :
693 : if( makeFourierModeFreqs_Circ( spf, N ) < 0 )
694 : {
695 : return -1;
696 : }
697 :
698 : return fillFourierBasis( cube, dim, spf, basisType );
699 : }
700 :
701 : /// Generate a rectangular Fourier basis.
702 : /** Fills the cube with modes generated by \ref makeFourierMode or \ref makeModifiedFourierMode using the mode grid
703 : * generated by \ref makeFourierModeFreqs_Rect.
704 : *
705 : * \param[out] cube will be allocated to hold and will be filled with the modes
706 : * \param[in] dim is the linear size of the maps, each is
707 : * \param[in] N is the linear number of degrees of freedom. The number of modes is ((N+1)(N+1) - 1).
708 : * \param[in] basisType is either MX_FOURIER_MODIFIED or MX_FOURIER_BASIC
709 : *
710 : * \tparam cubeT is an eigen-like cube, e.g. \ref mx::improc::eigenCube.
711 : */
712 : template <typename cubeT>
713 : int makeFourierBasis_Rect( cubeT &cube, int dim, int N, int basisType, typename cubeT::Scalar ang = 0 )
714 : {
715 : std::vector<fourierModeDef> spf;
716 :
717 : if( makeFourierModeFreqs_Rect( spf, N ) < 0 )
718 : {
719 : return -1;
720 : }
721 :
722 : return fillFourierBasis( cube, dim, spf, basisType, ang );
723 : }
724 :
725 : ///@}
726 :
727 : } // namespace sigproc
728 : } // namespace mx
729 :
730 : #endif // fourierModes_hpp
|