mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
Loading...
Searching...
No Matches
fourierModes.hpp
Go to the documentation of this file.
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
38namespace mx
39{
40
41namespace 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 */
77template <class typeN>
78int 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 */
127template <class typeN>
128int 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 */
168template <class typeN>
169int 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 */
199template <class typeN>
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 */
263template <class typeN>
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 */
281template <class typeN>
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.
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
299 {
300 m = 0;
301 n = 0;
302 p = 0;
303 }
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 */
315{
316 double fr1 = spf1.m * spf1.m + spf1.n * spf1.n;
317 double fr2 = spf2.m * spf2.m + spf2.n * spf2.n;
318
319 if( fr1 == fr2 )
320 {
321 if( spf1.n == spf2.n )
322 {
323 if( spf1.m == spf2.m )
324 return ( spf1.p < spf2.p );
325 else
326 return ( spf1.m < spf2.m );
327 }
328 return ( spf1.n < spf2.n );
329 }
330
331 // Otherwise sort by lowest absolute value
332 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 */
341int makeFourierModeFreqs_PandV( std::vector<fourierModeDef> &spf, int N )
342{
343 int Nmodes = N * N;
344
345 spf.resize( Nmodes );
346
347 int _k, _l;
348 int modeCount = 0;
349 for( int ll = 0; ll <= N; ++ll )
350 {
351 for( int l = ll, k = 0; l >= 0; --l, ++k )
352 {
353 if( modeCount >= Nmodes )
354 {
355 internal::mxlib_error_report( error_t::sizeerr, "mode count exceeded expected number of modes" );
356 return -1;
357 }
358
359 if( k == 0 && l > .5 * N )
360 continue;
361
362 if( k > .5 * N && ( l == 0 || l >= N - k ) )
363 continue;
364
365 if( k > 0.5 * N )
366 _k = k - N;
367 else
368 _k = k;
369
370 if( l > 0.5 * N )
371 _l = l - N;
372 else
373 _l = l;
374
375 // There is always a cosine mode
376 spf[modeCount].m = _k;
377 spf[modeCount].n = _l;
378 spf[modeCount].p = 1;
379
380 ++modeCount;
381
382 // Make sure it isn't one of the corners, then populate the sine mode
383 if( !( ( k == 0 && l == 0 ) || ( k == 0.5 * N && l == 0 ) || ( k == 0 && l == 0.5 * N ) ||
384 ( k == 0.5 * N && l == 0.5 * N ) ) )
385 {
386 spf[modeCount].m = _k;
387 spf[modeCount].n = _l;
388 spf[modeCount].p = -1;
389 ++modeCount;
390 }
391 }
392 }
393
394 std::sort( spf.begin(), spf.end(), comp_fourierModeDef_PandV );
395
396 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 */
409bool comp_fourierModeDef( const fourierModeDef &spf1, const fourierModeDef &spf2 )
410{
411 double k1 = spf1.m * spf1.m + spf1.n * spf1.n;
412 double k2 = spf2.m * spf2.m + spf2.n * spf2.n;
413
414 if( k1 == k2 )
415 {
416 // Now compare by angle
417 double a1 = atan2( spf1.n, spf1.m );
418 if( a1 < 0 )
419 a1 += math::two_pi<double>();
420
421 double a2 = atan2( spf2.n, spf2.m );
422 if( a2 < 0 )
423 a2 += math::two_pi<double>();
424
425 if( a1 == a2 )
426 return ( spf1.p < spf2.p );
427
428 return ( a1 < a2 );
429 }
430
431 // Otherwise sort by lowest absolute value
432 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 */
441int makeFourierModeFreqs_Circ( std::vector<fourierModeDef> &spf, int N )
442{
443 int krad;
444 int Nmodes;
445
446 krad = floor( 0.5 * N );
447
448 Nmodes = 0.25 * math::pi<double>() * N * N * 1.1; // The 1.1 is a buffer
449
450 spf.resize( Nmodes );
451
452 int modeCount = 0;
453
454 for( int m = -krad; m <= krad; ++m )
455 {
456 int nmax = sqrt( krad * krad - m * m );
457
458 for( int n = 0; n <= nmax; ++n )
459 {
460 if( n == 0 && m <= 0 )
461 continue;
462
463 for( int p = -1; p <= 1; p += 2 )
464 {
465 if( modeCount >= Nmodes )
466 {
467 internal::mxlib_error_report( error_t::sizeerr, "mode count exceeded expected number of modes" );
468 return -1;
469 }
470
471 spf[modeCount].m = m;
472 spf[modeCount].n = n;
473 spf[modeCount].p = p;
474 ++modeCount;
475 }
476 }
477 }
478
479 // Erase any extra modes (there will bedue to the buffer).
480 spf.erase( spf.begin() + modeCount, spf.end() );
481
482 // And now sort it
483 std::sort( spf.begin(), spf.end(), comp_fourierModeDef );
484
485 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 */
498int fourierModeNumber( int m, int n, int p )
499{
500
501 if( p != -1 && p != 1 )
502 {
504 return -1;
505 }
506
507 if( m == 0 && n == 0 )
508 {
510 return -1;
511 }
512
513 int m0 = std::max( abs( m ), abs( n ) );
514
515 int i0 = 2 * ( m0 * m0 - m0 );
516
517 // int di0= 4*m0;
518
519 int di;
520
521 if( m == m0 )
522 {
523 di = n;
524 }
525 else if( m == -m0 )
526 {
527 di = 4 * m0 - n;
528 }
529 else
530 {
531 di = 2 * m0 - m;
532 }
533
534 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 */
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 if( i < 0 )
549 {
551 m = 0;
552 n = 0;
553 p = 0;
554 return -1; /// \retval -1 if i < 0
555 }
556
557 int ii = ( i ) / 2;
558
559 int m0 = 1;
560
561 while( 2 * ( m0 * m0 - m0 ) <= ii )
562 ++m0;
563 --m0;
564
565 int di = ii - 2 * ( m0 * m0 - m0 );
566
567 if( di <= m0 )
568 {
569 m = m0;
570 n = di;
571 }
572 else if( di <= 3 * m0 )
573 {
574 m = 2 * m0 - di;
575 n = m0;
576 }
577 else
578 {
579 m = -m0;
580 n = 4 * m0 - di;
581 }
582
583 p = -1 + 2 * ( i % 2 );
584
585 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 */
593int makeFourierModeFreqs_Rect( std::vector<fourierModeDef> &spf, int N )
594{
595 int Ndx = floor( 0.5 * ( N ) );
596
597 int Nmodes = 2 * ( ( 2 * Ndx + 1 ) * ( Ndx + 1 ) - ( Ndx + 1 ) );
598
599 spf.resize( Nmodes );
600
601 int m, n, p;
602
603 for( int i = 0; i < Nmodes; ++i )
604 {
605 fourierModeCoordinates( m, n, p, i );
606
607 spf[i].m = m;
608 spf[i].n = n;
609 spf[i].p = p;
610 }
611
612 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::eigenCube.
620 */
621template <typename cubeT>
622int 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) \cite
655 * 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::eigenCube.
663 */
664template <typename cubeT>
665int 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::eigenCube.
687 */
688template <typename cubeT>
689int 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::eigenCube.
711 */
712template <typename cubeT>
713int 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
@ sizeerr
A size was invalid or calculated incorrectly.
@ invalidarg
An argument was invalid.
error_t mxlib_error_report(const error_t &code, const std::string &expl, const std::source_location &loc=std::source_location::current())
Print a report to stderr given an mxlib error_t code and explanation and return the code.
Definition error.hpp:331
int makeFourierModeS(typeN im, typename typeN::Scalar m, typename typeN::Scalar n)
Populate a single sine mode.
int makeFourierBasis_Rect(cubeT &cube, int dim, int N, int basisType, typename cubeT::Scalar ang=0)
Generate a rectangular Fourier basis.
int fourierModeCoordinates(int &m, int &n, int &p, int i)
Calculate the (m,n,p) coordinates of a Fourier mode given its index.
int makeModifiedFourierModeP(typeN im, typename typeN::Scalar m, typename typeN::Scalar n, typename typeN::Scalar ang=0)
Populate a single modified Fourier +1 mode.
int makeFourierBasis_Circ(cubeT &cube, int dim, int N, int basisType)
Generate a circular Fourier basis.
int makeModifiedFourierModeM(typeN im, typename typeN::Scalar m, typename typeN::Scalar n, typename typeN::Scalar ang=0)
Populate a single modified Fourier -1 mode.
int makeFourierModeFreqs_Rect(std::vector< fourierModeDef > &spf, int N)
Generate a rectangular spatial frequency grid.
int makeFourierBasis_PandV(cubeT &cube, int dim, int N, int basisType)
Generate a rectangular modified Fourier basis with the Poyneer and Veran ordering.
int makeModifiedFourierMode(typeN im, typename typeN::Scalar m, typename typeN::Scalar n, int p, typename typeN::Scalar ang=0)
Populate a single modified Fourier mode.
bool comp_fourierModeDef(const fourierModeDef &spf1, const fourierModeDef &spf2)
Sorting functor for modes according to the mx::AO standard.
int fourierModeNumber(int m, int n, int p)
Calculate the index of a Fourier mode given its (m,n,p) coordinates.
int fillFourierBasis(cubeT &cube, int dim, std::vector< fourierModeDef > spf, int basisType, typename cubeT::Scalar ang=0)
Fill in a cube with a Fourier basis.
int makeFourierModeFreqs_Circ(std::vector< fourierModeDef > &spf, int N)
Generate a circular spatial frequency grid.
int makeFourierMode(typeN im, typename typeN::Scalar m, typename typeN::Scalar n, int p)
Populate a single basic Fourier mode.
#define MX_FOURIER_MODIFIED
Signifies the modified Fourier basis.
int makeFourierModeFreqs_PandV(std::vector< fourierModeDef > &spf, int N)
Generate a Poyneer and Veran spatial frequency grid.
int makeFourierModeC(typeN im, typename typeN::Scalar m, typename typeN::Scalar n)
Populate a single cosine mode.
bool comp_fourierModeDef_PandV(const fourierModeDef &spf1, const fourierModeDef &spf2)
Sorting functor for modes according to the Poyner and Veran (2005) standard.
constexpr floatT six_fifths()
Return 6/5 in the specified precision.
realT dtor(realT q)
Convert from degrees to radians.
Definition geo.hpp:138
The mxlib c++ namespace.
Definition mxlib.hpp:37
Structure to contain the parameters of a Fourier mode.
int m
Spatial frequency m index.
int n
Spatial frequency n index.
int p
+/- 1 for modified Fourier modes, -1==>sine, +1==>cosine for basic Fourier modes.