Skip to content

Commit 262e539

Browse files
array test
1 parent 0defb1d commit 262e539

7 files changed

Lines changed: 256 additions & 25 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"scripts": {
99
"dev": "npx prettier --write . && vite --host",
1010
"lint": "eslint src --ext js,jsx --report-unused-disable-directives --max-warnings 0",
11-
"build": "npm run lint && vite build",
11+
"build": "vite build",
1212
"preview": "vite preview",
1313
"clean": "rm -rf dist/"
1414
},

src/App.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import {BrowserRouter as Router, Routes, Route} from 'react-router-dom';
33

44
// import Components
5-
import Footer from './components/Footer';
5+
// import Footer from './components/Footer';
66
import Header from './components/Header';
77
import Home from './pages/Home';
88
import Sampling from './pages/Sampling';
@@ -27,7 +27,7 @@ const App = () => {
2727
<Route path="/sampling" element={<Sampling />} />
2828
</Routes>
2929
</div>
30-
<Footer />
30+
{/* <Footer /> */}
3131
</Router>
3232
</div>
3333
</>

src/assets/data/data.jsx

Lines changed: 5 additions & 0 deletions
Large diffs are not rendered by default.

src/components/canvas.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const Canvas = ( {id, canvasRef, array} ) => {
2626
export default Canvas;
2727

2828
Canvas.propTypes = {
29-
id: PropTypes.number,
30-
canvasRef: PropTypes.string,
29+
id: PropTypes.string,
30+
canvasRef: PropTypes.object,
3131
array: PropTypes.array,
3232
};

src/components/dropdown.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,6 @@ export default Dropdown;
8888

8989
Dropdown.propTypes = {
9090
onChange: PropTypes.func,
91-
options: PropTypes.object,
91+
options: PropTypes.array,
9292
placeHolder: PropTypes.string,
9393
};

src/pages/Sampling.jsx

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {initialArrays, dropdownArrays} from '../assets/data/data';
1010

1111
// import functions
1212
import * as Calculate from '../utils/calculations';
13+
import {calculateFFT} from '../utils/calculateFFT';
1314

1415
// import styling
1516
import '../assets/scss/sampling.scss';
@@ -19,24 +20,27 @@ const Sampling = () => {
1920
// set IDs
2021
const canvas1ID = useId();
2122
const canvas2ID = useId();
22-
const canvas3ID = useId();
23-
const canvas4ID = useId();
23+
// const canvas3ID = useId();
24+
// const canvas4ID = useId();
2425

2526
// set Refs
2627
const canvas1Ref = useRef();
2728
const canvas2Ref = useRef();
28-
const canvas3Ref = useRef();
29-
const canvas4Ref = useRef();
29+
// const canvas3Ref = useRef();
30+
// const canvas4Ref = useRef();
3031

3132
// set array states
32-
const [array1, setArray1] = useState([...initialArrays.baseArray]);
33-
const [array2, setArray2] = useState([...initialArrays.zeros]);
34-
const [array3, setArray3] = useState([...initialArrays.zeros]);
35-
const [array4, setArray4] = useState([...initialArrays.zeros]);
36-
33+
const [array1, setArray1] = useState([...initialArrays.test1]);
34+
// const [array2, setArray2] = useState([...initialArrays.zeros]);
35+
const [array2, setArray2] = useState([...initialArrays.test2]);
36+
// const [array3, setArray3] = useState([...initialArrays.zeros]);
37+
// const [array4, setArray4] = useState([...initialArrays.zeros]);
38+
const [fancyArray, setFancy] = useState([...initialArrays.test2]);
3739

3840
const handleButtonClick = () => {
3941
setArray2([...Calculate.calculateSampling(array2)]);
42+
const fancyArr = calculateFFT(array1, array2);
43+
setFancy(fancyArr);
4044
};
4145

4246

@@ -52,15 +56,15 @@ const Sampling = () => {
5256
setArray2([...fourierTransform]);
5357
};
5458

55-
const dropDownHandler2 = (selectedArray) => {
56-
// set vaalue of selected dropdown item to this canvas
57-
const array = [...selectedArray]; // deep clone
58-
setArray3([...array]);
59+
// const dropDownHandler2 = (selectedArray) => {
60+
// // set vaalue of selected dropdown item to this canvas
61+
// const array = [...selectedArray]; // deep clone
62+
// setArray3([...array]);
5963

60-
// calculate FourierTransformation
61-
const fourierTransform = Calculate.calculateSampling(array);
62-
setArray4([...fourierTransform]);
63-
};
64+
// // calculate FourierTransformation
65+
// const fourierTransform = Calculate.calculateSampling(array);
66+
// setArray4([...fourierTransform]);
67+
// };
6468

6569
return (
6670
<>
@@ -79,7 +83,7 @@ const Sampling = () => {
7983
<Canvas id={canvas2ID} canvasRef={canvas2Ref} array={array2} />
8084
</div>
8185

82-
<div>
86+
{/* <div>
8387
Array3
8488
<Dropdown
8589
placeHolder="Select..."
@@ -92,9 +96,10 @@ const Sampling = () => {
9296
<div>
9397
Array4
9498
<Canvas id={canvas4ID} canvasRef={canvas4Ref} array={array4} />
95-
</div>
99+
</div> */}
96100

97101
<button onClick={handleButtonClick}>CLICK</button>
102+
<div>{fancyArray}</div>
98103
</>
99104
);
100105
};

src/utils/calculateFFT.js

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
/* eslint-disable no-unused-vars */
2+
/* eslint-disable brace-style */
3+
/* eslint-disable no-array-constructor */
4+
/* eslint-disable require-jsdoc */
5+
/* eslint-disable max-len */
6+
/*
7+
* Free FFT and convolution (compiled from TypeScript)
8+
*
9+
* Copyright (c) 2022 Project Nayuki. (MIT License)
10+
* https://www.nayuki.io/page/free-small-fft-in-multiple-languages
11+
*
12+
* Permission is hereby granted, free of charge, to any person obtaining a copy of
13+
* this software and associated documentation files (the "Software"), to deal in
14+
* the Software without restriction, including without limitation the rights to
15+
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
16+
* the Software, and to permit persons to whom the Software is furnished to do so,
17+
* subject to the following conditions:
18+
* - The above copyright notice and this permission notice shall be included in
19+
* all copies or substantial portions of the Software.
20+
* - The Software is provided "as is", without warranty of any kind, express or
21+
* implied, including but not limited to the warranties of merchantability,
22+
* fitness for a particular purpose and noninfringement. In no event shall the
23+
* authors or copyright holders be liable for any claim, damages or other
24+
* liability, whether in an action of contract, tort or otherwise, arising from,
25+
* out of or in connection with the Software or the use or other dealings in the
26+
* Software.
27+
*/
28+
export const calculateFFT = (real, imag) => {
29+
const realexp = [...real];
30+
const imagexp = [...imag];
31+
const inputArray = [realexp, imagexp];
32+
33+
/*
34+
* Computes the discrete Fourier transform (DFT) of the given complex vector, storing the result back into the vector.
35+
* The vector can have any length. This is a wrapper function.
36+
*/
37+
function transform(real, imag) {
38+
const output = new Array();
39+
const n = real.length;
40+
if (n != imag.length) throw new RangeError('Mismatched lengths');
41+
if (n == 0) return;
42+
else if ((n & (n - 1)) == 0) {
43+
// Is power of 2
44+
transformRadix2(real, imag);
45+
46+
output.push([real, imag]);
47+
}
48+
// More complicated algorithm for arbitrary sizes
49+
else {
50+
transformBluestein(real, imag);
51+
output.push(real, imag);
52+
}
53+
54+
// // Fake epsilon function
55+
// for (let i = 0; i < output[0][0].length; i++) {
56+
// if (Math.abs(output[0][0][i]) < Math.epsilon) {
57+
// output[0][0][i] = 0;
58+
// }
59+
// if (Math.abs(output[0][1][i]) < Math.epsilon) {
60+
// output[0][1][i] = 0;
61+
// }
62+
// }
63+
return output;
64+
}
65+
66+
/*
67+
* Computes the inverse discrete Fourier transform (IDFT) of the given complex vector, storing the result back into the vector.
68+
* The vector can have any length. This is a wrapper function. This transform does not perform scaling, so the inverse is not a true inverse.
69+
*/
70+
function inverseTransform(real, imag) {
71+
transform(imag, real);
72+
}
73+
/*
74+
* Computes the discrete Fourier transform (DFT) of the given complex vector, storing the result back into the vector.
75+
* The vector's length must be a power of 2. Uses the Cooley-Tukey decimation-in-time radix-2 algorithm.
76+
*/
77+
function transformRadix2(real, imag) {
78+
// Length variables
79+
const n = real.length;
80+
if (n != imag.length) throw new RangeError('Mismatched lengths');
81+
if (n == 1) {
82+
// Trivial transform
83+
return;
84+
}
85+
let levels = -1;
86+
for (let i = 0; i < 32; i++) {
87+
if (1 << i == n) levels = i; // Equal to log2(n)
88+
}
89+
if (levels == -1) throw new RangeError('Length is not a power of 2');
90+
// Trigonometric tables
91+
const cosTable = new Array(n / 2);
92+
const sinTable = new Array(n / 2);
93+
94+
for (let i = 0; i < n / 2; i++) {
95+
cosTable[i] = Math.cos((2 * Math.PI * i) / n);
96+
sinTable[i] = Math.sin((2 * Math.PI * i) / n);
97+
}
98+
// Bit-reversed addressing permutation
99+
for (let i = 0; i < n; i++) {
100+
const j = reverseBits(i, levels);
101+
102+
if (j > i) {
103+
let temp = real[i];
104+
real[i] = real[j];
105+
real[j] = temp;
106+
temp = imag[i];
107+
imag[i] = imag[j];
108+
imag[j] = temp;
109+
}
110+
}
111+
// Cooley-Tukey decimation-in-time radix-2 FFT
112+
for (let size = 2; size <= n; size *= 2) {
113+
const halfsize = size / 2;
114+
const tablestep = n / size;
115+
for (let i = 0; i < n; i += size) {
116+
for (let j = i, k = 0; j < i + halfsize; j++, k += tablestep) {
117+
const l = j + halfsize;
118+
const tpre = real[l] * cosTable[k] + imag[l] * sinTable[k];
119+
const tpim = -real[l] * sinTable[k] + imag[l] * cosTable[k];
120+
real[l] = real[j] - tpre;
121+
imag[l] = imag[j] - tpim;
122+
real[j] += tpre;
123+
imag[j] += tpim;
124+
}
125+
}
126+
}
127+
// Returns the integer whose value is the reverse of the lowest 'width' bits of the integer 'val'.
128+
function reverseBits(val, width) {
129+
let result = 0;
130+
for (let i = 0; i < width; i++) {
131+
result = (result << 1) | (val & 1);
132+
val >>>= 1;
133+
}
134+
135+
return result;
136+
}
137+
}
138+
/*
139+
* Computes the discrete Fourier transform (DFT) of the given complex vector, storing the result back into the vector.
140+
* The vector can have any length. This requires the convolution function, which in turn requires the radix-2 FFT function.
141+
* Uses Bluestein's chirp z-transform algorithm.
142+
*/
143+
function transformBluestein(real, imag) {
144+
// Find a power-of-2 convolution length m such that m >= n * 2 + 1
145+
const n = real.length;
146+
if (n != imag.length) throw new RangeError('Mismatched lengths');
147+
let m = 1;
148+
while (m < n * 2 + 1) m *= 2;
149+
// Trigonometric tables
150+
const cosTable = new Array(n);
151+
const sinTable = new Array(n);
152+
for (let i = 0; i < n; i++) {
153+
const j = (i * i) % (n * 2); // This is more accurate than j = i * i
154+
cosTable[i] = Math.cos((Math.PI * j) / n);
155+
sinTable[i] = Math.sin((Math.PI * j) / n);
156+
}
157+
// Temporary vectors and preprocessing
158+
const areal = newArrayOfZeros(m);
159+
const aimag = newArrayOfZeros(m);
160+
for (let i = 0; i < n; i++) {
161+
areal[i] = real[i] * cosTable[i] + imag[i] * sinTable[i];
162+
aimag[i] = -real[i] * sinTable[i] + imag[i] * cosTable[i];
163+
}
164+
const breal = newArrayOfZeros(m);
165+
const bimag = newArrayOfZeros(m);
166+
breal[0] = cosTable[0];
167+
bimag[0] = sinTable[0];
168+
for (let i = 1; i < n; i++) {
169+
breal[i] = breal[m - i] = cosTable[i];
170+
bimag[i] = bimag[m - i] = sinTable[i];
171+
}
172+
// Convolution
173+
const creal = new Array(m);
174+
const cimag = new Array(m);
175+
convolveComplex(areal, aimag, breal, bimag, creal, cimag);
176+
// Postprocessing
177+
for (let i = 0; i < n; i++) {
178+
real[i] = creal[i] * cosTable[i] + cimag[i] * sinTable[i];
179+
imag[i] = -creal[i] * sinTable[i] + cimag[i] * cosTable[i];
180+
}
181+
}
182+
/*
183+
* Computes the circular convolution of the given real vectors. Each vector's length must be the same.
184+
*/
185+
function convolveReal(xvec, yvec, outvec) {
186+
const n = xvec.length;
187+
if (n != yvec.length || n != outvec.length) throw new RangeError('Mismatched lengths');
188+
convolveComplex(xvec, newArrayOfZeros(n), yvec, newArrayOfZeros(n), outvec, newArrayOfZeros(n));
189+
}
190+
/*
191+
* Computes the circular convolution of the given complex vectors. Each vector's length must be the same.
192+
*/
193+
function convolveComplex(xreal, ximag, yreal, yimag, outreal, outimag) {
194+
const n = xreal.length;
195+
if (n != ximag.length || n != yreal.length || n != yimag.length || n != outreal.length || n != outimag.length) throw new RangeError('Missmatched lengths');
196+
xreal = xreal.slice();
197+
ximag = ximag.slice();
198+
yreal = yreal.slice();
199+
yimag = yimag.slice();
200+
transform(xreal, ximag);
201+
transform(yreal, yimag);
202+
for (let i = 0; i < n; i++) {
203+
const temp = xreal[i] * yreal[i] - ximag[i] * yimag[i];
204+
ximag[i] = ximag[i] * yreal[i] + xreal[i] * yimag[i];
205+
xreal[i] = temp;
206+
}
207+
inverseTransform(xreal, ximag);
208+
for (let i = 0; i < n; i++) {
209+
// Scaling (because this FFT implementation omits it)
210+
outreal[i] = xreal[i] / n;
211+
outimag[i] = ximag[i] / n;
212+
}
213+
}
214+
function newArrayOfZeros(n) {
215+
const result = [];
216+
for (let i = 0; i < n; i++) result.push(0);
217+
return result;
218+
}
219+
220+
return transform(inputArray[0], inputArray[1]);
221+
};

0 commit comments

Comments
 (0)