forked from Jezzamonn/fourier
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjust-fourier-things.js
96 lines (88 loc) · 3.02 KB
/
just-fourier-things.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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
import FFT from 'fft.js';
import { slurp } from "./util";
/**
* Do the fourier thing using a bunch of complex points
*
* @param {Array<Number>} points Array of points, alternative with re, im pairs. Length must be a power of 2
*/
export function getFourierData(points) {
if (points.length == 0) {
return [];
}
const numPoints = points.length / 2;
const fft = new FFT(numPoints);
const out = fft.createComplexArray();
fft.transform(out, points);
// Transform into an API of points I find friendlier.
const fftData = [];
for (let i = 0; i < numPoints; i ++) {
// to reorder the frequencies a little nicer, we pick from the front and back altermatively
const j = i % 2 == 0 ? i / 2 : numPoints - ((i+1) / 2);
const x = out[2 * j];
const y = out[2 * j + 1];
const freq = ((j + numPoints / 2) % numPoints) - numPoints / 2;
fftData.push({
freq: freq,
// a little expensive
amplitude: Math.sqrt(x * x + y * y) / numPoints,
// a lottle expensive :(
phase: Math.atan2(y, x),
});
}
// fftData.sort((a, b) => b.amplitude - a.amplitude);
return fftData;
}
/**
*
* @param {Array<Number>} points Array of values of some wave. Must be a power of 2.
*/
export function getRealFourierData(points) {
if (points.length == 0) {
return [];
}
const numPoints = points.length;
const fft = new FFT(numPoints);
const formatedPoints = fft.createComplexArray();
fft.toComplexArray(points, formatedPoints);
const out = fft.createComplexArray();
fft.transform(out, formatedPoints);
// Transform into an API of points I find friendlier.
const fftData = [];
// We only have to read the first half of this because of symmetry things.
for (let i = 0; i < numPoints / 2; i ++) {
const x = out[2 * i];
const y = out[2 * i + 1];
const freq = i;
fftData.push({
freq: freq,
// a little expensive
// Also we gotta multiply this by 2 to account for the other side that
amplitude: 2 * Math.sqrt(x * x + y * y) / numPoints,
// a lottle expensive :(
phase: Math.atan2(y, x),
});
}
// fftData.sort((a, b) => b.amplitude - a.amplitude);
return fftData;
}
/**
* Transforms a list of x, y points into input appropriate for a fourier transform.
*/
export function resample2dData(points, numSamples) {
if (points.length == 0) {
// Can't resample if we don't have ANY points
return [];
}
let newPoints = [];
for (let i = 0; i < numSamples; i ++) {
let position = points.length * (i / numSamples);
let index = Math.floor(position);
let nextIndex = (index + 1) % points.length;
let amt = position - index;
newPoints.push(
/* x */ slurp(points[index].x, points[nextIndex].x, amt),
/* y */ slurp(points[index].y, points[nextIndex].y, amt),
)
}
return newPoints;
}