LCOV - code coverage report
Current view: top level - src - fourier.cpp (source / functions) Hit Total Coverage
Test: qucs-core-0.0.19 Code Coverage Lines: 44 168 26.2 %
Date: 2015-01-05 16:01:02 Functions: 2 13 15.4 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 23 78 29.5 %

           Branch data     Line data    Source code
       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                 :         74 : void fourier::_fft_1d (nr_double_t * data, int len, int isign) {
      51                 :            : 
      52                 :            :   // bit reversal method
      53                 :            :   int i, j, m, n;
      54                 :         74 :   n = 2 * len;
      55                 :         74 :   j = 0;
      56         [ +  + ]:       1258 :   for (i = 0; i < n; i += 2) {
      57         [ +  + ]:       1184 :     if (j > i) {                   // was index already swapped ?
      58                 :        444 :       Swap (data[j], data[i]);     // swap real part
      59                 :        444 :       Swap (data[j+1], data[i+1]); // swap imaginary part
      60                 :            :     }
      61                 :       1184 :     m = len;
      62 [ +  + ][ +  + ]:       2294 :     while (m >= 2 && j >= m) {     // calculate next swap index
                 [ +  + ]
      63                 :       1110 :       j -= m;
      64                 :       1110 :       m >>= 1;
      65                 :            :     }
      66                 :       1184 :     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                 :         74 :   mmax = 2;
      73         [ +  + ]:        370 :   while (n > mmax) {
      74                 :        296 :     istep = mmax << 1;
      75                 :        296 :     th = isign * (2 * M_PI / mmax);
      76                 :        296 :     wt = sin (0.5 * th);
      77                 :        296 :     wpr = -2.0 * wt * wt;
      78                 :        296 :     wpi = sin (th);
      79                 :        296 :     wr = 1.0;
      80                 :        296 :     wi = 0.0;
      81         [ +  + ]:       1406 :     for (m = 1; m < mmax; m += 2) {
      82         [ +  + ]:       3478 :       for (i = m; i <= n; i += istep) {
      83                 :       2368 :         j = i + mmax;
      84                 :       2368 :         tr = wr * data[j] - wi * data[j-1];
      85                 :       2368 :         ti = wr * data[j-1] + wi * data[j];
      86                 :       2368 :         data[j] = data[i] - tr;
      87                 :       2368 :         data[j-1] = data[i-1] - ti;
      88                 :       2368 :         data[i] += tr;
      89                 :       2368 :         data[i-1] += ti;
      90                 :            :       }
      91                 :       1110 :       wr = (wt = wr) * wpr - wi * wpi + wr;
      92                 :       1110 :       wi = wi * wpr + wt * wpi + wi;
      93                 :            :     }
      94                 :        296 :     mmax = istep;
      95                 :            :   }
      96                 :         74 : }
      97                 :            : 
      98                 :            : /* The function transforms two real vectors using a single fast
      99                 :            :    fourier transformation step.  The routine works in place. */
     100                 :          0 : 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                 :          0 :   n3 = 1 + (n2 = len + len);
     104                 :            : 
     105                 :            :   // put the two real vectors into one complex vector
     106         [ #  # ]:          0 :   for (j = 1; j <= n2; j += 2) {
     107                 :          0 :     r1[j] = r2[j-1];
     108                 :            :   }
     109                 :            : 
     110                 :            :   // transform the complex vector
     111                 :          0 :   _fft_1d (r1, len, 1);
     112                 :            : 
     113                 :            :   // separate the two transforms
     114                 :          0 :   r2[0] = r1[1];
     115                 :          0 :   r1[1] = r2[1] = 0.0;
     116         [ #  # ]:          0 :   for (j = 2; j <= len; j += 2) {
     117                 :            :     // use symmetries to separate the two transforms
     118                 :          0 :     rep = 0.5 * (r1[j] + r1[n2-j]);
     119                 :          0 :     rem = 0.5 * (r1[j] - r1[n2-j]);
     120                 :          0 :     aip = 0.5 * (r1[j+1] + r1[n3-j]);
     121                 :          0 :     aim = 0.5 * (r1[j+1] - r1[n3-j]);
     122                 :            :     // ship them out in two complex vectors
     123                 :          0 :     r1[j+1] = aim;
     124                 :          0 :     r2[j+1] = -rem;
     125                 :          0 :     r1[j] = r1[n2-j] = rep;
     126                 :          0 :     r2[j] = r2[n2-j] = aip;
     127                 :          0 :     r1[n3-j] = -aim;
     128                 :          0 :     r2[n3-j] = rem;
     129                 :            :   }
     130                 :          0 : }
     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                 :          0 : void fourier::_ifft_1d_2r (nr_double_t * r1, nr_double_t * r2, int len) {
     136                 :            :   nr_double_t r, i;
     137                 :          0 :   int j, jj, nn = len + len;
     138                 :            : 
     139                 :            :   // put the two complex vectors into one complex vector
     140         [ #  # ]:          0 :   for (j = 0, jj = 0; j < nn; j += 2) {
     141                 :          0 :     r = r1[j] - r2[j+1];
     142                 :          0 :     i = r1[j+1] + r2[j];
     143                 :          0 :     r1[jj++] = r;
     144                 :          0 :     r1[jj++] = i;
     145                 :            :   }
     146                 :            : 
     147                 :            :   // transform the complex vector
     148                 :          0 :   _fft_1d (r1, len, -1);
     149                 :            : 
     150                 :            :   // split the transforms into two real vectors
     151         [ #  # ]:          0 :   for (j = 0; j < nn; j += 2) {
     152                 :          0 :     r2[j] = r1[j+1];
     153                 :          0 :     r1[j+1] = r2[j+1] = 0.0;
     154                 :            :   }
     155                 :          0 : }
     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                 :          0 : vector fourier::fft_1d (vector var, int isign) {
     162                 :          0 :   int i, n, len = var.getSize ();
     163                 :            : 
     164                 :            :   // compute necessary binary data array size
     165                 :          0 :   int size = 2;
     166         [ #  # ]:          0 :   while (size < len) size <<= 1;
     167                 :            : 
     168                 :            :   // put data items (temporary array) in place
     169                 :            :   nr_double_t * data;
     170                 :          0 :   data = (nr_double_t *) calloc (2 * size * sizeof (nr_double_t), 1);
     171         [ #  # ]:          0 :   for (n = i = 0; i < len; i++, n += 2) {
     172                 :          0 :     data[n] = real (var (i)); data[n+1] = imag (var (i));
     173                 :            :   }
     174                 :            : 
     175                 :            :   // run 1-dimensional fft
     176                 :          0 :   _fft_1d (data, size, isign);
     177                 :            : 
     178                 :            :   // store transformed data items in result vector
     179                 :          0 :   vector res = vector (size);
     180         [ #  # ]:          0 :   for (n = i = 0; i < size; i++, n += 2) {
     181                 :          0 :     res (i) = nr_complex_t (data[n], data[n+1]);
     182         [ #  # ]:          0 :     if (isign < 0) res (i) /= size;
     183                 :            :   }
     184                 :            : 
     185                 :            :   // free temporary data array
     186                 :          0 :   free (data);
     187                 :          0 :   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                 :          0 : void fourier::_dft_1d (nr_double_t * data, int len, int isign) {
     194                 :          0 :   int k, n, size = 2 * len * sizeof (nr_double_t);
     195                 :          0 :   nr_double_t * res = (nr_double_t *) calloc (size, 1);
     196                 :            :   nr_double_t th, c, s;
     197         [ #  # ]:          0 :   for (n = 0; n < 2 * len; n += 2) {
     198                 :          0 :     th = n * M_PI / 2 / len;
     199         [ #  # ]:          0 :     for (k = 0; k < 2 * len; k += 2) {
     200                 :          0 :       c = cos (k * th);
     201                 :          0 :       s = isign * sin (k * th);
     202                 :          0 :       res[n] += data[k] * c + data[k+1] * s;
     203                 :          0 :       res[n+1] += data[k+1] * c - data[k] * s;
     204                 :            :     }
     205                 :            :   }
     206                 :          0 :   memcpy (data, res, size);
     207                 :          0 :   free (res);
     208                 :          0 : }
     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                 :          3 : vector fourier::dft_1d (vector var, int isign) {
     214                 :          3 :   int k, n, len = var.getSize ();
     215                 :          3 :   vector res = vector (len);
     216         [ +  + ]:        861 :   for (n = 0; n < len; n++) {
     217                 :        858 :     nr_double_t th = - isign * 2 * M_PI * n / len;
     218                 :        858 :     nr_complex_t val = 0;
     219         [ +  + ]:     267596 :     for (k = 0; k < len; k++)
     220         [ +  - ]:     266738 :       val += var (k) * std::polar (1.0, th * k);
     221 [ -  + ][ -  + ]:        858 :     res (n) = isign < 0 ? val / (nr_double_t) len : val;
     222                 :            :   }
     223                 :          3 :   return res;
     224                 :            : }
     225                 :            : 
     226                 :            : // Helper functions.
     227                 :          0 : vector fourier::ifft_1d (vector var) {
     228         [ #  # ]:          0 :   return fft_1d (var, -1);
     229                 :            : }
     230                 :          0 : vector fourier::idft_1d (vector var) {
     231         [ #  # ]:          0 :   return dft_1d (var, -1);
     232                 :            : }
     233                 :          0 : void fourier::_ifft_1d (nr_double_t * data, int len) {
     234                 :          0 :   _fft_1d (data, len, -1);
     235                 :          0 : }
     236                 :          0 : void fourier::_idft_1d (nr_double_t * data, int len) {
     237                 :          0 :   _dft_1d (data, len, -1);
     238                 :          0 : }
     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                 :          0 : 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         [ #  # ]:          0 :  for (nt = 1, i = 0; i < nd; i++) nt *= len[i];
     251                 :            : 
     252                 :            :  // main loop over the dimensions
     253         [ #  # ]:          0 :  for (np = 1, i = nd - 1; i >= 0; i--) {
     254                 :          0 :    n = len[i];
     255                 :          0 :    nr = nt / (n * np);
     256                 :          0 :    ip1 = np << 1;
     257                 :          0 :    ip2 = ip1 * n;
     258                 :          0 :    ip3 = ip2 * nr;
     259                 :            : 
     260                 :            :    // bit-reversal method
     261         [ #  # ]:          0 :    for (i2rev = 1, i2 = 1; i2 <= ip2; i2 += ip1) {
     262         [ #  # ]:          0 :      if (i2 < i2rev) {
     263         [ #  # ]:          0 :        for (i1 = i2; i1 <= i2 + ip1 - 2; i1 += 2) {
     264         [ #  # ]:          0 :          for (i3 = i1; i3 <= ip3; i3 += ip2) {
     265                 :          0 :            i3rev = i2rev + i3 - i2;
     266                 :          0 :            Swap (data[i3-1], data[i3rev-1]);
     267                 :          0 :            Swap (data[i3], data[i3rev]);
     268                 :            :          }
     269                 :            :        }
     270                 :            :      }
     271                 :          0 :      ibit = ip2 >> 1;
     272 [ #  # ][ #  # ]:          0 :      while (ibit >= ip1 && i2rev > ibit) {
                 [ #  # ]
     273                 :          0 :        i2rev -= ibit;
     274                 :          0 :        ibit >>= 1;
     275                 :            :      }
     276                 :          0 :      i2rev += ibit;
     277                 :            :    }
     278                 :            : 
     279                 :            :    // Danielson-Lanzcos algorithm
     280                 :            :    nr_double_t ti, tr, wt, th, wr, wi, wpi, wpr;
     281                 :          0 :    ifp1 = ip1;
     282         [ #  # ]:          0 :    while (ifp1 < ip2) {
     283                 :          0 :      ifp2 = ifp1 << 1;
     284                 :          0 :      th = isign * 2 * M_PI / (ifp2 / ip1);
     285                 :          0 :      wt = sin (0.5 * th);
     286                 :          0 :      wpr = -2.0 * wt * wt;
     287                 :          0 :      wpi = sin (th);
     288                 :          0 :      wr = 1.0;
     289                 :          0 :      wi = 0.0;
     290         [ #  # ]:          0 :      for (i3 = 1; i3 <= ifp1; i3 += ip1) {
     291         [ #  # ]:          0 :        for (i1 = i3; i1 <= i3 + ip1 - 2; i1 += 2) {
     292         [ #  # ]:          0 :          for (i2 = i1; i2 <= ip3; i2 += ifp2) {
     293                 :          0 :            k1 = i2;
     294                 :          0 :            k2 = k1 + ifp1;
     295                 :          0 :            tr = wr * data[k2-1] - wi * data[k2];
     296                 :          0 :            ti = wr * data[k2] + wi * data[k2-1];
     297                 :          0 :            data[k2-1] = data[k1-1] - tr;
     298                 :          0 :            data[k2] = data[k1] - ti;
     299                 :          0 :            data[k1-1] += tr;
     300                 :          0 :            data[k1] += ti;
     301                 :            :          }
     302                 :            :        }
     303                 :          0 :        wr = (wt = wr) * wpr - wi * wpi + wr;
     304                 :          0 :        wi = wi * wpr + wt * wpi + wi;
     305                 :            :      }
     306                 :          0 :      ifp1 = ifp2;
     307                 :            :    }
     308                 :          0 :    np *= n;
     309                 :            :  }
     310                 :          0 : }
     311                 :            : 
     312                 :            : // Helper functions.
     313                 :          0 : void fourier::_ifft_nd (nr_double_t * data, int len[], int nd) {
     314                 :          0 :   _fft_nd (data, len, nd, -1);
     315                 :          0 : }
     316                 :            : 
     317                 :            : // Shuffles values of FFT around.
     318                 :          0 : vector fourier::fftshift (vector var) {
     319                 :          0 :   int i, n, len = var.getSize ();
     320                 :          0 :   vector res = vector (len);
     321                 :          0 :   n = len / 2;
     322         [ #  # ]:          0 :   for (i = 0; i < len / 2; i++) {
     323                 :          0 :     res (i) = var (n + i);
     324                 :          0 :     res (i + n) = var (i);
     325                 :            :   }
     326                 :          0 :   return res;
     327                 :            : }
     328                 :            : 
     329                 :            : } // namespace qucs

Generated by: LCOV version 1.11