Chris@0
|
1 /*
|
Chris@0
|
2 * Free FFT and convolution (JavaScript)
|
Chris@0
|
3 *
|
Chris@0
|
4 * Copyright (c) 2014 Project Nayuki
|
Chris@0
|
5 * http://www.nayuki.io/page/free-small-fft-in-multiple-languages
|
Chris@24
|
6 *
|
Chris@0
|
7 * (MIT License)
|
Chris@0
|
8 * Permission is hereby granted, free of charge, to any person obtaining a copy of
|
Chris@0
|
9 * this software and associated documentation files (the "Software"), to deal in
|
Chris@0
|
10 * the Software without restriction, including without limitation the rights to
|
Chris@0
|
11 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
Chris@0
|
12 * the Software, and to permit persons to whom the Software is furnished to do so,
|
Chris@0
|
13 * subject to the following conditions:
|
Chris@0
|
14 * - The above copyright notice and this permission notice shall be included in
|
Chris@0
|
15 * all copies or substantial portions of the Software.
|
Chris@0
|
16 * - The Software is provided "as is", without warranty of any kind, express or
|
Chris@0
|
17 * implied, including but not limited to the warranties of merchantability,
|
Chris@0
|
18 * fitness for a particular purpose and noninfringement. In no event shall the
|
Chris@0
|
19 * authors or copyright holders be liable for any claim, damages or other
|
Chris@0
|
20 * liability, whether in an action of contract, tort or otherwise, arising from,
|
Chris@0
|
21 * out of or in connection with the Software or the use or other dealings in the
|
Chris@0
|
22 * Software.
|
Chris@24
|
23 *
|
Chris@24
|
24 * Slightly restructured by Chris Cannam, cannam@all-day-breakfast.com
|
Chris@0
|
25 */
|
Chris@0
|
26
|
Chris@0
|
27 "use strict";
|
Chris@0
|
28
|
Chris@24
|
29 /*
|
Chris@24
|
30 * Construct an object for calculating the discrete Fourier transform (DFT) of size n, where n is a power of 2.
|
Chris@24
|
31 */
|
Chris@17
|
32 function FFTNayuki(n) {
|
Chris@19
|
33
|
Chris@17
|
34 this.n = n;
|
Chris@17
|
35 this.levels = -1;
|
Chris@0
|
36
|
Chris@17
|
37 for (var i = 0; i < 32; i++) {
|
Chris@17
|
38 if (1 << i == n) {
|
Chris@17
|
39 this.levels = i; // Equal to log2(n)
|
Chris@17
|
40 }
|
Chris@17
|
41 }
|
Chris@17
|
42 if (this.levels == -1) {
|
Chris@17
|
43 throw "Length is not a power of 2";
|
Chris@17
|
44 }
|
Chris@17
|
45
|
Chris@17
|
46 this.cosTable = new Array(n / 2);
|
Chris@17
|
47 this.sinTable = new Array(n / 2);
|
Chris@17
|
48 for (var i = 0; i < n / 2; i++) {
|
Chris@17
|
49 this.cosTable[i] = Math.cos(2 * Math.PI * i / n);
|
Chris@17
|
50 this.sinTable[i] = Math.sin(2 * Math.PI * i / n);
|
Chris@17
|
51 }
|
Chris@17
|
52
|
Chris@24
|
53 /*
|
Chris@24
|
54 * Computes the discrete Fourier transform (DFT) of the given complex vector, storing the result back into the vector.
|
Chris@24
|
55 * The vector's length must be equal to the size n that was passed to the object constructor, and this must be a power of 2. Uses the Cooley-Tukey decimation-in-time radix-2 algorithm.
|
Chris@24
|
56 */
|
Chris@17
|
57 this.forward = function(real, imag) {
|
Chris@22
|
58
|
Chris@22
|
59 var n = this.n;
|
Chris@17
|
60
|
Chris@24
|
61 // Bit-reversed addressing permutation
|
Chris@17
|
62 for (var i = 0; i < n; i++) {
|
Chris@17
|
63 var j = reverseBits(i, this.levels);
|
Chris@17
|
64 if (j > i) {
|
Chris@17
|
65 var temp = real[i];
|
Chris@17
|
66 real[i] = real[j];
|
Chris@17
|
67 real[j] = temp;
|
Chris@17
|
68 temp = imag[i];
|
Chris@17
|
69 imag[i] = imag[j];
|
Chris@17
|
70 imag[j] = temp;
|
Chris@17
|
71 }
|
Chris@17
|
72 }
|
Chris@0
|
73
|
Chris@24
|
74 // Cooley-Tukey decimation-in-time radix-2 FFT
|
Chris@17
|
75 for (var size = 2; size <= n; size *= 2) {
|
Chris@17
|
76 var halfsize = size / 2;
|
Chris@17
|
77 var tablestep = n / size;
|
Chris@17
|
78 for (var i = 0; i < n; i += size) {
|
Chris@17
|
79 for (var j = i, k = 0; j < i + halfsize; j++, k += tablestep) {
|
Chris@17
|
80 var tpre = real[j+halfsize] * this.cosTable[k] +
|
Chris@17
|
81 imag[j+halfsize] * this.sinTable[k];
|
Chris@17
|
82 var tpim = -real[j+halfsize] * this.sinTable[k] +
|
Chris@17
|
83 imag[j+halfsize] * this.cosTable[k];
|
Chris@17
|
84 real[j + halfsize] = real[j] - tpre;
|
Chris@17
|
85 imag[j + halfsize] = imag[j] - tpim;
|
Chris@17
|
86 real[j] += tpre;
|
Chris@17
|
87 imag[j] += tpim;
|
Chris@17
|
88 }
|
Chris@17
|
89 }
|
Chris@17
|
90 }
|
Chris@17
|
91
|
Chris@24
|
92 // Returns the integer whose value is the reverse of the lowest 'bits' bits of the integer 'x'.
|
Chris@17
|
93 function reverseBits(x, bits) {
|
Chris@17
|
94 var y = 0;
|
Chris@17
|
95 for (var i = 0; i < bits; i++) {
|
Chris@17
|
96 y = (y << 1) | (x & 1);
|
Chris@17
|
97 x >>>= 1;
|
Chris@17
|
98 }
|
Chris@17
|
99 return y;
|
Chris@17
|
100 }
|
Chris@17
|
101 }
|
Chris@0
|
102
|
Chris@24
|
103 /*
|
Chris@24
|
104 * Computes the inverse discrete Fourier transform (IDFT) of the given complex vector, storing the result back into the vector.
|
Chris@24
|
105 * The vector's length must be equal to the size n that was passed to the object constructor, and this must be a power of 2. This is a wrapper function. This transform does not perform scaling, so the inverse is not a true inverse.
|
Chris@24
|
106 */
|
Chris@17
|
107 this.inverse = function(real, imag) {
|
Chris@17
|
108 forward(imag, real);
|
Chris@0
|
109 }
|
Chris@0
|
110 }
|
Chris@0
|
111
|