mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
Loading...
Searching...
No Matches
mftT.hpp
Go to the documentation of this file.
1/** \file mftT.hpp
2 * \brief The Matrix Fourier Transform interface
3 * \ingroup ft_files
4 * \author Jared R. Males (jaredmales@gmail.com)
5 *
6 */
7
8//***********************************************************************//
9// Copyright 2024-2025 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 mftT_hpp
28#define mftT_hpp
29
30#pragma GCC system_header
31#include <Eigen/Dense>
32
33#include "fftwTemplates.hpp"
34#include "ftTypes.hpp"
35#include "../../math/constants.hpp"
36
37/** \addtogroup mft
38 *
39 * The Matrix Fourier Transform is the <a href="https://en.wikipedia.org/wiki/DFT_matrix">
40 * matrix-multiplication implementation of the
41 * Discrete Fourier Transform</a>. It is slower than the FFT given the same size matrix, e.g.
42 * <a href="https://pages.hmc.edu/ruye/e161/lectures/fourier/node11.html">in 2D</a>
43 * \f$O(N^3)\f$ vs \f$O(N^2\ln(N))\f$. However, compared to zero-padding,
44 * it can provide advantages in both speed
45 * and memory required for problems where oversampling is needed but only over a small region
46 * of the output.
47 */
48namespace mx
49{
50namespace math
51{
52namespace ft
53{
54
55template <typename _inputT, typename _outputT, size_t _rank, int _cudaGPU = 0>
56class mftT;
57
58/// Matrix Fourier Transforms
59/** Calculates the Discrete Fourier Transform (DFT) using matrix multiplication. This
60 * is normally much less efficient than the FFT, but for large oversampling (padding)
61 * the Matrix FT (MFT) will be much more space efficient and faster at the cost of
62 * "field of view".
63 *
64 * This interface is modeled after the \ref fftT<_inputT, _outputT, _rank, 0> "fftT" interface to fftw, and is interoperable with it.
65 * That means that using, e.g., mftT (unshifted, not-oversampled) for the forward transform
66 * and \ref fftT<_inputT, _outputT, _rank, 0> "fftT" for the backward
67 * transform is equivalent to using one or the other for both. Note that
68 * the MFT is normalized as in fftw, so by 1/N on the forward and by 1 on the backward.
69 *
70 * Oversampling is optionally included in the transform, which is equivalent to zero padding
71 * in terms of increased resolution \cite soummer_2007.
72 * The cost is that the output domain is truncated by the oversampling factor. I.e. if we
73 * oversample by a factor of 10, only 1/10th of the output transform is available.
74 *
75 * The output can be shifted as part of the MFT calculation, which is implemented similarly
76 * to <a href="https://www.mathworks.com/matlabcentral/fileexchange/18401-efficient-subpixel-image-registration-by-cross-correlation">
77 * this matlab code</a>.
78 *
79 * Note that when either oversampling or shifting is done on a forward (backward) transform,
80 * a subsequent backward (forward) transform will not in general be the inverse.
81 *
82 * \tparam inputT is the input type of the transform, only complex types are suppored by mftT
83 * \tparam outputT is the output type of the transform, only complex types are suppored by mftT
84 * \tparam _rank is the rank of the transform. Currently only rank 2 is implemented.
85 *
86 * \ingroup mft
87 */
88template <typename _inputT, typename _outputT, size_t _rank>
89class mftT<_inputT, _outputT, _rank, 0>
90{
91 typedef _inputT inputT;
92 typedef _outputT outputT;
93
94 typedef typename fftwTypeSpec<inputT, outputT>::realT realT;
95
96 typedef typename fftwTypeSpec<_inputT, _outputT>::complexT complexT;
97
98 static const size_t rank = _rank;
99
100 typedef Eigen::Array<inputT, -1, -1> eigenArrayInT;
101 typedef Eigen::Array<outputT, -1, -1> eigenArrayOutT;
102
103 typedef Eigen::Matrix<complexT, -1, -1> eigenMatrixT;
104
105 protected:
106 dir m_dir{ dir::forward }; /**< Direction of this MFT, either dir::forward (default)
107 or dir::backward */
108
109 int m_szX{ 0 }; ///< Size of the x dimension
110 int m_szY{ 0 }; ///< Size of the y dimension
111 int m_szZ{ 0 }; ///< size of the z dimension
112
113 float m_osFac{ 1 }; ///< The oversampling factor
114
115 realT m_xOff{ 0 }; ///< The offset in the rows direction for the center of the DFT.
116 realT m_yOff{ 0 }; ///< The offset in the columns direction for the center of the DFT.
117 public:
118 eigenMatrixT m_dftR; ///< DFT matrix for the rows
119 eigenMatrixT m_dftC; ///< DFT matrix for the columnss
120
121 public:
122 /// Default c'tor
124
125 /// Constructor for rank 1 MFT.
126 template <size_t crank = _rank>
127 mftT( int nx, ///< [in] the desired size of the MFT
128 dir ndir = dir::forward, /**< [in] [optional] direction of this MFT, either dir::forward
129 (default) or dir::backward */
130 realT xOff = 0, /**< [in] [optional] the x offset of the center of the
131 transformed array. Default 0.*/
132 realT osFac = 1.0, /**< [in] [optional] the oversampling factor. Default 1. */
133 typename std::enable_if<crank == 1>::type * = 0 ) = delete;
134
135 /// Constructor for rank 2 MFT.
136 template <size_t crank = _rank>
137 mftT( int nx, ///< [in] the desired x size of the MFT
138 int ny, ///< [in] the desired y size of the MFT
139 dir ndir = dir::forward, /**< [in] [optional] direction of this MFT, either dir::forward
140 (default) or dir::backward */
141 realT xOff = 0, /**< [in] [optional] the x offset of the center of the
142 transformed array. Default 0.*/
143 realT yOff = 0, /**< [in] [optional] the y offset of the center of the
144 transformed array Default 0.*/
145 realT osFac = 1.0, /**< [in] [optional] the oversampling factor. Default 1. */
146 typename std::enable_if<crank == 2>::type * = 0 );
147
148 /// Constructor for rank 3 MFT.
149 template <size_t crank = _rank>
150 mftT( int nx, ///< [in] the desired x size of the MFT
151 int ny, ///< [in] the desired y size of the MFT
152 int nz, ///< [in] the desired z size of the MFT
153 dir ndir = dir::forward, /**< [in] [optional] direction of this MFT, either dir::forward
154 (default) or dir::backward */
155 realT xOff = 0, /**< [in] [optional] the x offset of the center of the
156 transformed array. Default 0.*/
157 realT yOff = 0, /**< [in] [optional] the y offset of the center of the
158 transformed array Default 0.*/
159 realT zOff = 0, /**< [in] [optional] the z offset of the center of the
160 transformed array Default 0.*/
161 realT osFac = 1.0, /**< [in] [optional] the oversampling factor. Default 1. */
162 typename std::enable_if<crank == 3>::type * = 0 ) = delete;
163
164 /// Planning routine for rank 2 transforms.
165 template <size_t crank = _rank>
166 void plan( int nx, ///< [in] the desired x size of the MFT
167 int ny, ///< [in] the desired y size of the MFT
168 dir ndir = dir::forward, /**< [in] [optional] direction of this MFT, either dir::forward
169 (default) or dir::backward */
170 realT xOff = 0, /**< [in] [optional] the x offset of the center of the
171 transformed array. Default 0.*/
172 realT yOff = 0, /**< [in] [optional] the y offset of the center of the
173 transformed array Default 0.*/
174 realT osFac = 1.0, /**< [in] [optional] the oversampling factor. Default 1. */
175 typename std::enable_if<crank == 2>::type * = 0 );
176
177 /// Conduct the MFT
178 void operator()( eigenArrayOutT &out, /**< [out] the output of the DFT */
179 const eigenArrayInT &in /**< [in] the input to the DFT */ ) const;
180};
181
182template <typename inputT, typename outputT, size_t rank>
183mftT<inputT, outputT, rank, 0>::mftT()
184{
185}
186
187template <typename inputT, typename outputT, size_t rank>
188template <size_t crank>
189mftT<inputT, outputT, rank, 0>::mftT(
190 int nx, int ny, dir ndir, realT xoff, realT yoff, realT osFac, typename std::enable_if<crank == 2>::type * )
191{
192 plan( nx, ny, ndir, xoff, yoff, osFac );
193}
194
195template <typename inputT, typename outputT, size_t rank>
196template <size_t crank>
197void mftT<inputT, outputT, rank, 0>::plan(
198 int nx, int ny, dir ndir, realT xOff, realT yOff, realT osFac, typename std::enable_if<crank == 2>::type * )
199{
200 if(m_szX == nx && m_szY == ny && m_dir == ndir && m_xOff == xOff && m_yOff == yOff && m_osFac == osFac)
201 {
202 return;
203 }
204
205 m_szX = nx;
206 m_szY = ny;
207 m_dir = ndir;
208 m_xOff = xOff;
209 m_yOff = yOff;
210 m_osFac = osFac;
211
212 if( m_szX != m_szY )
213 {
214 throw std::invalid_argument( "MFT of non-square size is not implemented. nx must equal ny." );
215 }
216
217 // These should depend on szX too.
218 m_dftR.resize( m_szX, m_szX );
219 m_dftC.resize( m_szX, m_szX );
220
221 // There is probably an osNx and an osNy?
222 realT osN = m_szX * m_osFac;
223
224 if( m_dir == dir::forward )
225 {
226 realT sign = -1;
227 realT norm = 1.0 / ( m_szX * m_szY );
228
229 for( int cc = 0; cc < m_szY; ++cc )
230 {
231 realT ccx = cc;
232
233 for( int rr = 0; rr < m_szX; ++rr )
234 {
235 realT x = ( rr - m_xOff ) * ccx / osN;
236
237 m_dftR( rr, cc ) = norm * exp( complexT( { 0, sign * 2 * pi<realT>() * x } ) );
238
239 realT rrx = rr;
240
241 x = rrx * ( cc - m_yOff ) / osN;
242
243 m_dftC( rr, cc ) = norm * exp( complexT( { 0, sign * 2 * pi<realT>() * x } ) );
244 }
245 }
246 }
247 else
248 {
249 realT sign = +1;
250 realT norm = 1.0;
251
252 for( int cc = 0; cc < m_szY; ++cc )
253 {
254 realT ccx = cc;
255 if( ccx > m_szY / 2 )
256 ccx = -1 * ( m_szY - ccx );
257
258 for( int rr = 0; rr < m_szX; ++rr )
259 {
260 realT rrx = rr;
261 if( rrx > m_szX / 2 )
262 rrx = -1 * ( m_szX - rrx );
263
264 realT x = rrx * ( cc - m_xOff ) / osN;
265
266 m_dftR( cc, rr ) = norm * exp( complexT( { 0, sign * 2 * pi<realT>() * x } ) );
267
268 x = ( rr - m_yOff ) * ccx / osN;
269
270 m_dftC( cc, rr ) = norm * exp( complexT( { 0, sign * 2 * pi<realT>() * x } ) );
271 }
272 }
273 }
274}
275
276template <typename inputT, typename outputT, size_t rank>
277void mftT<inputT, outputT, rank, 0>::operator()( eigenArrayOutT &out, const eigenArrayInT &in ) const
278{
279 out = ( m_dftR * in.matrix() * m_dftC ).array();
280}
281
282} // namespace ft
283} // namespace math
284} // namespace mx
285
286#endif // mdft_hpp
eigenMatrixT m_dftC
DFT matrix for the columnss.
Definition mftT.hpp:119
float m_osFac
The oversampling factor.
Definition mftT.hpp:113
void operator()(eigenArrayOutT &out, const eigenArrayInT &in) const
Conduct the MFT.
mftT(int nx, int ny, dir ndir=dir::forward, realT xOff=0, realT yOff=0, realT osFac=1.0, typename std::enable_if< crank==2 >::type *=0)
Constructor for rank 2 MFT.
mftT(int nx, int ny, int nz, dir ndir=dir::forward, realT xOff=0, realT yOff=0, realT zOff=0, realT osFac=1.0, typename std::enable_if< crank==3 >::type *=0)=delete
Constructor for rank 3 MFT.
realT m_yOff
The offset in the columns direction for the center of the DFT.
Definition mftT.hpp:116
void plan(int nx, int ny, dir ndir=dir::forward, realT xOff=0, realT yOff=0, realT osFac=1.0, typename std::enable_if< crank==2 >::type *=0)
Planning routine for rank 2 transforms.
realT m_xOff
The offset in the rows direction for the center of the DFT.
Definition mftT.hpp:115
mftT(int nx, dir ndir=dir::forward, realT xOff=0, realT osFac=1.0, typename std::enable_if< crank==1 >::type *=0)=delete
Constructor for rank 1 MFT.
eigenMatrixT m_dftR
DFT matrix for the rows.
Definition mftT.hpp:118
Declares and defines templatized wrappers for the fftw library.
Fourier Transform Types.
dir
Directions of the Fourier Transform.
Definition ftTypes.hpp:41
@ forward
Specifies the forward transform.
Definition ftTypes.hpp:41
T sign(T x)
The sign function.
Definition sign.hpp:29
constexpr T pi()
Get the value of pi.
Definition constants.hpp:62
The mxlib c++ namespace.
Definition mxlib.hpp:37
std::complex< realT > complexT
The complex data type.
_realT realT
The real data type (_realT is actually defined in specializations).