Qucs-core  0.0.18
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups 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$
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 <cmath>
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 namespace qucs {
44 
45 using namespace fourier;
46 
47 /* The function performs a 1-dimensional fast fourier transformation.
48  Each data item is meant to be defined in equidistant steps. The
49  number of data items needs to be of binary size, e.g. 64, 128. */
50 void fourier::_fft_1d (nr_double_t * data, int len, int isign) {
51 
52  // bit reversal method
53  int i, j, m, n;
54  n = 2 * len;
55  j = 0;
56  for (i = 0; i < n; i += 2) {
57  if (j > i) { // was index already swapped ?
58  Swap (data[j], data[i]); // swap real part
59  Swap (data[j+1], data[i+1]); // swap imaginary part
60  }
61  m = len;
62  while (m >= 2 && j >= m) { // calculate next swap index
63  j -= m;
64  m >>= 1;
65  }
66  j += m;
67  }
68 
69  // Danielson-Lanzcos algorithm
70  int mmax, istep;
71  nr_double_t wt, th, wr, wi, wpr, wpi, ti, tr;
72  mmax = 2;
73  while (n > mmax) {
74  istep = mmax << 1;
75  th = isign * (2 * M_PI / mmax);
76  wt = sin (0.5 * th);
77  wpr = -2.0 * wt * wt;
78  wpi = sin (th);
79  wr = 1.0;
80  wi = 0.0;
81  for (m = 1; m < mmax; m += 2) {
82  for (i = m; i <= n; i += istep) {
83  j = i + mmax;
84  tr = wr * data[j] - wi * data[j-1];
85  ti = wr * data[j-1] + wi * data[j];
86  data[j] = data[i] - tr;
87  data[j-1] = data[i-1] - ti;
88  data[i] += tr;
89  data[i-1] += ti;
90  }
91  wr = (wt = wr) * wpr - wi * wpi + wr;
92  wi = wi * wpr + wt * wpi + wi;
93  }
94  mmax = istep;
95  }
96 }
97 
98 /* The function transforms two real vectors using a single fast
99  fourier transformation step. The routine works in place. */
100 void fourier::_fft_1d_2r (nr_double_t * r1, nr_double_t * r2, int len) {
101  int n3, n2, j;
102  nr_double_t rep, rem, aip, aim;
103  n3 = 1 + (n2 = len + len);
104 
105  // put the two real vectors into one complex vector
106  for (j = 1; j <= n2; j += 2) {
107  r1[j] = r2[j-1];
108  }
109 
110  // transform the complex vector
111  _fft_1d (r1, len, 1);
112 
113  // separate the two transforms
114  r2[0] = r1[1];
115  r1[1] = r2[1] = 0.0;
116  for (j = 2; j <= len; j += 2) {
117  // use symmetries to separate the two transforms
118  rep = 0.5 * (r1[j] + r1[n2-j]);
119  rem = 0.5 * (r1[j] - r1[n2-j]);
120  aip = 0.5 * (r1[j+1] + r1[n3-j]);
121  aim = 0.5 * (r1[j+1] - r1[n3-j]);
122  // ship them out in two complex vectors
123  r1[j+1] = aim;
124  r2[j+1] = -rem;
125  r1[j] = r1[n2-j] = rep;
126  r2[j] = r2[n2-j] = aip;
127  r1[n3-j] = -aim;
128  r2[n3-j] = rem;
129  }
130 }
131 
132 /* The following function transforms two vectors yielding real valued
133  vectors using a single inverse fast fourier transformation step.
134  The routine works in place as well. */
135 void fourier::_ifft_1d_2r (nr_double_t * r1, nr_double_t * r2, int len) {
136  nr_double_t r, i;
137  int j, jj, nn = len + len;
138 
139  // put the two complex vectors into one complex vector
140  for (j = 0, jj = 0; j < nn; j += 2) {
141  r = r1[j] - r2[j+1];
142  i = r1[j+1] + r2[j];
143  r1[jj++] = r;
144  r1[jj++] = i;
145  }
146 
147  // transform the complex vector
148  _fft_1d (r1, len, -1);
149 
150  // split the transforms into two real vectors
151  for (j = 0; j < nn; j += 2) {
152  r2[j] = r1[j+1];
153  r1[j+1] = r2[j+1] = 0.0;
154  }
155 }
156 
157 /* This function performs a 1-dimensional fast fourier transformation
158  on the given vector 'var'. If 'sign' is -1 the inverse fft is
159  computed, if +1 the fft itself is computed. It returns a vector of
160  binary size (as necessary for a fft). */
161 vector fourier::fft_1d (vector var, int isign) {
162  int i, n, len = var.getSize ();
163 
164  // compute necessary binary data array size
165  int size = 2;
166  while (size < len) size <<= 1;
167 
168  // put data items (temporary array) in place
169  nr_double_t * data;
170  data = (nr_double_t *) calloc (2 * size * sizeof (nr_double_t), 1);
171  for (n = i = 0; i < len; i++, n += 2) {
172  data[n] = real (var (i)); data[n+1] = imag (var (i));
173  }
174 
175  // run 1-dimensional fft
176  _fft_1d (data, size, isign);
177 
178  // store transformed data items in result vector
179  vector res = vector (size);
180  for (n = i = 0; i < size; i++, n += 2) {
181  res (i) = nr_complex_t (data[n], data[n+1]);
182  if (isign < 0) res (i) /= size;
183  }
184 
185  // free temporary data array
186  free (data);
187  return res;
188 }
189 
190 /* The function performs a 1-dimensional discrete fourier
191  transformation. Each data item is meant to be defined in
192  equidistant steps. */
193 void fourier::_dft_1d (nr_double_t * data, int len, int isign) {
194  int k, n, size = 2 * len * sizeof (nr_double_t);
195  nr_double_t * res = (nr_double_t *) calloc (size, 1);
196  nr_double_t th, c, s;
197  for (n = 0; n < 2 * len; n += 2) {
198  th = n * M_PI / 2 / len;
199  for (k = 0; k < 2 * len; k += 2) {
200  c = cos (k * th);
201  s = isign * sin (k * th);
202  res[n] += data[k] * c + data[k+1] * s;
203  res[n+1] += data[k+1] * c - data[k] * s;
204  }
205  }
206  memcpy (data, res, size);
207  free (res);
208 }
209 
210 /* The function performs a 1-dimensional discrete fourier
211  transformation on the given vector 'var'. If 'sign' is -1 the
212  inverse dft is computed, if +1 the dft itself is computed. */
213 vector fourier::dft_1d (vector var, int isign) {
214  int k, n, len = var.getSize ();
215  vector res = vector (len);
216  for (n = 0; n < len; n++) {
217  nr_double_t th = - isign * 2 * M_PI * n / len;
218  nr_complex_t val = 0;
219  for (k = 0; k < len; k++)
220  val += var (k) * std::polar (1.0, th * k);
221  res (n) = isign < 0 ? val / (nr_double_t) len : val;
222  }
223  return res;
224 }
225 
226 // Helper functions.
227 vector fourier::ifft_1d (vector var) {
228  return fft_1d (var, -1);
229 }
230 vector fourier::idft_1d (vector var) {
231  return dft_1d (var, -1);
232 }
233 void fourier::_ifft_1d (nr_double_t * data, int len) {
234  _fft_1d (data, len, -1);
235 }
236 void fourier::_idft_1d (nr_double_t * data, int len) {
237  _dft_1d (data, len, -1);
238 }
239 
240 /* The function performs a n-dimensional fast fourier transformation.
241  Each data item is meant to be defined in equidistant steps. The
242  number of data items needs to be of binary size, e.g. 64, 128 for
243  each dimension. */
244 void fourier::_fft_nd (nr_double_t * data, int len[], int nd, int isign) {
245 
246  int i, i1, i2, i3, i2rev, i3rev, ip1, ip2, ip3, ifp1, ifp2;
247  int ibit, k1, k2, n, np, nr, nt;
248 
249  // compute total number of complex values
250  for (nt = 1, i = 0; i < nd; i++) nt *= len[i];
251 
252  // main loop over the dimensions
253  for (np = 1, i = nd - 1; i >= 0; i--) {
254  n = len[i];
255  nr = nt / (n * np);
256  ip1 = np << 1;
257  ip2 = ip1 * n;
258  ip3 = ip2 * nr;
259 
260  // bit-reversal method
261  for (i2rev = 1, i2 = 1; i2 <= ip2; i2 += ip1) {
262  if (i2 < i2rev) {
263  for (i1 = i2; i1 <= i2 + ip1 - 2; i1 += 2) {
264  for (i3 = i1; i3 <= ip3; i3 += ip2) {
265  i3rev = i2rev + i3 - i2;
266  Swap (data[i3-1], data[i3rev-1]);
267  Swap (data[i3], data[i3rev]);
268  }
269  }
270  }
271  ibit = ip2 >> 1;
272  while (ibit >= ip1 && i2rev > ibit) {
273  i2rev -= ibit;
274  ibit >>= 1;
275  }
276  i2rev += ibit;
277  }
278 
279  // Danielson-Lanzcos algorithm
280  nr_double_t ti, tr, wt, th, wr, wi, wpi, wpr;
281  ifp1 = ip1;
282  while (ifp1 < ip2) {
283  ifp2 = ifp1 << 1;
284  th = isign * 2 * M_PI / (ifp2 / ip1);
285  wt = sin (0.5 * th);
286  wpr = -2.0 * wt * wt;
287  wpi = sin (th);
288  wr = 1.0;
289  wi = 0.0;
290  for (i3 = 1; i3 <= ifp1; i3 += ip1) {
291  for (i1 = i3; i1 <= i3 + ip1 - 2; i1 += 2) {
292  for (i2 = i1; i2 <= ip3; i2 += ifp2) {
293  k1 = i2;
294  k2 = k1 + ifp1;
295  tr = wr * data[k2-1] - wi * data[k2];
296  ti = wr * data[k2] + wi * data[k2-1];
297  data[k2-1] = data[k1-1] - tr;
298  data[k2] = data[k1] - ti;
299  data[k1-1] += tr;
300  data[k1] += ti;
301  }
302  }
303  wr = (wt = wr) * wpr - wi * wpi + wr;
304  wi = wi * wpr + wt * wpi + wi;
305  }
306  ifp1 = ifp2;
307  }
308  np *= n;
309  }
310 }
311 
312 // Helper functions.
313 void fourier::_ifft_nd (nr_double_t * data, int len[], int nd) {
314  _fft_nd (data, len, nd, -1);
315 }
316 
317 // Shuffles values of FFT around.
318 vector fourier::fftshift (vector var) {
319  int i, n, len = var.getSize ();
320  vector res = vector (len);
321  n = len / 2;
322  for (i = 0; i < len / 2; i++) {
323  res (i) = var (n + i);
324  res (i + n) = var (i);
325  }
326  return res;
327 }
328 
329 } // namespace qucs
std::complex< nr_double_t > nr_complex_t
Definition: complex.h:31
void _fft_1d(nr_double_t *, int, int isign=1)
Definition: fourier.cpp:50
matrix real(matrix a)
Real part matrix.
Definition: matrix.cpp:568
size
Definition: parse_vcd.y:203
void _ifft_1d_2r(nr_double_t *, nr_double_t *, int)
Definition: fourier.cpp:135
void _ifft_1d(nr_double_t *, int)
Definition: fourier.cpp:233
qucs::vector fft_1d(qucs::vector, int isign=1)
nr_complex_t cos(const nr_complex_t z)
Compute complex cosine.
Definition: complex.cpp:57
qucs::vector ifft_1d(qucs::vector)
n
Definition: parse_citi.y:147
void _fft_1d_2r(nr_double_t *, nr_double_t *, int)
Definition: fourier.cpp:100
r
Definition: parse_mdl.y:515
i1
Definition: parse_citi.y:148
void _ifft_nd(nr_double_t *, int[], int)
Definition: fourier.cpp:313
i
Definition: parse_mdl.y:516
n2
Definition: parse_zvr.y:187
matrix imag(matrix a)
Imaginary part matrix.
Definition: matrix.cpp:581
nr_complex_t sin(const nr_complex_t z)
Compute complex sine.
Definition: complex.cpp:66
free($1)
Global math constants header file.
#define M_PI
Archimedes' constant ( )
Definition: consts.h:47
void _idft_1d(nr_double_t *, int)
Definition: fourier.cpp:236
void _fft_nd(nr_double_t *, int[], int, int isign=1)
Definition: fourier.cpp:244
i2
Definition: parse_citi.y:160
var
Definition: parse_citi.y:145
qucs::vector fftshift(qucs::vector)
nr_complex_t polar(const nr_double_t mag, const nr_double_t ang)
Construct a complex number using polar notation.
Definition: complex.cpp:551
qucs::vector idft_1d(qucs::vector)
void _dft_1d(nr_double_t *, int, int isign=1)
Definition: fourier.cpp:193
#define Swap(a, b)
Definition: fourier.cpp:41
qucs::vector dft_1d(qucs::vector, int isign=1)
data
Definition: parse_citi.y:117