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

Last change on this file since 2650 was 2615, checked in by cmv, 21 years ago

using namespace sophya enleve de machdefs.h, nouveau sopnamsp.h cmv 10/09/2004

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