Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit d0c4baf

Browse files
committed
Add DFT.
1 parent 8e66189 commit d0c4baf

File tree

6 files changed

+149
-85
lines changed

6 files changed

+149
-85
lines changed

‎src/algorithms/math/fast-fourier-transform/__test__/fastFourierTransform.test.js‎

Lines changed: 0 additions & 85 deletions
This file was deleted.
File renamed without changes.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import discreteFourierTransform from '../discreteFourierTransform';
2+
3+
describe('discreteFourierTransform', () => {
4+
it('should calculate split signal into frequencies', () => {
5+
const frequencies = discreteFourierTransform([1, 0, 0, 0]);
6+
7+
expect(frequencies).toBeDefined();
8+
});
9+
});
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import fastFourierTransform from '../fastFourierTransform';
2+
import ComplexNumber from '../../complex-number/ComplexNumber';
3+
4+
/**
5+
* @param {ComplexNumber[]} [seq1]
6+
* @param {ComplexNumber[]} [seq2]
7+
* @param {Number} [eps]
8+
* @return {boolean}
9+
*/
10+
function approximatelyEqual(seq1, seq2, eps) {
11+
if (seq1.length !== seq2.length) { return false; }
12+
13+
for (let i = 0; i < seq1.length; i += 1) {
14+
if (Math.abs(seq1[i].real - seq2[i].real) > eps) { return false; }
15+
if (Math.abs(seq1[i].complex - seq2[i].complex) > eps) { return false; }
16+
}
17+
18+
return true;
19+
}
20+
21+
describe('fastFourierTransform', () => {
22+
it('should calculate the radix-2 discrete fourier transform after zero padding', () => {
23+
const eps = 1e-6;
24+
const in1 = [new ComplexNumber({ re: 0, im: 0 })];
25+
const expOut1 = [new ComplexNumber({ re: 0, im: 0 })];
26+
const out1 = fastFourierTransform(in1);
27+
const invOut1 = fastFourierTransform(out1, true);
28+
expect(approximatelyEqual(expOut1, out1, eps)).toBe(true);
29+
expect(approximatelyEqual(in1, invOut1, eps)).toBe(true);
30+
31+
const in2 = [
32+
new ComplexNumber({ re: 1, im: 2 }),
33+
new ComplexNumber({ re: 2, im: 3 }),
34+
new ComplexNumber({ re: 8, im: 4 }),
35+
];
36+
37+
const expOut2 = [
38+
new ComplexNumber({ re: 11, im: 9 }),
39+
new ComplexNumber({ re: -10, im: 0 }),
40+
new ComplexNumber({ re: 7, im: 3 }),
41+
new ComplexNumber({ re: -4, im: -4 }),
42+
];
43+
const out2 = fastFourierTransform(in2);
44+
const invOut2 = fastFourierTransform(out2, true);
45+
expect(approximatelyEqual(expOut2, out2, eps)).toBe(true);
46+
expect(approximatelyEqual(in2, invOut2, eps)).toBe(true);
47+
48+
const in3 = [
49+
new ComplexNumber({ re: -83656.9359385182, im: 98724.08038374918 }),
50+
new ComplexNumber({ re: -47537.415125808424, im: 88441.58381765135 }),
51+
new ComplexNumber({ re: -24849.657029355192, im: -72621.79007878687 }),
52+
new ComplexNumber({ re: 31451.27290052717, im: -21113.301128347346 }),
53+
new ComplexNumber({ re: 13973.90836288876, im: -73378.36721594246 }),
54+
new ComplexNumber({ re: 14981.520420492234, im: 63279.524958963884 }),
55+
new ComplexNumber({ re: -9892.575367044381, im: -81748.44671677813 }),
56+
new ComplexNumber({ re: -35933.00356823792, im: -46153.47157161784 }),
57+
new ComplexNumber({ re: -22425.008561855735, im: -86284.24507370662 }),
58+
new ComplexNumber({ re: -39327.43830818355, im: 30611.949874562706 }),
59+
];
60+
61+
const expOut3 = [
62+
new ComplexNumber({ re: -203215.3322151, im: -100242.4827503 }),
63+
new ComplexNumber({ re: 99217.0805705, im: 270646.9331932 }),
64+
new ComplexNumber({ re: -305990.9040412, im: 68224.8435751 }),
65+
new ComplexNumber({ re: -14135.7758282, im: 199223.9878095 }),
66+
new ComplexNumber({ re: -306965.6350922, im: 26030.1025439 }),
67+
new ComplexNumber({ re: -76477.6755206, im: 40781.9078990 }),
68+
new ComplexNumber({ re: -48409.3099088, im: 54674.7959662 }),
69+
new ComplexNumber({ re: -329683.0131713, im: 164287.7995937 }),
70+
new ComplexNumber({ re: -50485.2048527, im: -330375.0546527 }),
71+
new ComplexNumber({ re: 122235.7738708, im: 91091.6398019 }),
72+
new ComplexNumber({ re: 47625.8850387, im: 73497.3981523 }),
73+
new ComplexNumber({ re: -15619.8231136, im: 80804.8685410 }),
74+
new ComplexNumber({ re: 192234.0276101, im: 160833.3072355 }),
75+
new ComplexNumber({ re: -96389.4195635, im: 393408.4543872 }),
76+
new ComplexNumber({ re: -173449.0825417, im: 146875.7724104 }),
77+
new ComplexNumber({ re: -179002.5662573, im: 239821.0124341 }),
78+
];
79+
80+
const out3 = fastFourierTransform(in3);
81+
const invOut3 = fastFourierTransform(out3, true);
82+
expect(approximatelyEqual(expOut3, out3, eps)).toBe(true);
83+
expect(approximatelyEqual(in3, invOut3, eps)).toBe(true);
84+
});
85+
});
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/**
2+
* @param {number[]} data
3+
* @return {*[]}
4+
*/
5+
export default function discreteFourierTransform(data) {
6+
const N = data.length;
7+
const frequencies = [];
8+
9+
// for every frequency...
10+
for (let frequency = 0; frequency < N; frequency += 1) {
11+
let re = 0;
12+
let im = 0;
13+
14+
// for every point in time...
15+
for (let t = 0; t < N; t += 1) {
16+
// Spin the signal _backwards_ at each frequency (as radians/s, not Hertz)
17+
const rate = -1 * (2 * Math.PI) * frequency;
18+
19+
// How far around the circle have we gone at time=t?
20+
const time = t / N;
21+
const distance = rate * time;
22+
23+
// Data-point * e^(-i*2*pi*f) is complex, store each part.
24+
const rePart = data[t] * Math.cos(distance);
25+
const imPart = data[t] * Math.sin(distance);
26+
27+
// add this data point's contribution
28+
re += rePart;
29+
im += imPart;
30+
}
31+
32+
// Close to zero? You're zero.
33+
if (Math.abs(re) < 1e-10) {
34+
re = 0;
35+
}
36+
37+
if (Math.abs(im) < 1e-10) {
38+
im = 0;
39+
}
40+
41+
// Average contribution at this frequency
42+
re /= N;
43+
im /= N;
44+
45+
frequencies[frequency] = {
46+
re,
47+
im,
48+
frequency,
49+
amp: Math.sqrt((re ** 2) + (im ** 2)),
50+
phase: Math.atan2(im, re) * 180 / Math.PI, // in degrees
51+
};
52+
}
53+
54+
return frequencies;
55+
}
File renamed without changes.

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /