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

Last change on this file since 3083 was 3002, checked in by ansari, 19 years ago

Suppression const des arguments FFTForward/Backward + adaptation de Toeplitz, cmv+Reza 03/07/2006

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