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