Contiki 2.6

ifft.c

00001 /*
00002  * Copyright (c) 2008, Swedish Institute of Computer Science
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the Institute nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  *
00029  * -----------------------------------------------------------------
00030  * ifft - Integer FFT (fast fourier transform) library
00031  *
00032  *
00033  * Author  : Joakim Eriksson
00034  * Created : 2008-03-27
00035  * Updated : $Date: 2008/07/03 23:40:12 $
00036  *           $Revision: 1.3 $
00037  */
00038 #include "lib/ifft.h"
00039 
00040 /*---------------------------------------------------------------------------*/
00041 /* constant table of sin values in 8/7 bits resolution */
00042 /* NOTE: symmetry can be used to reduce this to 1/2 or 1/4 the size */
00043 #define SIN_TAB_LEN 120
00044 #define RESOLUTION 7
00045 #define ABS(x) (x < 0 ? -x : x)
00046 
00047 static const int8_t SIN_TAB[] = {
00048  0,6,13,20,26,33,39,45,52,58,63,69,75,80,
00049  85,90,95,99,103,107,110,114,116,119,121,
00050  123,125,126,127,127,127,127,127,126,125,
00051  123,121,119,116,114,110,107,103,99,95,90,
00052  85,80,75,69,63,58,52,45,39,33,26,20,13,6,
00053  0,-6,-13,-20,-26,-33,-39,-45,-52,-58,-63,
00054  -69,-75,-80,-85,-90,-95,-99,-103,-107,-110,
00055  -114,-116,-119,-121,-123,-125,-126,-127,-127,
00056  -127,-127,-127,-126,-125,-123,-121,-119,-116,
00057  -114,-110,-107,-103,-99,-95,-90,-85,-80,-75,
00058  -69,-63,-58,-52,-45,-39,-33,-26,-20,-13,-6
00059 };
00060 
00061 
00062 static uint16_t bitrev(uint16_t j, uint16_t nu)
00063 {
00064   uint16_t k;
00065   k = 0;
00066   for (; nu > 0; nu--) {
00067     k  = (k << 1) + (j & 1);
00068     j = j >> 1;
00069   }
00070   return k;
00071 }
00072 
00073 
00074 /* Non interpolating sine... which takes an angle of 0 - 999 */
00075 static int16_t sinI(uint16_t angleMilli)
00076 {
00077   uint16_t pos;
00078   pos = (uint16_t) ((SIN_TAB_LEN * (uint32_t) angleMilli) / 1000);
00079   return SIN_TAB[pos % SIN_TAB_LEN];
00080 }
00081 
00082 static int16_t cosI(uint16_t angleMilli)
00083 {
00084   return sinI(angleMilli + 250);
00085 }
00086 
00087 static uint16_t ilog2(uint16_t val)
00088 {
00089   uint16_t log;
00090   log = 0;
00091   val = val >> 1; /* The 20 = 1 => log = 0 => val = 0 */
00092   while (val > 0) {
00093     val = val >> 1;
00094     log++;
00095   }
00096   return log;
00097 }
00098 
00099 
00100 /* ifft(xre[], n) - integer (fixpoint) version of Fast Fourier Transform
00101    An integer version of FFT that takes in-samples in an int16_t array
00102    and does an fft on n samples in the array.
00103    The result of the FFT is stored in the same array as the samples
00104    was stored. Them imaginary part of the result is stored in xim which
00105    needs to be of the same size as xre (e.g. n ints).
00106 
00107    Note: This fft is designed to be used with 8 bit values (e.g. not
00108    16 bit values). The reason for the int16_t array is for keeping some
00109    'room' for the calculations. It is also designed for doing fairly small
00110    FFT:s since to large sample arrays might cause it to overflow during
00111    calculations.
00112 */
00113 void
00114 ifft(int16_t xre[], int16_t xim[], uint16_t n)
00115 {
00116   uint16_t nu;
00117   uint16_t n2;
00118   uint16_t nu1;
00119   int p, k, l, i;
00120   int32_t c, s, tr, ti;
00121 
00122   nu = ilog2(n);
00123   nu1 = nu - 1;
00124   n2 = n / 2;
00125 
00126   for (i = 0; i < n; i++)
00127     xim[i] = 0;
00128 
00129   for (l = 1; l <= nu; l++) {
00130     for (k = 0; k < n; k += n2) {
00131       for (i = 1; i <= n2; i++) {
00132         p = bitrev(k >> nu1, nu);
00133         c = cosI((1000 * p) / n);
00134         s = sinI((1000 * p) / n);
00135 
00136         tr = ((xre[k + n2] * c + xim[k + n2] * s) >> RESOLUTION);
00137         ti = ((xim[k + n2] * c - xre[k + n2] * s) >> RESOLUTION);
00138 
00139         xre[k + n2] = xre[k] - tr;
00140         xim[k + n2] = xim[k] - ti;
00141         xre[k] += tr;
00142         xim[k] += ti;
00143         k++;
00144       }
00145     }
00146     nu1--;
00147     n2 = n2 / 2;
00148   }
00149 
00150   for (k = 0; k < n; k++) {
00151     p = bitrev(k, nu);
00152     if (p > k) {
00153       n2 = xre[k];
00154       xre[k] = xre[p];
00155       xre[p] = n2;
00156 
00157       n2 = xim[k];
00158       xim[k] = xim[p];
00159       xim[p] = n2;
00160     }
00161   }
00162 
00163   /* This is a fast but not 100% correct magnitude calculation */
00164   /* Should be sqrt(xre[i]^2 + xim[i]^2) and normalized with div. by n */
00165   for (i = 0, n2 = n / 2; i < n2; i++) {
00166     xre[i] = (ABS(xre[i]) + ABS(xim[i]));
00167   }
00168 }