Statistics
| Revision:

root / Ports / examples / glcdSpectrum / fix_fft.cpp

History | View | Annotate | Download (7 KB)

1
//>>> The latest version of this code can be found at https://github.com/jcw/ !!
2
3
// copied from http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1286718155
4
5
#include <avr/pgmspace.h>
6
// #include "fix_fft.h"
7
#include <WProgram.h>
8
9
/* fix_fft.c - Fixed-point in-place Fast Fourier Transform  */
10
/*
11
  All data are fixed-point short integers, in which -32768
12
  to +32768 represent -1.0 to +1.0 respectively. Integer
13
  arithmetic is used for speed, instead of the more natural
14
  floating-point.
15
16
  For the forward FFT (time -> freq), fixed scaling is
17
  performed to prevent arithmetic overflow, and to map a 0dB
18
  sine/cosine wave (i.e. amplitude = 32767) to two -6dB freq
19
  coefficients. The return value is always 0.
20
21
  For the inverse FFT (freq -> time), fixed scaling cannot be
22
  done, as two 0dB coefficients would sum to a peak amplitude
23
  of 64K, overflowing the 32k range of the fixed-point integers.
24
  Thus, the fix_fft() routine performs variable scaling, and
25
  returns a value which is the number of bits LEFT by which
26
  the output must be shifted to get the actual amplitude
27
  (i.e. if fix_fft() returns 3, each value of fr[] and fi[]
28
  must be multiplied by 8 (2**3) for proper scaling.
29
  Clearly, this cannot be done within fixed-point short
30
  integers. In practice, if the result is to be used as a
31
  filter, the scale_shift can usually be ignored, as the
32
  result will be approximately correctly normalized as is.
33
34
  Written by:  Tom Roberts  11/8/89
35
  Made portable:  Malcolm Slaney 12/15/94 malcolm@interval.com
36
  Enhanced:  Dimitrios P. Bouras  14 Jun 2006 dbouras@ieee.org
37
  Modified for 8bit values David Keller  10.10.2010
38
*/
39
40
41
#define N_WAVE        256    /* full length of Sinewave[] */
42
#define LOG2_N_WAVE 8        /* log2(N_WAVE) */
43
44
45
46
47
/*
48
  Since we only use 3/4 of N_WAVE, we define only
49
  this many samples, in order to conserve data space.
50
*/
51
52
53
54
const prog_int8_t Sinewave[N_WAVE-N_WAVE/4] PROGMEM = {
55
0, 3, 6, 9, 12, 15, 18, 21,
56
24, 28, 31, 34, 37, 40, 43, 46,
57
48, 51, 54, 57, 60, 63, 65, 68,
58
71, 73, 76, 78, 81, 83, 85, 88,
59
90, 92, 94, 96, 98, 100, 102, 104,
60
106, 108, 109, 111, 112, 114, 115, 117,
61
118, 119, 120, 121, 122, 123, 124, 124,
62
125, 126, 126, 127, 127, 127, 127, 127,
63
64
127, 127, 127, 127, 127, 127, 126, 126,
65
125, 124, 124, 123, 122, 121, 120, 119,
66
118, 117, 115, 114, 112, 111, 109, 108,
67
106, 104, 102, 100, 98, 96, 94, 92,
68
90, 88, 85, 83, 81, 78, 76, 73,
69
71, 68, 65, 63, 60, 57, 54, 51,
70
48, 46, 43, 40, 37, 34, 31, 28,
71
24, 21, 18, 15, 12, 9, 6, 3,
72
73
0, -3, -6, -9, -12, -15, -18, -21,
74
-24, -28, -31, -34, -37, -40, -43, -46,
75
-48, -51, -54, -57, -60, -63, -65, -68,
76
-71, -73, -76, -78, -81, -83, -85, -88,
77
-90, -92, -94, -96, -98, -100, -102, -104,
78
-106, -108, -109, -111, -112, -114, -115, -117,
79
-118, -119, -120, -121, -122, -123, -124, -124,
80
-125, -126, -126, -127, -127, -127, -127, -127,
81
82
/*-127, -127, -127, -127, -127, -127, -126, -126,
83
-125, -124, -124, -123, -122, -121, -120, -119,
84
-118, -117, -115, -114, -112, -111, -109, -108,
85
-106, -104, -102, -100, -98, -96, -94, -92,
86
-90, -88, -85, -83, -81, -78, -76, -73,
87
-71, -68, -65, -63, -60, -57, -54, -51,
88
-48, -46, -43, -40, -37, -34, -31, -28,
89
-24, -21, -18, -15, -12, -9, -6, -3, */
90
};
91
92
93
94
95
96
97
/*
98
  FIX_MPY() - fixed-point multiplication & scaling.
99
  Substitute inline assembly for hardware-specific
100
  optimization suited to a particluar DSP processor.
101
  Scaling ensures that result remains 16-bit.
102
*/
103
inline char FIX_MPY(char a, char b)
104
{
105
  
106
  //Serial.println(a);
107
 //Serial.println(b);
108
  
109
  
110
    /* shift right one less bit (i.e. 15-1) */
111
    int c = ((int)a * (int)b) >> 6;
112
    /* last bit shifted out = rounding-bit */
113
    b = c & 0x01;
114
    /* last shift + rounding bit */
115
    a = (c >> 1) + b;
116
117
          /*
118
          Serial.println(Sinewave[3]);
119
          Serial.println(c);
120
          Serial.println(a);
121
          while(1);*/
122
123
    return a;
124
}
125
126
/*
127
  fix_fft() - perform forward/inverse fast Fourier transform.
128
  fr[n],fi[n] are real and imaginary arrays, both INPUT AND
129
  RESULT (in-place FFT), with 0 <= n < 2**m; set inverse to
130
  0 for forward transform (FFT), or 1 for iFFT.
131
*/
132
int fix_fft(char fr[], char fi[], int m, int inverse)
133
{
134
    int mr, nn, i, j, l, k, istep, n, scale, shift;
135
    char qr, qi, tr, ti, wr, wi;
136
137
    n = 1 << m;
138
139
    /* max FFT size = N_WAVE */
140
    if (n > N_WAVE)
141
          return -1;
142
143
    mr = 0;
144
    nn = n - 1;
145
    scale = 0;
146
147
    /* decimation in time - re-order data */
148
    for (m=1; m<=nn; ++m) {
149
          l = n;
150
          do {
151
                l >>= 1;
152
          } while (mr+l > nn);
153
          mr = (mr & (l-1)) + l;
154
155
          if (mr <= m)
156
                continue;
157
          tr = fr[m];
158
          fr[m] = fr[mr];
159
          fr[mr] = tr;
160
          ti = fi[m];
161
          fi[m] = fi[mr];
162
          fi[mr] = ti;
163
    }
164
165
    l = 1;
166
    k = LOG2_N_WAVE-1;
167
    while (l < n) {
168
          if (inverse) {
169
                /* variable scaling, depending upon data */
170
                shift = 0;
171
                for (i=0; i<n; ++i) {
172
                    j = fr[i];
173
                    if (j < 0)
174
                          j = -j;
175
                    m = fi[i];
176
                    if (m < 0)
177
                          m = -m;
178
                    if (j > 16383 || m > 16383) {
179
                          shift = 1;
180
                          break;
181
                    }
182
                }
183
                if (shift)
184
                    ++scale;
185
          } else {
186
                /*
187
                  fixed scaling, for proper normalization --
188
                  there will be log2(n) passes, so this results
189
                  in an overall factor of 1/n, distributed to
190
                  maximize arithmetic accuracy.
191
                */
192
                shift = 1;
193
          }
194
          /*
195
            it may not be obvious, but the shift will be
196
            performed on each data point exactly once,
197
            during this pass.
198
          */
199
          istep = l << 1;
200
          for (m=0; m<l; ++m) {
201
                j = m << k;
202
                /* 0 <= j < N_WAVE/2 */
203
                wr =  pgm_read_word_near(Sinewave + j+N_WAVE/4);
204
205
/*Serial.println("asdfasdf");
206
Serial.println(wr);
207
Serial.println(j+N_WAVE/4);
208
Serial.println(Sinewave[256]);
209
210
Serial.println("");*/
211
212
213
                wi = -pgm_read_word_near(Sinewave + j);
214
                if (inverse)
215
                    wi = -wi;
216
                if (shift) {
217
                    wr >>= 1;
218
                    wi >>= 1;
219
                }
220
                for (i=m; i<n; i+=istep) {
221
                    j = i + l;
222
                    tr = FIX_MPY(wr,fr[j]) - FIX_MPY(wi,fi[j]);
223
                    ti = FIX_MPY(wr,fi[j]) + FIX_MPY(wi,fr[j]);
224
                    qr = fr[i];
225
                    qi = fi[i];
226
                    if (shift) {
227
                          qr >>= 1;
228
                          qi >>= 1;
229
                    }
230
                    fr[j] = qr - tr;
231
                    fi[j] = qi - ti;
232
                    fr[i] = qr + tr;
233
                    fi[i] = qi + ti;
234
                }
235
          }
236
          --k;
237
          l = istep;
238
    }
239
    return scale;
240
}
241
242
/*
243
  fix_fftr() - forward/inverse FFT on array of real numbers.
244
  Real FFT/iFFT using half-size complex FFT by distributing
245
  even/odd samples into real/imaginary arrays respectively.
246
  In order to save data space (i.e. to avoid two arrays, one
247
  for real, one for imaginary samples), we proceed in the
248
  following two steps: a) samples are rearranged in the real
249
  array so that all even samples are in places 0-(N/2-1) and
250
  all imaginary samples in places (N/2)-(N-1), and b) fix_fft
251
  is called with fr and fi pointing to index 0 and index N/2
252
  respectively in the original array. The above guarantees
253
  that fix_fft "sees" consecutive real samples as alternating
254
  real and imaginary samples in the complex array.
255
*/
256
int fix_fftr(char f[], int m, int inverse)
257
{
258
    int i, N = 1<<(m-1), scale = 0;
259
    char tt, *fr=f, *fi=&f[N];
260
261
    if (inverse)
262
          scale = fix_fft(fi, fr, m-1, inverse);
263
    for (i=1; i<N; i+=2) {
264
          tt = f[N+i-1];
265
          f[N+i-1] = f[i];
266
          f[i] = tt;
267
    }
268
    if (! inverse)
269
          scale = fix_fft(fi, fr, m-1, inverse);
270
    return scale;
271
}