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

Last change on this file since 3235 was 3235, checked in by ansari, 18 years ago

suppression include sopnamsp.h et mis la declaration namespace SOPHYA ds les fichiers .cc de NTools, quand DECL_TEMP_SPEC ds le fichier , cmv+reza 27/04/2007

File size: 15.1 KB
Line 
1#include "fftservintf.h"
2
3namespace SOPHYA {
4
5//// VOIR GRAND BLABLA EXPLICATIF A LA FIN DU FICHIER
6
7/*!
8 \class FFTServerInterface
9 \ingroup NTools
10 Defines the interface for FFT (Fast Fourier Transform) operations.
11 Definitions :
12 - Sampling period \b T
13 - Sampling frequency \b fs=1/T
14 - Total number of samples \b N
15 - Frequency step in Fourier space \b =fs/N=1/(N*T)
16 - Component frequencies
17 - k=0 -> 0
18 - k=1 -> 1/(N*T)
19 - k -> k/(N*T)
20 - k=N/2 -> 1/(2*T) (Nyquist frequency)
21 - k>N/2 -> k/(N*T) (or negative frequency -(N-k)/(N*T))
22
23 For a sampling period T=1, the computed Fourier components correspond to :
24 \verbatim
25 0 1/N 2/N ... 1/2 1/2+1/N 1/2+2/N ... 1-2/N 1-1/N
26 0 1/N 2/N ... 1/2 ... -2/N -1/N
27 \endverbatim
28
29 For complex one-dimensional transforms:
30 \f[
31 out(i) = F_{norm} \Sigma_{j} \ e^{-2 \pi \sqrt{-1} \ i \ j} \ {\rm (forward)}
32 \f]
33 \f[
34 out(i) = F_{norm} \Sigma_{j} \ e^{2 \pi \sqrt{-1} \ i \ j} \ {\rm (backward)}
35 \f]
36 i,j= 0..N-1 , where N is the input or the output array size.
37
38 For complex multi-dimensional transforms:
39 \f[
40 out(i1,i2,...,id) = F_{norm} \Sigma_{j1} \Sigma_{j2} ... \Sigma_{jd} \
41 e^{-2 \pi \sqrt{-1} \ i1 \ j1} ... e^{-2 \pi \sqrt{-1} \ id \ jd} \ {\rm (forward)}
42 \f]
43 \f[
44 out(i1,i2,...,id) = F_{norm} \Sigma_{j1} \Sigma_{j2} ... \Sigma_{jd} \
45 e^{2 \pi \sqrt{-1} \ i1 \ j1} ... e^{2 \pi \sqrt{-1} \ id \ jd} \ {\rm (backward)}
46 \f]
47
48 For real forward transforms, the input array is real, and
49 the output array complex, with Fourier components up to k=N/2.
50 For real backward transforms, the input array is complex and
51 the output array is real.
52*/
53
54/* --Methode-- */
55FFTServerInterface::FFTServerInterface(string info)
56{
57 _info = info;
58 _fgnorm = true;
59}
60
61/* --Methode-- */
62FFTServerInterface::~FFTServerInterface()
63{
64}
65
66// ----------------- Transforme pour les double -------------------
67
68/* --Methode-- */
69//! Forward Fourier transform for double precision complex data
70/*!
71 \param in : Input complex array
72 \param out : Output complex array
73 */
74void FFTServerInterface::FFTForward(TArray< complex<r_8> > &, TArray< complex<r_8> > &)
75{
76 throw NotAvailableOperation("FFTServer::FFTForward(TArray...) Unsupported operation !");
77}
78
79/* --Methode-- */
80//! Backward (inverse) Fourier transform for double precision complex data
81/*!
82 \param in : Input complex array
83 \param out : Output complex array
84 */
85void FFTServerInterface::FFTBackward(TArray< complex<r_8> > &, TArray< complex<r_8> > &)
86{
87 throw NotAvailableOperation("FFTServer::FFTBackward(TArray...) Unsupported operation !");
88}
89
90/* --Methode-- */
91//! Forward Fourier transform for double precision real input data
92/*!
93 \param in : Input real array
94 \param out : Output complex array
95 */
96void FFTServerInterface::FFTForward(TArray< r_8 > &, TArray< complex<r_8> > &)
97{
98 throw NotAvailableOperation("FFTServer::FFTForward(TArray...) Unsupported operation !");
99}
100
101/* --Methode-- */
102//! Backward (inverse) Fourier transform for double precision real output data
103/*!
104 \param in : Input complex array
105 \param out : Output real array
106 \param usoutsz : if true, use the output array size for computing the inverse FFT.
107
108 In all cases, the input/output array sizes compatibility is checked.
109 if usoutsz == false, the size of the real array is selected based on the
110 the imaginary part of the input complex array at the nyquist frequency.
111 size_out_real = 2*size_in_complex - ( 1 or 2)
112 */
113void FFTServerInterface::FFTBackward(TArray< complex<r_8> > &, TArray< r_8 > &, bool)
114{
115 throw NotAvailableOperation("FFTServer::FFTBackward(TArray...) Unsupported operation !");
116}
117
118
119// ----------------- Transforme pour les float -------------------
120
121/* --Methode-- */
122//! Forward Fourier transform for complex data
123/*!
124 \param in : Input complex array
125 \param out : Output complex array
126 */
127void FFTServerInterface::FFTForward(TArray< complex<r_4> > &, TArray< complex<r_4> > &)
128{
129 throw NotAvailableOperation("FFTServer::FFTForward(TArray r_4 ... ) Unsupported operation !");
130}
131
132/* --Methode-- */
133//! Backward (inverse) Fourier transform for complex data
134/*!
135 \param in : Input complex array
136 \param out : Output complex array
137 */
138void FFTServerInterface::FFTBackward(TArray< complex<r_4> > &, TArray< complex<r_4> > &)
139{
140 throw NotAvailableOperation("FFTServer::FFTBackward(TArray r_4 ... ) Unsupported operation !");
141}
142
143/* --Methode-- */
144//! Forward Fourier transform for real input data
145/*!
146 \param in : Input real array
147 \param out : Output complex array
148 */
149void FFTServerInterface::FFTForward(TArray< r_4 > &, TArray< complex<r_4> > &)
150{
151 throw NotAvailableOperation("FFTServer::FFTForward(TArray r_4 ... ) Unsupported operation !");
152}
153
154/* --Methode-- */
155//! Backward (inverse) Fourier transform for real output data
156/*!
157 \param in : Input complex array
158 \param out : Output real array
159 \param usoutsz : if true, use the output array size for computing the inverse FFT.
160
161 In all cases, the input/output array sizes compatibility is checked.
162 if usoutsz == false, the size of the real array is selected based on the
163 the imaginary part of the input complex array at the nyquist frequency.
164 size_out_real = 2*size_in_complex - ( 1 or 2)
165*/
166void FFTServerInterface::FFTBackward(TArray< complex<r_4> > &, TArray< r_4 > &, bool)
167{
168 throw NotAvailableOperation("FFTServer::FFTBackward(TArray r_4 ... ) Unsupported operation !");
169}
170
171/* --Methode-- */
172/*!
173 \class FFTArrayChecker
174 \ingroup NTools
175 Service class for checking array size and resizing output arrays,
176 to be used by FFTServer classes
177*/
178
179template <class T>
180FFTArrayChecker<T>::FFTArrayChecker(string msg, bool checkpack, bool onedonly)
181{
182 _msg = msg + " FFTArrayChecker::";
183 _checkpack = checkpack;
184 _onedonly = onedonly;
185}
186
187/* --Methode-- */
188template <class T>
189FFTArrayChecker<T>::~FFTArrayChecker()
190{
191}
192
193template <class T>
194T FFTArrayChecker<T>::ZeroThreshold()
195{
196 return(0);
197}
198
199DECL_TEMP_SPEC /* equivalent a template <> , pour SGI-CC en particulier */
200r_8 FFTArrayChecker< r_8 >::ZeroThreshold()
201{
202 return(1.e-39);
203}
204
205DECL_TEMP_SPEC /* equivalent a template <> , pour SGI-CC en particulier */
206r_4 FFTArrayChecker< r_4 >::ZeroThreshold()
207{
208 return(1.e-19);
209}
210
211/* --Methode-- */
212template <class T>
213int FFTArrayChecker<T>::CheckResize(TArray< complex<T> > const & in, TArray< complex<T> > & out)
214{
215 int k;
216 string msg;
217 if (in.Size() < 1) {
218 msg = _msg + "CheckResize(complex in, complex out) - Unallocated input array !";
219 throw(SzMismatchError(msg));
220 }
221 if (_checkpack)
222 if ( !in.IsPacked() ) {
223 msg = _msg + "CheckResize(complex in, complex out) - Not packed input array !";
224 throw(SzMismatchError(msg));
225 }
226 int ndg1 = 0;
227 for(k=0; k<in.NbDimensions(); k++)
228 if (in.Size(k) > 1) ndg1++;
229 if (_onedonly)
230 if (ndg1 > 1) {
231 msg = _msg + "CheckResize(complex in, complex out) - Only 1-D array accepted !";
232 throw(SzMismatchError(msg));
233 }
234 out.ReSize(in);
235 // sa_size_t sz[BASEARRAY_MAXNDIMS];
236 // for(k=0; k<in.NbDimensions(); k++)
237 // sz[k] = in.Size(k);
238 // out.ReSize(in.NbDimensions(), sz);
239
240 return(ndg1);
241}
242
243/* --Methode-- */
244template <class T>
245int FFTArrayChecker<T>::CheckResize(TArray< T > const & in, TArray< complex<T> > & out)
246{
247 int k;
248 string msg;
249 if (in.Size() < 1) {
250 msg = _msg + "CheckResize(real in, complex out) - Unallocated input array !";
251 throw(SzMismatchError(msg));
252 }
253 if (_checkpack)
254 if ( !in.IsPacked() ) {
255 msg = _msg + "CheckResize(real in, complex out) - Not packed input array !";
256 throw(SzMismatchError(msg));
257 }
258 int ndg1 = 0;
259 for(k=0; k<in.NbDimensions(); k++)
260 if (in.Size(k) > 1) ndg1++;
261 if (_onedonly)
262 if (ndg1 > 1) {
263 msg = _msg + "CheckResize(real in, complex out) - Only 1-D array accepted !";
264 throw(SzMismatchError(msg));
265 }
266 sa_size_t sz[BASEARRAY_MAXNDIMS];
267 //
268 if (ndg1 > 1) {
269 sz[0] = in.Size(0)/2+1;
270 for(k=1; k<in.NbDimensions(); k++)
271 sz[k] = in.Size(k);
272 }
273 else {
274 for(k=0; k<BASEARRAY_MAXNDIMS; k++) sz[k] = 1;
275 sz[in.MaxSizeKA()] = in.Size(in.MaxSizeKA())/2+1;
276 // sz[k] = in.Size(k)/2+1;
277 // sz[k] = (in.Size(k)%2 != 0) ? in.Size(k)/2+1 : in.Size(k)/2;
278 }
279 out.ReSize(in.NbDimensions(), sz);
280
281 return(ndg1);
282}
283
284/* --Methode-- */
285template <class T>
286int FFTArrayChecker<T>::CheckResize(TArray< complex<T> > const & in, TArray< T > & out,
287 bool usoutsz)
288{
289 int k;
290 string msg;
291 if (in.Size() < 1) {
292 msg = _msg + "CheckResize(complex in, real out) - Unallocated input array !";
293 throw(SzMismatchError(msg));
294 }
295 if (_checkpack)
296 if ( !in.IsPacked() ) {
297 msg = _msg + "CheckResize(complex in, real out) - Not packed input array !";
298 throw(SzMismatchError(msg));
299 }
300 int ndg1 = 0;
301 for(k=0; k<in.NbDimensions(); k++)
302 if (in.Size(k) > 1) ndg1++;
303 if (_onedonly)
304 if (ndg1 > 1) {
305 msg = _msg + "CheckResize(complex in, real out) - Only 1-D array accepted !";
306 throw(SzMismatchError(msg));
307 }
308 if (usoutsz) { // We have to use output array size
309 bool fgerr = false;
310 if (ndg1 > 1) {
311 if (in.Size(0) != out.Size(0)/2+1) fgerr = true;
312 }
313 else {
314 if (in.Size(in.MaxSizeKA()) != out.Size(in.MaxSizeKA())/2+1) fgerr = true;
315 }
316 if (fgerr) {
317 msg = _msg + "CheckResize(complex in, real out) - Incompatible in-out sizes !";
318 throw(SzMismatchError(msg));
319 }
320 }
321 else { // We have to resize the output array
322 sa_size_t sz[BASEARRAY_MAXNDIMS];
323 if (ndg1 > 1) {
324 sz[0] = 2*in.Size(0)-1;
325 for(k=1; k<in.NbDimensions(); k++)
326 sz[k] = in.Size(k);
327 // sz[k] = in.Size(k)*2-1;
328 }
329 else {
330 for(k=0; k<BASEARRAY_MAXNDIMS; k++) sz[k] = 1;
331 T thr = ZeroThreshold();
332 sa_size_t n = in.Size(in.MaxSizeKA());
333 sa_size_t ncs = ( (in[n-1].imag() < -thr) || (in[n-1].imag() > thr) )
334 ? 2*n-1 : 2*n-2;
335 sz[in.MaxSizeKA()] = ncs;
336 }
337 out.ReSize(in.NbDimensions(), sz);
338 }
339
340 return(ndg1);
341
342}
343
344
345#ifdef __CXX_PRAGMA_TEMPLATES__
346#pragma define_template FFTArrayChecker<r_4>
347#pragma define_template FFTArrayChecker<r_8>
348#endif
349
350#if defined(ANSI_TEMPLATES) || defined(GNU_TEMPLATES)
351template class FFTArrayChecker<r_4>;
352template class FFTArrayChecker<r_8>;
353#endif
354
355} // FIN namespace SOPHYA
356
357
358
359/**********************************************************************
360
361Memo uniquement destine aux programmeurs: (cmv 03/05/04)
362-- cf programme de tests explicatif: cmvtfft.cc
363
364=====================================================================
365=====================================================================
366============== Transformees de Fourier et setNormalize ==============
367=====================================================================
368=====================================================================
369
370- si setNormalize(true): invTF{TF{S}} = S
371- si setNormalize(false): invTF{TF{S}} = N * S
372
373=====================================================================
374=====================================================================
375============== Transformees de Fourier de signaux REELS =============
376=====================================================================
377=====================================================================
378
379-------
380--- FFT d'un signal REEL S ayant un nombre pair d'elements N=2p
381-------
382 taille de la FFT: Nfft = N/2 + 1 = p + 1
383 abscisses de la fft: | 0 | 1/N | 2/N | ..... | p/N=1/2 |
384 ^continu ^frequence de Nyquist
385
386 ... Ex: N=6 -> Nfft = 6/3+1 = 4
387
388 le signal a N elements reels, la fft a Nfft elements complexes
389 cad 2*Nfft reels = 2*(p+1) reels = 2p + 2 reels = N + 2 reels
390 soit 2 reels en trop:
391 ce sont les phases du continu et de la frequence de Nyquist
392
393 relations:
394 - si setNormalize(true) : fac = N
395 setNormalize(false) : fac = 1/N
396 sum(i=0,N-1){S(i)^2}
397 = fac* [[ 2* sum(j=0,Nfft-1){|TF{S}(j)|^2}
398 - |TF{S}(0)|^2 - |TF{S}(Nfft-1)|^2 ]]
399 (On ne compte pas deux fois le continu et la freq de Nyquist)
400
401
402-------
403--- FFT d'un signal REEL ayant un nombre impair d'elements N=2p+1
404-------
405 taille de la FFT: Nfft = N/2 + 1 = p + 1
406 abscisses de la fft: | 0 | 1/N | 2/N | ..... | p/N |
407 ^continu
408 (la frequence de Nyquist n'y est pas)
409
410 ... Ex: N=7 -> Nfft = 7/3+1 = 4
411
412 le signal a N elements reels, la fft a Nfft elements complexes
413 cad 2*Nfft reels = 2*(p+1) reels = 2p + 2 reels = N + 1 reels
414 soit 1 reel en trop: c'est la phase du continu
415
416 relations:
417 - si setNormalize(true) : fac = N
418 setNormalize(false) : fac = 1/N
419 sum(i=0,N-1){S(i)^2}
420 = fac* [[ 2* sum(j=0,Nfft-1){|TF{S}(j)|^2}
421 - |TF{S}(0)|^2 ]]
422 (On ne compte pas deux fois le continu)
423
424
425------------
426--- FFT-BACK d'un signal F=TF{S} ayant un nombre d'elements Nfft
427------------
428 Sback = invTF{TF{S}}
429
430 Remarque: Nfft a la meme valeur pour N=2p et N=2p+1
431 donc Nfft conduit a 2 possibilites:
432 { N = 2*(Nfft-1) signal back avec nombre pair d'elements
433 { N = 2*Nfft-1 signal back avec nombre impair d'elements
434
435 Pour savoir quel est la longueur N du signal TF^(-1){F} on regarde
436 si F(Nfft-1) est reel ou complexe
437 (la frequence de Nyquist d'un signal reel est reelle)
438
439 - Si F(Nfft-1) reel cad Im{F(Nfft-1)}=0: N = 2*(Nfft-1)
440 - Si F(Nfft-1) complexe cad Im{F(Nfft-1)}#0: N = 2*Nfft-1
441
442 Si setNormalize(true): invTF{TF{S}} = S
443 setNormalize(false): invTF{TF{S}} = N * S
444
445=========================================================================
446=========================================================================
447============== Transformees de Fourier de signaux COMPLEXES =============
448=========================================================================
449=========================================================================
450
451-------
452--- FFT d'un signal COMPLEXE S ayant un nombre d'elements N
453-------
454 taille de la FFT: Nfft = N
455 abscisses de la fft: | 0 | 1/N | 2/N | ..... | (N-1)/N |
456 ^continu
457
458 Frequence de Nyquist:
459 si N est pair: la frequence de Nyquist est l'absicce d'un des bins
460 abscisses de TF{S}: Nfft = N = 2p
461 | 0 | 1/N | 2/N | ... | (N/2)/N=p/N=0.5 | ... | (N-1)/N |
462 ^frequence de Nyquist
463 si N est impair: la frequence de Nyquist N'est PAS l'absicce d'un des bins
464 abscisses de TF{S}: Nfft = N = 2p+1
465 | 0 | 1/N | 2/N | ... | (N/2)/N=p/N | ((N+1)/2)/N=(p+1)/N | ... | (N-1)/N |
466
467 ... Ex: N = 2p =6 -> Nfft = 2p = 6
468 abscisses de TF{S}: | 0 | 1/6 | 2/6 | 3/6=0.5 | 4/6 | 5/6 |
469 ... Ex: N = 2p+1 = 7 -> Nfft = 2p+1 = 7
470 abscisses de TF{S}: | 0 | 1/7 | 2/7 | 3/7 | 4/7 | 5/7 | 6/7 |
471
472 relations:
473 - si setNormalize(true) : fac = N
474 setNormalize(false) : fac = 1/N
475 sum(i=0,N-1){S(i)^2} = fac* [[ sum(j=0,Nfft-1){|TF{S}(j)|^2} ]]
476
477------------
478--- FFT-BACK d'un signal F=TF{S} ayant un nombre d'elements Nfft
479------------
480 taille du signal: N = Nfft
481
482 Si setNormalize(true): invTF{TF{S}} = S
483 setNormalize(false): invTF{TF{S}} = N * S
484
485**********************************************************************/
Note: See TracBrowser for help on using the repository browser.