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

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

on enleve TransfEnergyFFT,SizeFFT obsolete cmv 25/5/04

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