mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
Loading...
Searching...
No Matches
psdFilterCuda.hpp
Go to the documentation of this file.
1/** \file psdFilterCuda.hpp
2 * \brief Declares and defines a class for filtering with PSDs on CUDA GPUs
3 * \ingroup signal_processing_files
4 * \author Jared R. Males (jaredmales@gmail.com)
5 *
6 */
7
8//***********************************************************************//
9// Copyright 2018 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 psdFilterCuda_hpp
28#define psdFilterCuda_hpp
29
30#include "../cuda/templateCudaPtr.hpp"
31#include "../cuda/templateCuda.hpp"
32
33#include "psdFilter.hpp"
34
35#include <cufft.h>
36#include <cufftXt.h>
37// #include <helper_functions.h>
38#include <helper_cuda.h>
39
40namespace mx
41{
42namespace sigproc
43{
44
45/// A class for filtering noise with PSDs using CUDA cuFFT
46/** The square-root of the PSD is maintained by this class, either as a pointer to an external array or using internally
47 allocated memory (which will be
48 * de-allocated on destruction.
49 *
50 * PSD Normalization: the PSD used for this needs to be normalized properly to produce filtered noise with the correct
51 statistics. Given an
52 * array of size N which contains the PSD as "power per unit frequency" vs frequency (i.e. the PSD) on some frequency
53 scale with uniform spacing \f$ \Delta f \f$,
54 * the normalization is
55 \f[
56 PSD_{norm} = PSD * N * \Delta f
57 \f]
58 * for a 1-dimensional PSD and
59 \f[
60 PSD_{norm} = PSD * N_0 * \Delta f_0 * N_1 * \Delta f_1
61 \f]
62 * for a 2-dimensional PSD. Remember that these are applied before taking the square root.
63 *
64 *
65 * \ingroup psd_filter
66 *
67 * \todo once fftT has a plan interface with pointers for working memory, use it.
68 */
69template <typename _realT>
70class psdFilter<_realT, 1>
71{
72 public:
73 typedef _realT realT; ///< Real floating point type
74 typedef std::complex<_realT> complexT; ///< Complex floating point type.
75 typedef Eigen::Array<realT, Eigen::Dynamic, Eigen::Dynamic> realArrayT; ///< Eigen array type with Scalar==realT
76 typedef Eigen::Array<complexT, Eigen::Dynamic, Eigen::Dynamic>
77 complexArrayT; ///< Eigen array type with Scalar==complexT
78
79 typedef realT deviceRealPtrT;
80 typedef complexT deviceComplexPtrT;
81
82 protected:
83 int m_rows{ 0 }; ///< The number of rows in the filter, and the required number of rows in the noise array.
84 int m_cols{ 0 }; ///< The number of columns in the filter, and the required number of columns in the noise array.
85
86 mx::cuda::cudaPtr<complexT> m_psdSqrt; ///< Pointer to the real array containing the square root of the PSD.
87
88 mx::cuda::cudaPtr<complexT> m_scale; ///< the scale factor.
89
90 /// Cuda FFT plan. We only need one since the forward/inverse is part of execution.
91 cufftHandle m_fftPlan{ 0 };
92
93 public:
94 /// C'tor.
96
97 /// Destructor
99
100 protected:
101 /// Set the size of the filter.
102 /** Handles allocation of the _ftWork array and fftw planning.
103 *
104 * Requires _psdSqrt to be set first. This is called by the psdSqrt() and psd() methods.
105 *
106 */
107 int setSize();
108
109 public:
110 /// Get the number of rows in the filter
111 /**
112 * \returns the current value of m_rows.
113 */
114 int rows();
115
116 /// Get the number of columns in the filter
117 /**
118 * \returns the current value of m_cols.
119 */
120 int cols();
121
122 /// Set the sqaure-root of the PSD.
123 /** This allocates _npsdSqrt and fills it with th evalues in the array.
124 *
125 * See the discussion of PSD normalization above.
126 *
127 * \returns 0 on success
128 * \returns -1 on error
129 */
130 int psdSqrt( const realArrayT &npsdSqrt /**< [in] an array containing the square root of the PSD.*/ );
131
133 const cuda::cudaPtr<std::complex<realT>> &npsdSqrt, /**< [in] an array containing the square root of the PSD.*/
134 size_t rows,
135 size_t cols );
136
137 /// De-allocate all working memory and reset to initial state.
138 void clear();
139
140 /// Apply the filter.
141 /**
142 *
143 * \returns 0 on success
144 * \returns -1 on error
145 */
146 int
147 filter( deviceComplexPtrT *noise ///< [in.out] the noise field of size rows() X cols(), which is filtered in-place.
148 );
149
150 /// Apply the filter.
151 /**
152 * \returns 0 on success
153 * \returns -1 on error
154 */
156 realArrayT &noise /**< [in.out] the noise field of size rows() X cols(), which is filtered in-place. */ );
157
158 /// Apply the filter.
159 /**
160 * \returns 0 on success
161 * \returns -1 on error
162 */
163 int
164 operator()( realArrayT &noise, ///< [in.out] the noise field of size rows() X cols(), which is filtered in-place.
165 realArrayT &noiseIm ///< [out] [optional] an array to fill with the imaginary output of the filter,
166 ///< allowing 2-for-1 calculation.
167 );
168};
169
170template <typename realT>
171psdFilter<realT, 1>::psdFilter()
172{
173}
174
175template <typename realT>
176psdFilter<realT, 1>::~psdFilter()
177{
178 if( m_fftPlan )
179 {
180 checkCudaErrors( cufftDestroy( m_fftPlan ) );
181 }
182}
183
184template <typename realT>
185int psdFilter<realT, 1>::setSize()
186{
187
188 m_scale.resize( 1 );
189 std::complex<realT> scale( 1. / ( m_rows * m_cols ), 0 );
190 m_scale.upload( &scale, 1 );
191
192 checkCudaErrors( cufftPlan2d( &m_fftPlan, m_rows, m_cols, CUFFT_C2C ) );
193
194 return 0;
195}
196
197template <typename realT>
198int psdFilter<realT, 1>::rows()
199{
200 return m_rows;
201}
202
203template <typename realT>
204int psdFilter<realT, 1>::cols()
205{
206 return m_cols;
207}
208
209// template<typename realT>
210// int psdFilter<realT,1>::psdSqrt( realArrayT * npsdSqrt )
211// {
212// if(_psdSqrt && _owner)
213// {
214// delete _psdSqrt;
215// }
216//
217// _psdSqrt = npsdSqrt;
218// _owner = false;
219//
220// setSize();
221//
222// return 0;
223// }
224
225template <typename realT>
226int psdFilter<realT, 1>::psdSqrt( const realArrayT &npsdSqrt )
227{
228 m_rows = npsdSqrt.rows();
229 m_cols = npsdSqrt.cols();
230
231 complexArrayT tmp( m_rows, m_cols );
232 tmp.setZero();
233 tmp.real() = npsdSqrt;
234
235 m_psdSqrt.upload( tmp.data(), m_rows * m_cols );
236
237 setSize();
238
239 return 0;
240}
241
242template <typename realT>
243int psdFilter<realT, 1>::psdSqrt( const cuda::cudaPtr<std::complex<realT>> &npsdSqrt, size_t rows, size_t cols )
244{
245 m_rows = rows;
246 m_cols = cols;
247
248 m_psdSqrt.resize( m_rows * m_cols );
249
250 ///\todo move this into cudaPtr
251 cudaMemcpy( m_psdSqrt.m_devicePtr,
252 npsdSqrt.m_devicePtr,
253 m_rows * m_cols * sizeof( std::complex<realT> ),
254 cudaMemcpyDeviceToDevice );
255
256 setSize();
257
258 return 0;
259}
260
261template <typename realT>
262void psdFilter<realT, 1>::clear()
263{
264 m_scale.resize( 0 );
265 m_rows = 0;
266 m_cols = 0;
267
268 m_psdSqrt.resize( 0 );
269}
270
271template <typename realT>
272int psdFilter<realT, 1>::filter( deviceComplexPtrT *noise )
273{
274
275 // Transform complex noise to Fourier domain.
276
277 cufftExecC2C( m_fftPlan, (cuComplex *)noise, (cuComplex *)noise, CUFFT_FORWARD );
278
279 // Apply the filter.
280 mx::cuda::pointwiseMul<cuComplex>
281 <<<32, 256>>>( (cuComplex *)noise, (cufftComplex *)m_psdSqrt.m_devicePtr, m_rows * m_cols );
282
283 cufftExecC2C( m_fftPlan, (cuComplex *)noise, (cuComplex *)noise, CUFFT_INVERSE );
284
285 mx::cuda::scalarMul<cuComplex>
286 <<<32, 256>>>( (cuComplex *)noise, (cuComplex *)m_scale.m_devicePtr, m_rows * m_cols );
287 // Now take the real part, and normalize.
288
289 // noise = noise/(noise.rows()*noise.cols());
290
291 return 0;
292}
293
294template <typename realT>
295int psdFilter<realT, 1>::operator()( realArrayT &noise )
296{
297 return filter( noise );
298}
299
300template <typename realT>
301int psdFilter<realT, 1>::operator()( realArrayT &noise, realArrayT &noiseIm )
302{
303 return filter( noise, &noiseIm );
304}
305
306} // namespace sigproc
307} // namespace mx
308
309#endif // psdFilterCuda_hpp
int psdSqrt(const realArrayT &npsdSqrt)
Set the sqaure-root of the PSD.
_realT realT
Real floating point type.
int filter(deviceComplexPtrT *noise)
Apply the filter.
int cols()
Get the number of columns in the filter.
std::complex< _realT > complexT
Complex floating point type.
int psdSqrt(const cuda::cudaPtr< std::complex< realT > > &npsdSqrt, size_t rows, size_t cols)
Eigen::Array< realT, Eigen::Dynamic, Eigen::Dynamic > realArrayT
Eigen array type with Scalar==realT.
int operator()(realArrayT &noise, realArrayT &noiseIm)
Apply the filter.
mx::cuda::cudaPtr< complexT > m_scale
the scale factor.
mx::cuda::cudaPtr< complexT > m_psdSqrt
Pointer to the real array containing the square root of the PSD.
int setSize()
Set the size of the filter.
Eigen::Array< complexT, Eigen::Dynamic, Eigen::Dynamic > complexArrayT
Eigen array type with Scalar==complexT.
int operator()(realArrayT &noise)
Apply the filter.
void clear()
De-allocate all working memory and reset to initial state.
int rows()
Get the number of rows in the filter.
The mxlib c++ namespace.
Definition mxError.hpp:106
Declares and defines a class for filtering with PSDs.
A smart-pointer wrapper for cuda device pointers.
Definition cudaPtr.hpp:47