source: Sophya/trunk/SophyaLib/NTools/fftservintf.cc@ 2367

Last change on this file since 2367 was 2344, checked in by ansari, 23 years ago

Compilation (fin ?) avec SGI-CC -LANG:std - Reza 10/03/2003

File size: 12.2 KB
Line 
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-- */
52FFTServerInterface::FFTServerInterface(string info)
53{
54 _info = info;
55 _fgnorm = true;
56}
57
58/* --Methode-- */
59FFTServerInterface::~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 */
71void 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 */
82void 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 */
93void 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 */
105void 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 */
119void 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 */
130void 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 */
141void 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 */
153void 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// ----------------- Transformation de normalisation pour les energies -------------------
160
161/* --Methode-- */
162//! Compute the transform to be applied to "fftx=FFT(x)" so that "x" and "FFT(x)" have the same energy
163/*!
164\return The factor to be applied to the FFT energy such that we get the same energy as for the x.
165\verbatim
166 fftx is computed by: FFTForward(x,fftx)
167 Energy of x : Ex = sum{|x(i)|^2} i=0,x.Size()-1
168 Energy of fftx : Efftx = sum{|fftx(i)^2|} i=0,fftx.Size()-1
169 ( usually x.Size() != fftx.Size() )
170 -------------------------------------------------------------------
171 | TransfEnergyFFT return A and B such that : Ex = A * Efftx + B |
172 | and Norm such that : Ex = Norm * Efftx |
173 -------------------------------------------------------------------
174 To normalize the fftx vector apply : "fftx *= sqrt(Norm)"
175\endverbatim
176*/
177r_8 FFTServerInterface::TransfEnergyFFT
178 (TVector< complex<r_8> > const& x, TVector< complex<r_8> > const& fftx, r_8& A, r_8& B)
179{
180 B=0.;
181 if(getNormalize()) A = x.Size(); else A = 1./x.Size();
182 r_8 norm = A;
183 return norm;
184}
185
186//! Compute the transform to be applied to "fftx=FFT(x)" so that "x" and "FFT(x)" have the same energy
187r_8 FFTServerInterface::TransfEnergyFFT
188 (TVector< complex<r_4> > const & x, TVector< complex<r_4> > const & fftx, r_8& A, r_8& B)
189{
190 B=0.;
191 if(getNormalize()) A = x.Size(); else A = 1./x.Size();
192 r_8 norm = A;
193 return norm;
194}
195
196//! Compute the transform to be applied to "fftx=FFT(x)" so that "x" and "FFT(x)" have the same energy
197r_8 FFTServerInterface::TransfEnergyFFT
198 (TVector< r_8 > const & x, TVector< complex<r_8> > const & fftx, r_8& A, r_8& B)
199{
200 A= 2.;
201 B= - abs(fftx(0)*fftx(0));
202 if(x.Size()%2 == 0) B -= abs(fftx(fftx.Size()-1)*fftx(fftx.Size()-1));
203 if(getNormalize()) {A *= x.Size(); B *= x.Size();}
204 else {A /= x.Size(); B /= x.Size();}
205 r_8 norm = 0.;
206 for(int_4 i=0;i<fftx.Size();i++) norm += abs(fftx(i)*fftx(i));
207 if(norm>0.) norm = (A*norm+B)/norm;
208 return norm;
209}
210
211//! Compute the transform to be applied to "fftx=FFT(x)" so that "x" and "FFT(x)" have the same energy
212r_8 FFTServerInterface::TransfEnergyFFT
213 (TVector< r_4 > const & x, TVector< complex<r_4> > const & fftx, r_8& A, r_8& B)
214{
215 A= 2.;
216 B= - abs(fftx(0)*fftx(0));
217 if(x.Size()%2 == 0) B -= abs(fftx(fftx.Size()-1)*fftx(fftx.Size()-1));
218 if(getNormalize()) {A *= x.Size(); B *= x.Size();}
219 else {A /= x.Size(); B /= x.Size();}
220 r_8 norm = 0.;
221 for(int_4 i=0;i<fftx.Size();i++) norm += abs(fftx(i)*fftx(i));
222 if(norm>0.) norm = (A*norm+B)/norm;
223 return norm;
224}
225
226
227/* --Methode-- */
228/*!
229 \class SOPHYA::FFTArrayChecker
230 \ingroup NTools
231 Service class for checking array size and resizing output arrays,
232 to be used by FFTServer classes
233*/
234
235template <class T>
236FFTArrayChecker<T>::FFTArrayChecker(string msg, bool checkpack, bool onedonly)
237{
238 _msg = msg + " FFTArrayChecker::";
239 _checkpack = checkpack;
240 _onedonly = onedonly;
241}
242
243/* --Methode-- */
244template <class T>
245FFTArrayChecker<T>::~FFTArrayChecker()
246{
247}
248
249template <class T>
250T FFTArrayChecker<T>::ZeroThreshold()
251{
252 return(0);
253}
254
255DECL_TEMP_SPEC /* equivalent a template <> , pour SGI-CC en particulier */
256r_8 FFTArrayChecker< r_8 >::ZeroThreshold()
257{
258 return(1.e-39);
259}
260
261DECL_TEMP_SPEC /* equivalent a template <> , pour SGI-CC en particulier */
262r_4 FFTArrayChecker< r_4 >::ZeroThreshold()
263{
264 return(1.e-19);
265}
266
267/* --Methode-- */
268template <class T>
269int FFTArrayChecker<T>::CheckResize(TArray< complex<T> > const & in, TArray< complex<T> > & out)
270{
271 int k;
272 string msg;
273 if (in.Size() < 1) {
274 msg = _msg + "CheckResize(complex in, complex out) - Unallocated input array !";
275 throw(SzMismatchError(msg));
276 }
277 if (_checkpack)
278 if ( !in.IsPacked() ) {
279 msg = _msg + "CheckResize(complex in, complex out) - Not packed input array !";
280 throw(SzMismatchError(msg));
281 }
282 int ndg1 = 0;
283 for(k=0; k<in.NbDimensions(); k++)
284 if (in.Size(k) > 1) ndg1++;
285 if (_onedonly)
286 if (ndg1 > 1) {
287 msg = _msg + "CheckResize(complex in, complex out) - Only 1-D array accepted !";
288 throw(SzMismatchError(msg));
289 }
290 out.ReSize(in);
291 // sa_size_t sz[BASEARRAY_MAXNDIMS];
292 // for(k=0; k<in.NbDimensions(); k++)
293 // sz[k] = in.Size(k);
294 // out.ReSize(in.NbDimensions(), sz);
295
296 return(ndg1);
297}
298
299/* --Methode-- */
300template <class T>
301int FFTArrayChecker<T>::CheckResize(TArray< T > const & in, TArray< complex<T> > & out)
302{
303 int k;
304 string msg;
305 if (in.Size() < 1) {
306 msg = _msg + "CheckResize(real in, complex out) - Unallocated input array !";
307 throw(SzMismatchError(msg));
308 }
309 if (_checkpack)
310 if ( !in.IsPacked() ) {
311 msg = _msg + "CheckResize(real in, complex out) - Not packed input array !";
312 throw(SzMismatchError(msg));
313 }
314 int ndg1 = 0;
315 for(k=0; k<in.NbDimensions(); k++)
316 if (in.Size(k) > 1) ndg1++;
317 if (_onedonly)
318 if (ndg1 > 1) {
319 msg = _msg + "CheckResize(real in, complex out) - Only 1-D array accepted !";
320 throw(SzMismatchError(msg));
321 }
322 sa_size_t sz[BASEARRAY_MAXNDIMS];
323 //
324 if (ndg1 > 1) {
325 sz[0] = in.Size(0)/2+1;
326 for(k=1; k<in.NbDimensions(); k++)
327 sz[k] = in.Size(k);
328 }
329 else {
330 for(k=0; k<BASEARRAY_MAXNDIMS; k++) sz[k] = 1;
331 sz[in.MaxSizeKA()] = in.Size(in.MaxSizeKA())/2+1;
332 // sz[k] = in.Size(k)/2+1;
333 // sz[k] = (in.Size(k)%2 != 0) ? in.Size(k)/2+1 : in.Size(k)/2;
334 }
335 out.ReSize(in.NbDimensions(), sz);
336
337 return(ndg1);
338}
339
340/* --Methode-- */
341template <class T>
342int FFTArrayChecker<T>::CheckResize(TArray< complex<T> > const & in, TArray< T > & out,
343 bool usoutsz)
344{
345 int k;
346 string msg;
347 if (in.Size() < 1) {
348 msg = _msg + "CheckResize(complex in, real out) - Unallocated input array !";
349 throw(SzMismatchError(msg));
350 }
351 if (_checkpack)
352 if ( !in.IsPacked() ) {
353 msg = _msg + "CheckResize(complex in, real out) - Not packed input array !";
354 throw(SzMismatchError(msg));
355 }
356 int ndg1 = 0;
357 for(k=0; k<in.NbDimensions(); k++)
358 if (in.Size(k) > 1) ndg1++;
359 if (_onedonly)
360 if (ndg1 > 1) {
361 msg = _msg + "CheckResize(complex in, real out) - Only 1-D array accepted !";
362 throw(SzMismatchError(msg));
363 }
364 if (usoutsz) { // We have to use output array size
365 bool fgerr = false;
366 if (ndg1 > 1) {
367 if (in.Size(0) != out.Size(0)/2+1) fgerr = true;
368 }
369 else {
370 if (in.Size(in.MaxSizeKA()) != out.Size(in.MaxSizeKA())/2+1) fgerr = true;
371 }
372 if (fgerr) {
373 msg = _msg + "CheckResize(complex in, real out) - Incompatible in-out sizes !";
374 throw(SzMismatchError(msg));
375 }
376 }
377 else { // We have to resize the output array
378 sa_size_t sz[BASEARRAY_MAXNDIMS];
379 if (ndg1 > 1) {
380 sz[0] = 2*in.Size(0)-1;
381 for(k=1; k<in.NbDimensions(); k++)
382 sz[k] = in.Size(k);
383 // sz[k] = in.Size(k)*2-1;
384 }
385 else {
386 for(k=0; k<BASEARRAY_MAXNDIMS; k++) sz[k] = 1;
387 T thr = ZeroThreshold();
388 sa_size_t n = in.Size(in.MaxSizeKA());
389 sa_size_t ncs = ( (in[n-1].imag() < -thr) || (in[n-1].imag() > thr) )
390 ? 2*n-1 : 2*n-2;
391 sz[in.MaxSizeKA()] = ncs;
392 }
393 out.ReSize(in.NbDimensions(), sz);
394 }
395
396 return(ndg1);
397
398}
399
400
401#ifdef __CXX_PRAGMA_TEMPLATES__
402#pragma define_template FFTArrayChecker<r_4>
403#pragma define_template FFTArrayChecker<r_8>
404#endif
405
406#if defined(ANSI_TEMPLATES) || defined(GNU_TEMPLATES)
407template class FFTArrayChecker<r_4>;
408template class FFTArrayChecker<r_8>;
409#endif
Note: See TracBrowser for help on using the repository browser.