Skip to content

Commit 351a745

Browse files
committed
Refactor DFT and add common tests for Fourier.
1 parent 13ed506 commit 351a745

File tree

3 files changed

+314
-164
lines changed

3 files changed

+314
-164
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
1+
import ComplexNumber from '../../complex-number/ComplexNumber';
2+
3+
export const fourierDirectTestCases = [
4+
{
5+
input: [
6+
{ amplitude: 1 },
7+
],
8+
output: [
9+
{
10+
frequency: 0, amplitude: 1, phase: 0, re: 1, im: 0,
11+
},
12+
],
13+
},
14+
{
15+
input: [
16+
{ amplitude: 1 },
17+
{ amplitude: 0 },
18+
],
19+
output: [
20+
{
21+
frequency: 0, amplitude: 0.5, phase: 0, re: 0.5, im: 0,
22+
},
23+
{
24+
frequency: 1, amplitude: 0.5, phase: 0, re: 0.5, im: 0,
25+
},
26+
],
27+
},
28+
{
29+
input: [
30+
{ amplitude: 2 },
31+
{ amplitude: 0 },
32+
],
33+
output: [
34+
{
35+
frequency: 0, amplitude: 1, phase: 0, re: 1, im: 0,
36+
},
37+
{
38+
frequency: 1, amplitude: 1, phase: 0, re: 1, im: 0,
39+
},
40+
],
41+
},
42+
{
43+
input: [
44+
{ amplitude: 1 },
45+
{ amplitude: 0 },
46+
{ amplitude: 0 },
47+
],
48+
output: [
49+
{
50+
frequency: 0, amplitude: 0.3333, phase: 0, re: 0.3333, im: 0,
51+
},
52+
{
53+
frequency: 1, amplitude: 0.3333, phase: 0, re: 0.3333, im: 0,
54+
},
55+
{
56+
frequency: 2, amplitude: 0.3333, phase: 0, re: 0.3333, im: 0,
57+
},
58+
],
59+
},
60+
{
61+
input: [
62+
{ amplitude: 1 },
63+
{ amplitude: 0 },
64+
{ amplitude: 0 },
65+
{ amplitude: 0 },
66+
],
67+
output: [
68+
{
69+
frequency: 0, amplitude: 0.25, phase: 0, re: 0.25, im: 0,
70+
},
71+
{
72+
frequency: 1, amplitude: 0.25, phase: 0, re: 0.25, im: 0,
73+
},
74+
{
75+
frequency: 2, amplitude: 0.25, phase: 0, re: 0.25, im: 0,
76+
},
77+
{
78+
frequency: 3, amplitude: 0.25, phase: 0, re: 0.25, im: 0,
79+
},
80+
],
81+
},
82+
{
83+
input: [
84+
{ amplitude: 0 },
85+
{ amplitude: 1 },
86+
{ amplitude: 0 },
87+
{ amplitude: 0 },
88+
],
89+
output: [
90+
{
91+
frequency: 0, amplitude: 0.25, phase: 0, re: 0.25, im: 0,
92+
},
93+
{
94+
frequency: 1, amplitude: 0.25, phase: -90, re: 0, im: -0.25,
95+
},
96+
{
97+
frequency: 2, amplitude: 0.25, phase: 180, re: -0.25, im: 0,
98+
},
99+
{
100+
frequency: 3, amplitude: 0.25, phase: 90, re: 0, im: 0.25,
101+
},
102+
],
103+
},
104+
{
105+
input: [
106+
{ amplitude: 0 },
107+
{ amplitude: 0 },
108+
{ amplitude: 1 },
109+
{ amplitude: 0 },
110+
],
111+
output: [
112+
{
113+
frequency: 0, amplitude: 0.25, phase: 0, re: 0.25, im: 0,
114+
},
115+
{
116+
frequency: 1, amplitude: 0.25, phase: 180, re: -0.25, im: 0,
117+
},
118+
{
119+
frequency: 2, amplitude: 0.25, phase: 0, re: 0.25, im: 0,
120+
},
121+
{
122+
frequency: 3, amplitude: 0.25, phase: 180, re: -0.25, im: 0,
123+
},
124+
],
125+
},
126+
{
127+
input: [
128+
{ amplitude: 0 },
129+
{ amplitude: 0 },
130+
{ amplitude: 0 },
131+
{ amplitude: 2 },
132+
],
133+
output: [
134+
{
135+
frequency: 0, amplitude: 0.5, phase: 0, re: 0.5, im: 0,
136+
},
137+
{
138+
frequency: 1, amplitude: 0.5, phase: 90, re: 0, im: 0.5,
139+
},
140+
{
141+
frequency: 2, amplitude: 0.5, phase: 180, re: -0.5, im: 0,
142+
},
143+
{
144+
frequency: 3, amplitude: 0.5, phase: -90, re: 0, im: -0.5,
145+
},
146+
],
147+
},
148+
{
149+
input: [
150+
{ amplitude: 0 },
151+
{ amplitude: 1 },
152+
{ amplitude: 0 },
153+
{ amplitude: 2 },
154+
],
155+
output: [
156+
{
157+
frequency: 0, amplitude: 0.75, phase: 0, re: 0.75, im: 0,
158+
},
159+
{
160+
frequency: 1, amplitude: 0.25, phase: 90, re: 0, im: 0.25,
161+
},
162+
{
163+
frequency: 2, amplitude: 0.75, phase: 180, re: -0.75, im: 0,
164+
},
165+
{
166+
frequency: 3, amplitude: 0.25, phase: -90, re: 0, im: -0.25,
167+
},
168+
],
169+
},
170+
{
171+
input: [
172+
{ amplitude: 4 },
173+
{ amplitude: 1 },
174+
{ amplitude: 0 },
175+
{ amplitude: 2 },
176+
],
177+
output: [
178+
{
179+
frequency: 0, amplitude: 1.75, phase: 0, re: 1.75, im: 0,
180+
},
181+
{
182+
frequency: 1, amplitude: 1.03077, phase: 14.0362, re: 0.99999, im: 0.25,
183+
},
184+
{
185+
frequency: 2, amplitude: 0.25, phase: 0, re: 0.25, im: 0,
186+
},
187+
{
188+
frequency: 3, amplitude: 1.03077, phase: -14.0362, re: 1, im: -0.25,
189+
},
190+
],
191+
},
192+
{
193+
input: [
194+
{ amplitude: 4 },
195+
{ amplitude: 1 },
196+
{ amplitude: -3 },
197+
{ amplitude: 2 },
198+
],
199+
output: [
200+
{
201+
frequency: 0, amplitude: 1, phase: 0, re: 1, im: 0,
202+
},
203+
{
204+
frequency: 1, amplitude: 1.76776, phase: 8.1301, re: 1.75, im: 0.25,
205+
},
206+
{
207+
frequency: 2, amplitude: 0.5, phase: 180, re: -0.5, im: 0,
208+
},
209+
{
210+
frequency: 3, amplitude: 1.76776, phase: -8.13010, re: 1.75, im: -0.24999,
211+
},
212+
],
213+
},
214+
{
215+
input: [
216+
{ amplitude: 1 },
217+
{ amplitude: 2 },
218+
{ amplitude: 3 },
219+
{ amplitude: 4 },
220+
],
221+
output: [
222+
{
223+
frequency: 0, amplitude: 2.5, phase: 0, re: 2.5, im: 0,
224+
},
225+
{
226+
frequency: 1, amplitude: 0.70710, phase: 135, re: -0.5, im: 0.49999,
227+
},
228+
{
229+
frequency: 2, amplitude: 0.5, phase: 180, re: -0.5, im: 0,
230+
},
231+
{
232+
frequency: 3, amplitude: 0.70710, phase: -134.99999, re: -0.49999, im: -0.5,
233+
},
234+
],
235+
},
236+
];
237+
238+
export default class FourierTester {
239+
/**
240+
* @param {function} fourierTransform
241+
*/
242+
static testDirectFourierTransform(fourierTransform) {
243+
fourierDirectTestCases.forEach((testCase) => {
244+
const { input, output: expectedOutput } = testCase;
245+
246+
// Convert input into complex numbers.
247+
const complexInput = input.map(sample => new ComplexNumber({ re: sample.amplitude }));
248+
249+
// Try to split input signal into sequence of pure sinusoids.
250+
const currentOutput = fourierTransform(complexInput);
251+
252+
// Check the signal has been split into proper amount of sub-signals.
253+
expect(currentOutput.length).toBeGreaterThanOrEqual(complexInput.length);
254+
255+
// Now go through all the signals and check their frequency, amplitude and phase.
256+
expectedOutput.forEach((expectedSignal, frequency) => {
257+
// Get template data we want to test against.
258+
const currentSignal = currentOutput[frequency];
259+
const currentPolarSignal = currentSignal.getPolarForm(false);
260+
261+
// Check all signal parameters.
262+
expect(frequency).toBe(expectedSignal.frequency);
263+
expect(currentSignal.re).toBeCloseTo(expectedSignal.re, 4);
264+
expect(currentSignal.im).toBeCloseTo(expectedSignal.im, 4);
265+
expect(currentPolarSignal.phase).toBeCloseTo(expectedSignal.phase, 4);
266+
expect(currentPolarSignal.radius).toBeCloseTo(expectedSignal.amplitude, 4);
267+
});
268+
});
269+
}
270+
}

0 commit comments

Comments
 (0)