My Project  0.0.16
QUCS Mapping
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
fourier.cpp
Go to the documentation of this file.
1 /*
2  * fourier.cpp - fourier transformation class implementation
3  *
4  * Copyright (C) 2005, 2006, 2009 Stefan Jahn <stefan@lkcc.org>
5  *
6  * This is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * This software is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this package; see the file COPYING. If not, write to
18  * the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19  * Boston, MA 02110-1301, USA.
20  *
21  * $Id: fourier.cpp 1825 2011-03-11 20:42:14Z ela $
22  *
23  */
24 
25 #if HAVE_CONFIG_H
26 # include <config.h>
27 #endif
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <math.h>
33 
34 #include "consts.h"
35 #include "object.h"
36 #include "complex.h"
37 #include "vector.h"
38 #include "fourier.h"
39 
40 // Helper macro.
41 #define Swap(a,b) { nr_double_t t; t = a; a = b; b = t; }
42 
43 using namespace fourier;
44 
45 /* The function performs a 1-dimensional fast fourier transformation.
46  Each data item is meant to be defined in equidistant steps. The
47  number of data items needs to be of binary size, e.g. 64, 128. */
48 void fourier::_fft_1d (nr_double_t * data, int len, int isign) {
49 
50  // bit reversal method
51  int i, j, m, n;
52  n = 2 * len;
53  j = 0;
54  for (i = 0; i < n; i += 2) {
55  if (j > i) { // was index already swapped ?
56  Swap (data[j], data[i]); // swap real part
57  Swap (data[j+1], data[i+1]); // swap imaginary part
58  }
59  m = len;
60  while (m >= 2 && j >= m) { // calculate next swap index
61  j -= m;
62  m >>= 1;
63  }
64  j += m;
65  }
66 
67  // Danielson-Lanzcos algorithm
68  int mmax, istep;
69  nr_double_t wt, th, wr, wi, wpr, wpi, ti, tr;
70  mmax = 2;
71  while (n > mmax) {
72  istep = mmax << 1;
73  th = isign * (2 * M_PI / mmax);
74  wt = sin (0.5 * th);
75  wpr = -2.0 * wt * wt;
76  wpi = sin (th);
77  wr = 1.0;
78  wi = 0.0;
79  for (m = 1; m < mmax; m += 2) {
80  for (i = m; i <= n; i += istep) {
81  j = i + mmax;
82  tr = wr * data[j] - wi * data[j-1];
83  ti = wr * data[j-1] + wi * data[j];
84  data[j] = data[i] - tr;
85  data[j-1] = data[i-1] - ti;
86  data[i] += tr;
87  data[i-1] += ti;
88  }
89  wr = (wt = wr) * wpr - wi * wpi + wr;
90  wi = wi * wpr + wt * wpi + wi;
91  }
92  mmax = istep;
93  }
94 }
95 
96 /* The function transforms two real vectors using a single fast
97  fourier transformation step. The routine works in place. */
98 void fourier::_fft_1d_2r (nr_double_t * r1, nr_double_t * r2, int len) {
99  int n3, n2, j;
100  nr_double_t rep, rem, aip, aim;
101  n3 = 1 + (n2 = len + len);
102 
103  // put the two real vectors into one complex vector
104  for (j = 1; j <= n2; j += 2) {
105  r1[j] = r2[j-1];
106  }
107 
108  // transform the complex vector
109  _fft_1d (r1, len, 1);
110 
111  // separate the two transforms
112  r2[0] = r1[1];
113  r1[1] = r2[1] = 0.0;
114  for (j = 2; j <= len; j += 2) {
115  // use symmetries to separate the two transforms
116  rep = 0.5 * (r1[j] + r1[n2-j]);
117  rem = 0.5 * (r1[j] - r1[n2-j]);
118  aip = 0.5 * (r1[j+1] + r1[n3-j]);
119  aim = 0.5 * (r1[j+1] - r1[n3-j]);
120  // ship them out in two complex vectors
121  r1[j+1] = aim;
122  r2[j+1] = -rem;
123  r1[j] = r1[n2-j] = rep;
124  r2[j] = r2[n2-j] = aip;
125  r1[n3-j] = -aim;
126  r2[n3-j] = rem;
127  }
128 }
129 
130 /* The following function transforms two vectors yielding real valued
131  vectors using a single inverse fast fourier transformation step.
132  The routine works in place as well. */
133 void fourier::_ifft_1d_2r (nr_double_t * r1, nr_double_t * r2, int len) {
134  nr_double_t r, i;
135  int j, jj, nn = len + len;
136 
137  // put the two complex vectors into one complex vector
138  for (j = 0, jj = 0; j < nn; j += 2) {
139  r = r1[j] - r2[j+1];
140  i = r1[j+1] + r2[j];
141  r1[jj++] = r;
142  r1[jj++] = i;
143  }
144 
145  // transform the complex vector
146  _fft_1d (r1, len, -1);
147 
148  // split the transforms into two real vectors
149  for (j = 0; j < nn; j += 2) {
150  r2[j] = r1[j+1];
151  r1[j+1] = r2[j+1] = 0.0;
152  }
153 }
154 
155 /* This function performs a 1-dimensional fast fourier transformation
156  on the given vector 'var'. If 'sign' is -1 the inverse fft is
157  computed, if +1 the fft itself is computed. It returns a vector of
158  binary size (as necessary for a fft). */
159 vector fourier::fft_1d (vector var, int isign) {
160  int i, n, len = var.getSize ();
161 
162  // compute necessary binary data array size
163  int size = 2;
164  while (size < len) size <<= 1;
165 
166  // put data items (temporary array) in place
167  nr_double_t * data;
168  data = (nr_double_t *) calloc (2 * size * sizeof (nr_double_t), 1);
169  for (n = i = 0; i < len; i++, n += 2) {
170  data[n] = real (var (i)); data[n+1] = imag (var (i));
171  }
172 
173  // run 1-dimensional fft
174  _fft_1d (data, size, isign);
175 
176  // store transformed data items in result vector
177  vector res = vector (size);
178  for (n = i = 0; i < size; i++, n += 2) {
179  res (i) = rect (data[n], data[n+1]);
180  if (isign < 0) res (i) /= size;
181  }
182 
183  // free temporary data array
184  free (data);
185  return res;
186 }
187 
188 /* The function performs a 1-dimensional discrete fourier
189  transformation. Each data item is meant to be defined in
190  equidistant steps. */
191 void fourier::_dft_1d (nr_double_t * data, int len, int isign) {
192  int k, n, size = 2 * len * sizeof (nr_double_t);
193  nr_double_t * res = (nr_double_t *) calloc (size, 1);
194  nr_double_t th, c, s;
195  for (n = 0; n < 2 * len; n += 2) {
196  th = n * M_PI / 2 / len;
197  for (k = 0; k < 2 * len; k += 2) {
198  c = cos (k * th);
199  s = isign * sin (k * th);
200  res[n] += data[k] * c + data[k+1] * s;
201  res[n+1] += data[k+1] * c - data[k] * s;
202  }
203  }
204  memcpy (data, res, size);
205  free (res);
206 }
207 
208 /* The function performs a 1-dimensional discrete fourier
209  transformation on the given vector 'var'. If 'sign' is -1 the
210  inverse dft is computed, if +1 the dft itself is computed. */
211 vector fourier::dft_1d (vector var, int isign) {
212  int k, n, len = var.getSize ();
213  vector res = vector (len);
214  for (n = 0; n < len; n++) {
215  nr_double_t th = - isign * 2 * M_PI * n / len;
216  nr_complex_t val = 0;
217  for (k = 0; k < len; k++)
218  val += var (k) * polar (1.0, th * k);
219  res (n) = isign < 0 ? val / (nr_double_t) len : val;
220  }
221  return res;
222 }
223 
224 // Helper functions.
226  return fft_1d (var, -1);
227 }
229  return dft_1d (var, -1);
230 }
231 void fourier::_ifft_1d (nr_double_t * data, int len) {
232  _fft_1d (data, len, -1);
233 }
234 void fourier::_idft_1d (nr_double_t * data, int len) {
235  _dft_1d (data, len, -1);
236 }
237 
238 /* The function performs a n-dimensional fast fourier transformation.
239  Each data item is meant to be defined in equidistant steps. The
240  number of data items needs to be of binary size, e.g. 64, 128 for
241  each dimension. */
242 void fourier::_fft_nd (nr_double_t * data, int len[], int nd, int isign) {
243 
244  int i, i1, i2, i3, i2rev, i3rev, ip1, ip2, ip3, ifp1, ifp2;
245  int ibit, k1, k2, n, np, nr, nt;
246 
247  // compute total number of complex values
248  for (nt = 1, i = 0; i < nd; i++) nt *= len[i];
249 
250  // main loop over the dimensions
251  for (np = 1, i = nd - 1; i >= 0; i--) {
252  n = len[i];
253  nr = nt / (n * np);
254  ip1 = np << 1;
255  ip2 = ip1 * n;
256  ip3 = ip2 * nr;
257 
258  // bit-reversal method
259  for (i2rev = 1, i2 = 1; i2 <= ip2; i2 += ip1) {
260  if (i2 < i2rev) {
261  for (i1 = i2; i1 <= i2 + ip1 - 2; i1 += 2) {
262  for (i3 = i1; i3 <= ip3; i3 += ip2) {
263  i3rev = i2rev + i3 - i2;
264  Swap (data[i3-1], data[i3rev-1]);
265  Swap (data[i3], data[i3rev]);
266  }
267  }
268  }
269  ibit = ip2 >> 1;
270  while (ibit >= ip1 && i2rev > ibit) {
271  i2rev -= ibit;
272  ibit >>= 1;
273  }
274  i2rev += ibit;
275  }
276 
277  // Danielson-Lanzcos algorithm
278  nr_double_t ti, tr, wt, th, wr, wi, wpi, wpr;
279  ifp1 = ip1;
280  while (ifp1 < ip2) {
281  ifp2 = ifp1 << 1;
282  th = isign * 2 * M_PI / (ifp2 / ip1);
283  wt = sin (0.5 * th);
284  wpr = -2.0 * wt * wt;
285  wpi = sin (th);
286  wr = 1.0;
287  wi = 0.0;
288  for (i3 = 1; i3 <= ifp1; i3 += ip1) {
289  for (i1 = i3; i1 <= i3 + ip1 - 2; i1 += 2) {
290  for (i2 = i1; i2 <= ip3; i2 += ifp2) {
291  k1 = i2;
292  k2 = k1 + ifp1;
293  tr = wr * data[k2-1] - wi * data[k2];
294  ti = wr * data[k2] + wi * data[k2-1];
295  data[k2-1] = data[k1-1] - tr;
296  data[k2] = data[k1] - ti;
297  data[k1-1] += tr;
298  data[k1] += ti;
299  }
300  }
301  wr = (wt = wr) * wpr - wi * wpi + wr;
302  wi = wi * wpr + wt * wpi + wi;
303  }
304  ifp1 = ifp2;
305  }
306  np *= n;
307  }
308 }
309 
310 // Helper functions.
311 void fourier::_ifft_nd (nr_double_t * data, int len[], int nd) {
312  _fft_nd (data, len, nd, -1);
313 }
314 
315 // Shuffles values of FFT around.
317  int i, n, len = var.getSize ();
318  vector res = vector (len);
319  n = len / 2;
320  for (i = 0; i < len / 2; i++) {
321  res (i) = var (n + i);
322  res (i + n) = var (i);
323  }
324  return res;
325 }
326