forked from trekhleb/javascript-algorithms
-
Notifications
You must be signed in to change notification settings - Fork 1
/
fastFourierTransform.js
77 lines (62 loc) · 2.13 KB
/
fastFourierTransform.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import ComplexNumber from '../complex-number/ComplexNumber';
import bitLength from '../bits/bitLength';
/**
* Returns the number which is the flipped binary representation of input.
*
* @param {number} input
* @param {number} bitsCount
* @return {number}
*/
function reverseBits(input, bitsCount) {
let reversedBits = 0;
for (let bitIndex = 0; bitIndex < bitsCount; bitIndex += 1) {
reversedBits *= 2;
if (Math.floor(input / (1 << bitIndex)) % 2 === 1) {
reversedBits += 1;
}
}
return reversedBits;
}
/**
* Returns the radix-2 fast fourier transform of the given array.
* Optionally computes the radix-2 inverse fast fourier transform.
*
* @param {ComplexNumber[]} inputData
* @param {boolean} [inverse]
* @return {ComplexNumber[]}
*/
export default function fastFourierTransform(inputData, inverse = false) {
const bitsCount = bitLength(inputData.length - 1);
const N = 1 << bitsCount;
while (inputData.length < N) {
inputData.push(new ComplexNumber());
}
const output = [];
for (let dataSampleIndex = 0; dataSampleIndex < N; dataSampleIndex += 1) {
output[dataSampleIndex] = inputData[reverseBits(dataSampleIndex, bitsCount)];
}
for (let blockLength = 2; blockLength <= N; blockLength *= 2) {
const imaginarySign = inverse ? -1 : 1;
const phaseStep = new ComplexNumber({
re: Math.cos((2 * Math.PI) / blockLength),
im: imaginarySign * Math.sin((2 * Math.PI) / blockLength),
});
for (let blockStart = 0; blockStart < N; blockStart += blockLength) {
let phase = new ComplexNumber({ re: 1, im: 0 });
for (let signalId = blockStart; signalId < (blockStart + blockLength / 2); signalId += 1) {
const component = output[signalId + blockLength / 2].multiply(phase);
const upd1 = output[signalId].add(component);
const upd2 = output[signalId].subtract(component);
output[signalId] = upd1;
output[signalId + blockLength / 2] = upd2;
phase = phase.multiply(phaseStep);
}
}
}
if (inverse) {
for (let signalId = 0; signalId < N; signalId += 1) {
output[signalId] /= N;
}
}
return output;
}