1 | #include "fftservintf.h"
|
---|
2 |
|
---|
3 |
|
---|
4 | /*!
|
---|
5 | \class SOPHYA::FFTServerInterface
|
---|
6 | \ingroup NTools
|
---|
7 | Defines the interface for FFT (Fast Fourier Transform) operations.
|
---|
8 | Definitions :
|
---|
9 | - Sampling period \b T
|
---|
10 | - Sampling frequency \b fs=1/T
|
---|
11 | - Total number of samples \b N
|
---|
12 | - Frequency step in Fourier space \b =fs/N=1/(N*T)
|
---|
13 | - Component frequencies
|
---|
14 | - k=0 -> 0
|
---|
15 | - k=1 -> 1/(N*T)
|
---|
16 | - k -> k/(N*T)
|
---|
17 | - k=N/2 -> 1/(2*T) (Nyquist frequency)
|
---|
18 | - k>N/2 -> k/(N*T) (or negative frequency -(N-k)/(N*T))
|
---|
19 |
|
---|
20 | For a sampling period T=1, the computed Fourier components correspond to :
|
---|
21 | \verbatim
|
---|
22 | 0 1/N 2/N ... 1/2 1/2+1/N 1/2+2/N ... 1-2/N 1-1/N
|
---|
23 | 0 1/N 2/N ... 1/2 ... -2/N -1/N
|
---|
24 | \endverbatim
|
---|
25 |
|
---|
26 | For complex one-dimensional transforms:
|
---|
27 | \f[
|
---|
28 | out(i) = F_{norm} \Sigma_{j} \ e^{-2 \pi \sqrt{-1} \ i \ j} \ {\rm (forward)}
|
---|
29 | \f]
|
---|
30 | \f[
|
---|
31 | out(i) = F_{norm} \Sigma_{j} \ e^{2 \pi \sqrt{-1} \ i \ j} \ {\rm (backward)}
|
---|
32 | \f]
|
---|
33 | i,j= 0..N-1 , where N is the input or the output array size.
|
---|
34 |
|
---|
35 | For complex multi-dimensional transforms:
|
---|
36 | \f[
|
---|
37 | out(i1,i2,...,id) = F_{norm} \Sigma_{j1} \Sigma_{j2} ... \Sigma_{jd} \
|
---|
38 | e^{-2 \pi \sqrt{-1} \ i1 \ j1} ... e^{-2 \pi \sqrt{-1} \ id \ jd} \ {\rm (forward)}
|
---|
39 | \f]
|
---|
40 | \f[
|
---|
41 | out(i1,i2,...,id) = F_{norm} \Sigma_{j1} \Sigma_{j2} ... \Sigma_{jd} \
|
---|
42 | e^{2 \pi \sqrt{-1} \ i1 \ j1} ... e^{2 \pi \sqrt{-1} \ id \ jd} \ {\rm (backward)}
|
---|
43 | \f]
|
---|
44 |
|
---|
45 | For real forward transforms, the input array is real, and
|
---|
46 | the output array complex, with Fourier components up to k=N/2.
|
---|
47 | For real backward transforms, the input array is complex and
|
---|
48 | the output array is real.
|
---|
49 | */
|
---|
50 |
|
---|
51 | /* --Methode-- */
|
---|
52 | FFTServerInterface::FFTServerInterface(string info)
|
---|
53 | {
|
---|
54 | _info = info;
|
---|
55 | _fgnorm = true;
|
---|
56 | }
|
---|
57 |
|
---|
58 | /* --Methode-- */
|
---|
59 | FFTServerInterface::~FFTServerInterface()
|
---|
60 | {
|
---|
61 | }
|
---|
62 |
|
---|
63 | // ----------------- Transforme pour les double -------------------
|
---|
64 |
|
---|
65 | /* --Methode-- */
|
---|
66 | //! Forward Fourier transform for double precision complex data
|
---|
67 | /*!
|
---|
68 | \param in : Input complex array
|
---|
69 | \param out : Output complex array
|
---|
70 | */
|
---|
71 | void FFTServerInterface::FFTForward(TArray< complex<r_8> > const &, TArray< complex<r_8> > &)
|
---|
72 | {
|
---|
73 | throw NotAvailableOperation("FFTServer::FFTForward(TArray...) Unsupported operation !");
|
---|
74 | }
|
---|
75 |
|
---|
76 | /* --Methode-- */
|
---|
77 | //! Backward (inverse) Fourier transform for double precision complex data
|
---|
78 | /*!
|
---|
79 | \param in : Input complex array
|
---|
80 | \param out : Output complex array
|
---|
81 | */
|
---|
82 | void FFTServerInterface::FFTBackward(TArray< complex<r_8> > const &, TArray< complex<r_8> > &)
|
---|
83 | {
|
---|
84 | throw NotAvailableOperation("FFTServer::FFTBackward(TArray...) Unsupported operation !");
|
---|
85 | }
|
---|
86 |
|
---|
87 | /* --Methode-- */
|
---|
88 | //! Forward Fourier transform for double precision real input data
|
---|
89 | /*!
|
---|
90 | \param in : Input real array
|
---|
91 | \param out : Output complex array
|
---|
92 | */
|
---|
93 | void FFTServerInterface::FFTForward(TArray< r_8 > const &, TArray< complex<r_8> > &)
|
---|
94 | {
|
---|
95 | throw NotAvailableOperation("FFTServer::FFTForward(TArray...) Unsupported operation !");
|
---|
96 | }
|
---|
97 |
|
---|
98 | /* --Methode-- */
|
---|
99 | //! Backward (inverse) Fourier transform for double precision real output data
|
---|
100 | /*!
|
---|
101 | \param in : Input complex array
|
---|
102 | \param out : Output real array
|
---|
103 | \param usoutsz : if true, use the output array size for computing the inverse FFT.
|
---|
104 | */
|
---|
105 | void FFTServerInterface::FFTBackward(TArray< complex<r_8> > const &, TArray< r_8 > &, bool)
|
---|
106 | {
|
---|
107 | throw NotAvailableOperation("FFTServer::FFTBackward(TArray...) Unsupported operation !");
|
---|
108 | }
|
---|
109 |
|
---|
110 |
|
---|
111 | // ----------------- Transforme pour les float -------------------
|
---|
112 |
|
---|
113 | /* --Methode-- */
|
---|
114 | //! Forward Fourier transform for complex data
|
---|
115 | /*!
|
---|
116 | \param in : Input complex array
|
---|
117 | \param out : Output complex array
|
---|
118 | */
|
---|
119 | void FFTServerInterface::FFTForward(TArray< complex<r_4> > const &, TArray< complex<r_4> > &)
|
---|
120 | {
|
---|
121 | throw NotAvailableOperation("FFTServer::FFTForward(TArray r_4 ... ) Unsupported operation !");
|
---|
122 | }
|
---|
123 |
|
---|
124 | /* --Methode-- */
|
---|
125 | //! Backward (inverse) Fourier transform for complex data
|
---|
126 | /*!
|
---|
127 | \param in : Input complex array
|
---|
128 | \param out : Output complex array
|
---|
129 | */
|
---|
130 | void FFTServerInterface::FFTBackward(TArray< complex<r_4> > const &, TArray< complex<r_4> > &)
|
---|
131 | {
|
---|
132 | throw NotAvailableOperation("FFTServer::FFTBackward(TArray r_4 ... ) Unsupported operation !");
|
---|
133 | }
|
---|
134 |
|
---|
135 | /* --Methode-- */
|
---|
136 | //! Forward Fourier transform for real input data
|
---|
137 | /*!
|
---|
138 | \param in : Input real array
|
---|
139 | \param out : Output complex array
|
---|
140 | */
|
---|
141 | void FFTServerInterface::FFTForward(TArray< r_4 > const &, TArray< complex<r_4> > &)
|
---|
142 | {
|
---|
143 | throw NotAvailableOperation("FFTServer::FFTForward(TArray r_4 ... ) Unsupported operation !");
|
---|
144 | }
|
---|
145 |
|
---|
146 | /* --Methode-- */
|
---|
147 | //! Backward (inverse) Fourier transform for real output data
|
---|
148 | /*!
|
---|
149 | \param in : Input complex array
|
---|
150 | \param out : Output real array
|
---|
151 | \param usoutsz : if true, use the output array size for computing the inverse FFT.
|
---|
152 | */
|
---|
153 | void FFTServerInterface::FFTBackward(TArray< complex<r_4> > const &, TArray< r_4 > &, bool)
|
---|
154 | {
|
---|
155 | throw NotAvailableOperation("FFTServer::FFTBackward(TArray r_4 ... ) Unsupported operation !");
|
---|
156 | }
|
---|
157 |
|
---|
158 |
|
---|
159 |
|
---|
160 | /* --Methode-- */
|
---|
161 | /*!
|
---|
162 | \class SOPHYA::FFTArrayChecker
|
---|
163 | \ingroup NTools
|
---|
164 | Service class for checking array size and resizing output arrays,
|
---|
165 | to be used by FFTServer classes
|
---|
166 | */
|
---|
167 |
|
---|
168 | template <class T>
|
---|
169 | FFTArrayChecker<T>::FFTArrayChecker(string msg, bool checkpack, bool onedonly)
|
---|
170 | {
|
---|
171 | _msg = msg + " FFTArrayChecker::";
|
---|
172 | _checkpack = checkpack;
|
---|
173 | _onedonly = onedonly;
|
---|
174 | }
|
---|
175 |
|
---|
176 | /* --Methode-- */
|
---|
177 | template <class T>
|
---|
178 | FFTArrayChecker<T>::~FFTArrayChecker()
|
---|
179 | {
|
---|
180 | }
|
---|
181 |
|
---|
182 | template <class T>
|
---|
183 | T FFTArrayChecker<T>::ZeroThreshold()
|
---|
184 | {
|
---|
185 | return(0);
|
---|
186 | }
|
---|
187 |
|
---|
188 | r_8 FFTArrayChecker< r_8 >::ZeroThreshold()
|
---|
189 | {
|
---|
190 | return(1.e-18);
|
---|
191 | }
|
---|
192 |
|
---|
193 | r_4 FFTArrayChecker< r_4 >::ZeroThreshold()
|
---|
194 | {
|
---|
195 | return(1.e-9);
|
---|
196 | }
|
---|
197 |
|
---|
198 |
|
---|
199 |
|
---|
200 | /* --Methode-- */
|
---|
201 | template <class T>
|
---|
202 | int FFTArrayChecker<T>::CheckResize(TArray< complex<T> > const & in, TArray< complex<T> > & out)
|
---|
203 | {
|
---|
204 | int k;
|
---|
205 | string msg;
|
---|
206 | if (in.Size() < 1) {
|
---|
207 | msg = _msg + "CheckResize(complex in, complex out) - Unallocated input array !";
|
---|
208 | throw(SzMismatchError(msg));
|
---|
209 | }
|
---|
210 | if (_checkpack)
|
---|
211 | if ( !in.IsPacked() ) {
|
---|
212 | msg = _msg + "CheckResize(complex in, complex out) - Not packed input array !";
|
---|
213 | throw(SzMismatchError(msg));
|
---|
214 | }
|
---|
215 | int ndg1 = 0;
|
---|
216 | for(k=0; k<in.NbDimensions(); k++)
|
---|
217 | if (in.Size(k) > 1) ndg1++;
|
---|
218 | if (_onedonly)
|
---|
219 | if (ndg1 > 1) {
|
---|
220 | msg = _msg + "CheckResize(complex in, complex out) - Only 1-D array accepted !";
|
---|
221 | throw(SzMismatchError(msg));
|
---|
222 | }
|
---|
223 | out.ReSize(in);
|
---|
224 | // sa_size_t sz[BASEARRAY_MAXNDIMS];
|
---|
225 | // for(k=0; k<in.NbDimensions(); k++)
|
---|
226 | // sz[k] = in.Size(k);
|
---|
227 | // out.ReSize(in.NbDimensions(), sz);
|
---|
228 |
|
---|
229 | return(ndg1);
|
---|
230 | }
|
---|
231 |
|
---|
232 | /* --Methode-- */
|
---|
233 | template <class T>
|
---|
234 | int FFTArrayChecker<T>::CheckResize(TArray< T > const & in, TArray< complex<T> > & out)
|
---|
235 | {
|
---|
236 | int k;
|
---|
237 | string msg;
|
---|
238 | if (in.Size() < 1) {
|
---|
239 | msg = _msg + "CheckResize(real in, complex out) - Unallocated input array !";
|
---|
240 | throw(SzMismatchError(msg));
|
---|
241 | }
|
---|
242 | if (_checkpack)
|
---|
243 | if ( !in.IsPacked() ) {
|
---|
244 | msg = _msg + "CheckResize(real in, complex out) - Not packed input array !";
|
---|
245 | throw(SzMismatchError(msg));
|
---|
246 | }
|
---|
247 | int ndg1 = 0;
|
---|
248 | for(k=0; k<in.NbDimensions(); k++)
|
---|
249 | if (in.Size(k) > 1) ndg1++;
|
---|
250 | if (_onedonly)
|
---|
251 | if (ndg1 > 1) {
|
---|
252 | msg = _msg + "CheckResize(real in, complex out) - Only 1-D array accepted !";
|
---|
253 | throw(SzMismatchError(msg));
|
---|
254 | }
|
---|
255 | sa_size_t sz[BASEARRAY_MAXNDIMS];
|
---|
256 | //
|
---|
257 | if (ndg1 > 1) {
|
---|
258 | sz[0] = in.Size(0)/2+1;
|
---|
259 | for(k=1; k<in.NbDimensions(); k++)
|
---|
260 | sz[k] = in.Size(k);
|
---|
261 | }
|
---|
262 | else {
|
---|
263 | for(k=0; k<BASEARRAY_MAXNDIMS; k++) sz[k] = 1;
|
---|
264 | sz[in.MaxSizeKA()] = in.Size(in.MaxSizeKA())/2+1;
|
---|
265 | // sz[k] = in.Size(k)/2+1;
|
---|
266 | // sz[k] = (in.Size(k)%2 != 0) ? in.Size(k)/2+1 : in.Size(k)/2;
|
---|
267 | }
|
---|
268 | out.ReSize(in.NbDimensions(), sz);
|
---|
269 |
|
---|
270 | return(ndg1);
|
---|
271 | }
|
---|
272 |
|
---|
273 | /* --Methode-- */
|
---|
274 | template <class T>
|
---|
275 | int FFTArrayChecker<T>::CheckResize(TArray< complex<T> > const & in, TArray< T > & out,
|
---|
276 | bool usoutsz)
|
---|
277 | {
|
---|
278 | int k;
|
---|
279 | string msg;
|
---|
280 | if (in.Size() < 1) {
|
---|
281 | msg = _msg + "CheckResize(complex in, real out) - Unallocated input array !";
|
---|
282 | throw(SzMismatchError(msg));
|
---|
283 | }
|
---|
284 | if (_checkpack)
|
---|
285 | if ( !in.IsPacked() ) {
|
---|
286 | msg = _msg + "CheckResize(complex in, real out) - Not packed input array !";
|
---|
287 | throw(SzMismatchError(msg));
|
---|
288 | }
|
---|
289 | int ndg1 = 0;
|
---|
290 | for(k=0; k<in.NbDimensions(); k++)
|
---|
291 | if (in.Size(k) > 1) ndg1++;
|
---|
292 | if (_onedonly)
|
---|
293 | if (ndg1 > 1) {
|
---|
294 | msg = _msg + "CheckResize(complex in, real out) - Only 1-D array accepted !";
|
---|
295 | throw(SzMismatchError(msg));
|
---|
296 | }
|
---|
297 | if (usoutsz) { // We have to use output array size
|
---|
298 | bool fgerr = false;
|
---|
299 | if (ndg1 > 1) {
|
---|
300 | if (in.Size(0) != out.Size(0)/2+1) fgerr = true;
|
---|
301 | }
|
---|
302 | else {
|
---|
303 | if (in.Size(in.MaxSizeKA()) != out.Size(in.MaxSizeKA())/2+1) fgerr = true;
|
---|
304 | }
|
---|
305 | if (fgerr) {
|
---|
306 | msg = _msg + "CheckResize(complex in, real out) - Incompatible in-out sizes !";
|
---|
307 | throw(SzMismatchError(msg));
|
---|
308 | }
|
---|
309 | }
|
---|
310 | else { // We have to resize the output array
|
---|
311 | sa_size_t sz[BASEARRAY_MAXNDIMS];
|
---|
312 | if (ndg1 > 1) {
|
---|
313 | sz[0] = 2*in.Size(0)-1;
|
---|
314 | for(k=1; k<in.NbDimensions(); k++)
|
---|
315 | sz[k] = in.Size(k);
|
---|
316 | // sz[k] = in.Size(k)*2-1;
|
---|
317 | }
|
---|
318 | else {
|
---|
319 | for(k=0; k<BASEARRAY_MAXNDIMS; k++) sz[k] = 1;
|
---|
320 | T thr = ZeroThreshold();
|
---|
321 | sa_size_t n = in.Size(in.MaxSizeKA());
|
---|
322 | sa_size_t ncs = ( (in[n-1].imag() < -thr) || (in[n-1].imag() > thr) ) ?
|
---|
323 | ncs = 2*n-1 : ncs = 2*n-2;
|
---|
324 | sz[in.MaxSizeKA()] = ncs;
|
---|
325 | }
|
---|
326 | out.ReSize(in.NbDimensions(), sz);
|
---|
327 | }
|
---|
328 |
|
---|
329 | return(ndg1);
|
---|
330 |
|
---|
331 | }
|
---|
332 |
|
---|
333 |
|
---|
334 | #ifdef __CXX_PRAGMA_TEMPLATES__
|
---|
335 | #pragma define_template FFTArrayChecker<r_4>
|
---|
336 | #pragma define_template FFTArrayChecker<r_8>
|
---|
337 | #endif
|
---|
338 |
|
---|
339 | #if defined(ANSI_TEMPLATES) || defined(GNU_TEMPLATES)
|
---|
340 | template class FFTArrayChecker<r_4>;
|
---|
341 | template class FFTArrayChecker<r_8>;
|
---|
342 | #endif
|
---|