OSSIM - Open Source Software Image Map  Version 1.9.0 (20180803)
fft.cpp
Go to the documentation of this file.
1 //$$ fft.cpp Fast fourier transform
2 
3 // Copyright (C) 1991,2,3,4,8: R B Davies
4 
5 
6 #define WANT_MATH
7 // #define WANT_STREAM
8 
9 #include <cmath>
10 #include <ossim/matrix/include.h>
11 
12 #include <ossim/matrix/newmatap.h>
13 
14 #include <ossim/matrix/newmatio.h>
15 
16 #ifdef use_namespace
17 namespace NEWMAT {
18 #endif
19 
20 #ifdef DO_REPORT
21 #define REPORT { static ExeCounter ExeCount(__LINE__,19); ++ExeCount; }
22 #else
23 #define REPORT {}
24 #endif
25 
26 static void cossin(int n, int d, Real& c, Real& s)
27 // calculate cos(twopi*n/d) and sin(twopi*n/d)
28 // minimise roundoff error
29 {
30  REPORT
31  long n4 = n * 4; int sector = (int)std::floor( (Real)n4 / (Real)d + 0.5 );
32  n4 -= sector * d;
33  if (sector < 0) { REPORT sector = 3 - (3 - sector) % 4; }
34  else { REPORT sector %= 4; }
35  Real ratio = 1.5707963267948966192 * (Real)n4 / (Real)d;
36 
37  switch (sector)
38  {
39  case 0: REPORT c = cos(ratio); s = sin(ratio); break;
40  case 1: REPORT c = -sin(ratio); s = cos(ratio); break;
41  case 2: REPORT c = -cos(ratio); s = -sin(ratio); break;
42  case 3: REPORT c = sin(ratio); s = -cos(ratio); break;
43  }
44 }
45 
46 static void fftstep(ColumnVector& A, ColumnVector& B, ColumnVector& X,
47  ColumnVector& Y, int after, int now, int before)
48 {
49  REPORT
50  Tracer trace("FFT(step)");
51  // const Real twopi = 6.2831853071795864769;
52  const int gamma = after * before; const int delta = now * after;
53  // const Real angle = twopi / delta; Real temp;
54  // Real r_omega = cos(angle); Real i_omega = -sin(angle);
55  Real r_arg = 1.0; Real i_arg = 0.0;
56  Real* x = X.Store(); Real* y = Y.Store(); // pointers to array storage
57  const int m = A.Nrows() - gamma;
58 
59  for (int j = 0; j < now; j++)
60  {
61  Real* a = A.Store(); Real* b = B.Store(); // pointers to array storage
62  Real* x1 = x; Real* y1 = y; x += after; y += after;
63  for (int ia = 0; ia < after; ia++)
64  {
65  // generate sins & cosines explicitly rather than iteratively
66  // for more accuracy; but slower
67  cossin(-(j*after+ia), delta, r_arg, i_arg);
68 
69  Real* a1 = a++; Real* b1 = b++; Real* x2 = x1++; Real* y2 = y1++;
70  if (now==2)
71  {
72  REPORT int ib = before;
73  if (ib) for (;;)
74  {
75  REPORT
76  Real* a2 = m + a1; Real* b2 = m + b1; a1 += after; b1 += after;
77  Real r_value = *a2; Real i_value = *b2;
78  *x2 = r_value * r_arg - i_value * i_arg + *(a2-gamma);
79  *y2 = r_value * i_arg + i_value * r_arg + *(b2-gamma);
80  if (!(--ib)) break;
81  x2 += delta; y2 += delta;
82  }
83  }
84  else
85  {
86  REPORT int ib = before;
87  if (ib) for (;;)
88  {
89  REPORT
90  Real* a2 = m + a1; Real* b2 = m + b1; a1 += after; b1 += after;
91  Real r_value = *a2; Real i_value = *b2;
92  int in = now-1; while (in--)
93  {
94  // it should be possible to make this faster
95  // hand code for now = 2,3,4,5,8
96  // use symmetry to halve number of operations
97  a2 -= gamma; b2 -= gamma; Real temp = r_value;
98  r_value = r_value * r_arg - i_value * i_arg + *a2;
99  i_value = temp * i_arg + i_value * r_arg + *b2;
100  }
101  *x2 = r_value; *y2 = i_value;
102  if (!(--ib)) break;
103  x2 += delta; y2 += delta;
104  }
105  }
106 
107  // temp = r_arg;
108  // r_arg = r_arg * r_omega - i_arg * i_omega;
109  // i_arg = temp * i_omega + i_arg * r_omega;
110 
111  }
112  }
113 }
114 
115 
116 void FFTI(const ColumnVector& U, const ColumnVector& V,
117  ColumnVector& X, ColumnVector& Y)
118 {
119  // Inverse transform
120  Tracer trace("FFTI");
121  REPORT
122  FFT(U,-V,X,Y);
123  const Real n = X.Nrows(); X /= n; Y /= (-n);
124 }
125 
127 {
128  // Fourier transform of a real series
129  Tracer trace("RealFFT");
130  REPORT
131  const int n = U.Nrows(); // length of arrays
132  const int n2 = n / 2;
133  if (n != 2 * n2)
134  Throw(ProgramException("Vector length not multiple of 2", U));
135  ColumnVector A(n2), B(n2);
136  Real* a = A.Store(); Real* b = B.Store(); Real* u = U.Store(); int i = n2;
137  while (i--) { *a++ = *u++; *b++ = *u++; }
138  FFT(A,B,A,B);
139  int n21 = n2 + 1;
140  X.ReSize(n21); Y.ReSize(n21);
141  i = n2 - 1;
142  a = A.Store(); b = B.Store(); // first els of A and B
143  Real* an = a + i; Real* bn = b + i; // last els of A and B
144  Real* x = X.Store(); Real* y = Y.Store(); // first els of X and Y
145  Real* xn = x + n2; Real* yn = y + n2; // last els of X and Y
146 
147  *x++ = *a + *b; *y++ = 0.0; // first complex element
148  *xn-- = *a++ - *b++; *yn-- = 0.0; // last complex element
149 
150  int j = -1; i = n2/2;
151  while (i--)
152  {
153  Real c,s; cossin(j--,n,c,s);
154  Real am = *a - *an; Real ap = *a++ + *an--;
155  Real bm = *b - *bn; Real bp = *b++ + *bn--;
156  Real samcbp = s * am + c * bp; Real sbpcam = s * bp - c * am;
157  *x++ = 0.5 * ( ap + samcbp); *y++ = 0.5 * ( bm + sbpcam);
158  *xn-- = 0.5 * ( ap - samcbp); *yn-- = 0.5 * (-bm + sbpcam);
159  }
160 }
161 
162 void RealFFTI(const ColumnVector& A, const ColumnVector& B, ColumnVector& U)
163 {
164  // inverse of a Fourier transform of a real series
165  Tracer trace("RealFFTI");
166  REPORT
167  const int n21 = A.Nrows(); // length of arrays
168  if (n21 != B.Nrows() || n21 == 0)
169  Throw(ProgramException("Vector lengths unequal or zero", A, B));
170  const int n2 = n21 - 1; const int n = 2 * n2; int i = n2 - 1;
171 
172  ColumnVector X(n2), Y(n2);
173  Real* a = A.Store(); Real* b = B.Store(); // first els of A and B
174  Real* an = a + n2; Real* bn = b + n2; // last els of A and B
175  Real* x = X.Store(); Real* y = Y.Store(); // first els of X and Y
176  Real* xn = x + i; Real* yn = y + i; // last els of X and Y
177 
178  Real hn = 0.5 / n2;
179  *x++ = hn * (*a + *an); *y++ = - hn * (*a - *an);
180  a++; an--; b++; bn--;
181  int j = -1; i = n2/2;
182  while (i--)
183  {
184  Real c,s; cossin(j--,n,c,s);
185  Real am = *a - *an; Real ap = *a++ + *an--;
186  Real bm = *b - *bn; Real bp = *b++ + *bn--;
187  Real samcbp = s * am - c * bp; Real sbpcam = s * bp + c * am;
188  *x++ = hn * ( ap + samcbp); *y++ = - hn * ( bm + sbpcam);
189  *xn-- = hn * ( ap - samcbp); *yn-- = - hn * (-bm + sbpcam);
190  }
191  FFT(X,Y,X,Y); // have done inverting elsewhere
192  U.ReSize(n); i = n2;
193  x = X.Store(); y = Y.Store(); Real* u = U.Store();
194  while (i--) { *u++ = *x++; *u++ = - *y++; }
195 }
196 
197 void FFT(const ColumnVector& U, const ColumnVector& V,
198  ColumnVector& X, ColumnVector& Y)
199 {
200  // from Carl de Boor (1980), Siam J Sci Stat Comput, 1 173-8
201  // but first try Sande and Gentleman
202  Tracer trace("FFT");
203  REPORT
204  const int n = U.Nrows(); // length of arrays
205  if (n != V.Nrows() || n == 0)
206  Throw(ProgramException("Vector lengths unequal or zero", U, V));
207  if (n == 1) { REPORT X = U; Y = V; return; }
208 
209  // see if we can use the newfft routine
211  {
212  REPORT
213  X = U; Y = V;
214  if ( FFT_Controller::ar_1d_ft(n,X.Store(),Y.Store()) ) return;
215  }
216 
217  ColumnVector B = V;
218  ColumnVector A = U;
219  X.ReSize(n); Y.ReSize(n);
220  const int nextmx = 8;
221  int prime[8] = { 2,3,5,7,11,13,17,19 };
222  int after = 1; int before = n; int next = 0; bool inzee = true;
223  int now = 0; int b1; // initialised to keep gnu happy
224 
225  do
226  {
227  for (;;)
228  {
229  if (next < nextmx) { REPORT now = prime[next]; }
230  b1 = before / now; if (b1 * now == before) { REPORT break; }
231  next++; now += 2;
232  }
233  before = b1;
234 
235  if (inzee) { REPORT fftstep(A, B, X, Y, after, now, before); }
236  else { REPORT fftstep(X, Y, A, B, after, now, before); }
237 
238  inzee = !inzee; after *= now;
239  }
240  while (before != 1);
241 
242  if (inzee) { REPORT A.Release(); X = A; B.Release(); Y = B; }
243 }
244 
245 // Trigonometric transforms
246 // see Charles Van Loan (1992) "Computational frameworks for the fast
247 // Fourier transform" published by SIAM; section 4.4.
248 
249 void DCT_II(const ColumnVector& U, ColumnVector& V)
250 {
251  // Discrete cosine transform, type II, of a real series
252  Tracer trace("DCT_II");
253  REPORT
254  const int n = U.Nrows(); // length of arrays
255  const int n2 = n / 2; const int n4 = n * 4;
256  if (n != 2 * n2)
257  Throw(ProgramException("Vector length not multiple of 2", U));
258  ColumnVector A(n);
259  Real* a = A.Store(); Real* b = a + n; Real* u = U.Store();
260  int i = n2;
261  while (i--) { *a++ = *u++; *(--b) = *u++; }
262  ColumnVector X, Y;
263  RealFFT(A, X, Y); A.CleanUp();
264  V.ReSize(n);
265  Real* x = X.Store(); Real* y = Y.Store();
266  Real* v = V.Store(); Real* w = v + n;
267  *v = *x;
268  int k = 0; i = n2;
269  while (i--)
270  {
271  Real c, s; cossin(++k, n4, c, s);
272  Real xi = *(++x); Real yi = *(++y);
273  *(++v) = xi * c + yi * s; *(--w) = xi * s - yi * c;
274  }
275 }
276 
278 {
279  // Inverse of discrete cosine transform, type II
280  Tracer trace("DCT_II_inverse");
281  REPORT
282  const int n = V.Nrows(); // length of array
283  const int n2 = n / 2; const int n4 = n * 4; const int n21 = n2 + 1;
284  if (n != 2 * n2)
285  Throw(ProgramException("Vector length not multiple of 2", V));
286  ColumnVector X(n21), Y(n21);
287  Real* x = X.Store(); Real* y = Y.Store();
288  Real* v = V.Store(); Real* w = v + n;
289  *x = *v; *y = 0.0;
290  int i = n2; int k = 0;
291  while (i--)
292  {
293  Real c, s; cossin(++k, n4, c, s);
294  Real vi = *(++v); Real wi = *(--w);
295  *(++x) = vi * c + wi * s; *(++y) = vi * s - wi * c;
296  }
297  ColumnVector A; RealFFTI(X, Y, A);
298  X.CleanUp(); Y.CleanUp(); U.ReSize(n);
299  Real* a = A.Store(); Real* b = a + n; Real* u = U.Store();
300  i = n2;
301  while (i--) { *u++ = *a++; *u++ = *(--b); }
302 }
303 
304 void DST_II(const ColumnVector& U, ColumnVector& V)
305 {
306  // Discrete sine transform, type II, of a real series
307  Tracer trace("DST_II");
308  REPORT
309  const int n = U.Nrows(); // length of arrays
310  const int n2 = n / 2; const int n4 = n * 4;
311  if (n != 2 * n2)
312  Throw(ProgramException("Vector length not multiple of 2", U));
313  ColumnVector A(n);
314  Real* a = A.Store(); Real* b = a + n; Real* u = U.Store();
315  int i = n2;
316  while (i--) { *a++ = *u++; *(--b) = -(*u++); }
317  ColumnVector X, Y;
318  RealFFT(A, X, Y); A.CleanUp();
319  V.ReSize(n);
320  Real* x = X.Store(); Real* y = Y.Store();
321  Real* v = V.Store(); Real* w = v + n;
322  *(--w) = *x;
323  int k = 0; i = n2;
324  while (i--)
325  {
326  Real c, s; cossin(++k, n4, c, s);
327  Real xi = *(++x); Real yi = *(++y);
328  *v++ = xi * s - yi * c; *(--w) = xi * c + yi * s;
329  }
330 }
331 
333 {
334  // Inverse of discrete sine transform, type II
335  Tracer trace("DST_II_inverse");
336  REPORT
337  const int n = V.Nrows(); // length of array
338  const int n2 = n / 2; const int n4 = n * 4; const int n21 = n2 + 1;
339  if (n != 2 * n2)
340  Throw(ProgramException("Vector length not multiple of 2", V));
341  ColumnVector X(n21), Y(n21);
342  Real* x = X.Store(); Real* y = Y.Store();
343  Real* v = V.Store(); Real* w = v + n;
344  *x = *(--w); *y = 0.0;
345  int i = n2; int k = 0;
346  while (i--)
347  {
348  Real c, s; cossin(++k, n4, c, s);
349  Real vi = *v++; Real wi = *(--w);
350  *(++x) = vi * s + wi * c; *(++y) = - vi * c + wi * s;
351  }
352  ColumnVector A; RealFFTI(X, Y, A);
353  X.CleanUp(); Y.CleanUp(); U.ReSize(n);
354  Real* a = A.Store(); Real* b = a + n; Real* u = U.Store();
355  i = n2;
356  while (i--) { *u++ = *a++; *u++ = -(*(--b)); }
357 }
358 
360 {
361  // Inverse of discrete cosine transform, type I
362  Tracer trace("DCT_inverse");
363  REPORT
364  const int n = V.Nrows()-1; // length of transform
365  const int n2 = n / 2; const int n21 = n2 + 1;
366  if (n != 2 * n2)
367  Throw(ProgramException("Vector length not multiple of 2", V));
368  ColumnVector X(n21), Y(n21);
369  Real* x = X.Store(); Real* y = Y.Store(); Real* v = V.Store();
370  Real vi = *v++; *x++ = vi; *y++ = 0.0;
371  Real sum1 = vi / 2.0; Real sum2 = sum1; vi = *v++;
372  int i = n2-1;
373  while (i--)
374  {
375  Real vi2 = *v++; sum1 += vi2 + vi; sum2 += vi2 - vi;
376  *x++ = vi2; vi2 = *v++; *y++ = vi - vi2; vi = vi2;
377  }
378  sum1 += vi; sum2 -= vi;
379  vi = *v; *x = vi; *y = 0.0; vi /= 2.0; sum1 += vi; sum2 += vi;
380  ColumnVector A; RealFFTI(X, Y, A);
381  X.CleanUp(); Y.CleanUp(); U.ReSize(n+1);
382  Real* a = A.Store(); Real* b = a + n; Real* u = U.Store(); v = u + n;
383  i = n2; int k = 0; *u++ = sum1 / n2; *v-- = sum2 / n2;
384  while (i--)
385  {
386  Real s = sin(1.5707963267948966192 * (++k) / n2);
387  Real ai = *(++a); Real bi = *(--b);
388  Real bz = (ai - bi) / 4 / s; Real az = (ai + bi) / 2;
389  *u++ = az - bz; *v-- = az + bz;
390  }
391 }
392 
393 void DCT(const ColumnVector& U, ColumnVector& V)
394 {
395  // Discrete cosine transform, type I
396  Tracer trace("DCT");
397  REPORT
398  DCT_inverse(U, V);
399  V *= (V.Nrows()-1)/2;
400 }
401 
403 {
404  // Inverse of discrete sine transform, type I
405  Tracer trace("DST_inverse");
406  REPORT
407  const int n = V.Nrows()-1; // length of transform
408  const int n2 = n / 2; const int n21 = n2 + 1;
409  if (n != 2 * n2)
410  Throw(ProgramException("Vector length not multiple of 2", V));
411  ColumnVector X(n21), Y(n21);
412  Real* x = X.Store(); Real* y = Y.Store(); Real* v = V.Store();
413  Real vi = *(++v); *x++ = 2 * vi; *y++ = 0.0;
414  int i = n2-1;
415  while (i--) { *y++ = *(++v); Real vi2 = *(++v); *x++ = vi2 - vi; vi = vi2; }
416  *x = -2 * vi; *y = 0.0;
417  ColumnVector A; RealFFTI(X, Y, A);
418  X.CleanUp(); Y.CleanUp(); U.ReSize(n+1);
419  Real* a = A.Store(); Real* b = a + n; Real* u = U.Store(); v = u + n;
420  i = n2; int k = 0; *u++ = 0.0; *v-- = 0.0;
421  while (i--)
422  {
423  Real s = sin(1.5707963267948966192 * (++k) / n2);
424  Real ai = *(++a); Real bi = *(--b);
425  Real az = (ai + bi) / 4 / s; Real bz = (ai - bi) / 2;
426  *u++ = az - bz; *v-- = az + bz;
427  }
428 }
429 
430 void DST(const ColumnVector& U, ColumnVector& V)
431 {
432  // Discrete sine transform, type I
433  Tracer trace("DST");
434  REPORT
435  DST_inverse(U, V);
436  V *= (V.Nrows()-1)/2;
437 }
438 
439 // Two dimensional FFT
440 void FFT2(const Matrix& U, const Matrix& V, Matrix& X, Matrix& Y)
441 {
442  Tracer trace("FFT2");
443  REPORT
444  int m = U.Nrows(); int n = U.Ncols();
445  if (m != V.Nrows() || n != V.Ncols() || m == 0 || n == 0)
446  Throw(ProgramException("Matrix dimensions unequal or zero", U, V));
447  X = U; Y = V;
448  int i; ColumnVector CVR; ColumnVector CVI;
449  for (i = 1; i <= m; ++i)
450  {
451  FFT(X.Row(i).t(), Y.Row(i).t(), CVR, CVI);
452  X.Row(i) = CVR.t(); Y.Row(i) = CVI.t();
453  }
454  for (i = 1; i <= n; ++i)
455  {
456  FFT(X.Column(i), Y.Column(i), CVR, CVI);
457  X.Column(i) = CVR; Y.Column(i) = CVI;
458  }
459 }
460 
461 void FFT2I(const Matrix& U, const Matrix& V, Matrix& X, Matrix& Y)
462 {
463  // Inverse transform
464  Tracer trace("FFT2I");
465  REPORT
466  FFT2(U,-V,X,Y);
467  const Real n = X.Nrows() * X.Ncols(); X /= n; Y /= (-n);
468 }
469 
470 
471 #ifdef use_namespace
472 }
473 #endif
474 
475 
GetSubMatrix Column(int) const
Definition: submat.cpp:64
ossim_uint32 x
void DST_inverse(const ColumnVector &V, ColumnVector &U)
Definition: fft.cpp:402
double Real
Definition: include.h:57
void DST_II(const ColumnVector &U, ColumnVector &V)
Definition: fft.cpp:304
void RealFFT(const ColumnVector &U, ColumnVector &X, ColumnVector &Y)
Definition: fft.cpp:126
void Release()
Definition: newmat.h:440
ossim_uint32 y
int Ncols() const
Definition: newmat.h:431
#define A(r, c)
void DCT_II(const ColumnVector &U, ColumnVector &V)
Definition: fft.cpp:249
void FFT(const ColumnVector &U, const ColumnVector &V, ColumnVector &X, ColumnVector &Y)
Definition: fft.cpp:197
void FFT2(const Matrix &U, const Matrix &V, Matrix &X, Matrix &Y)
Definition: fft.cpp:440
void DCT_II_inverse(const ColumnVector &V, ColumnVector &U)
Definition: fft.cpp:277
void FFT2I(const Matrix &U, const Matrix &V, Matrix &X, Matrix &Y)
Definition: fft.cpp:461
os2<< "> n<< " > nendobj n
void FFTI(const ColumnVector &U, const ColumnVector &V, ColumnVector &X, ColumnVector &Y)
Definition: fft.cpp:116
void DST(const ColumnVector &U, ColumnVector &V)
Definition: fft.cpp:430
GetSubMatrix Row(int) const
Definition: submat.cpp:45
Definition: newmat.h:543
static bool ar_1d_ft(int PTS, Real *X, Real *Y)
Definition: newfft.cpp:146
void RealFFTI(const ColumnVector &A, const ColumnVector &B, ColumnVector &U)
Definition: fft.cpp:162
static bool OnlyOldFFT
Definition: newmatap.h:109
#define REPORT
Definition: fft.cpp:23
int Nrows() const
Definition: newmat.h:430
void DCT(const ColumnVector &U, ColumnVector &V)
Definition: fft.cpp:393
void DCT_inverse(const ColumnVector &V, ColumnVector &U)
Definition: fft.cpp:359
static bool CanFactor(int PTS)
Definition: newfft.cpp:988
Real * Store() const
Definition: newmat.h:433
TransposedMatrix t() const
Definition: newmat6.cpp:316
void CleanUp()
Definition: newmat4.cpp:895
void DST_II_inverse(const ColumnVector &V, ColumnVector &U)
Definition: fft.cpp:332
void ReSize(int)
Definition: newmat4.cpp:262