comparison fft/nayuki/fft-test.html @ 0:d7c216b6a84f

Pull in some FFT implementations for test
author Chris Cannam
date Thu, 01 Oct 2015 15:50:58 +0100
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:d7c216b6a84f
1 <!--
2 - FFT and convolution test (JavaScript)
3 -
4 - Copyright (c) 2014 Project Nayuki
5 - http://www.nayuki.io/page/free-small-fft-in-multiple-languages
6 -
7 - (MIT License)
8 - Permission is hereby granted, free of charge, to any person obtaining a copy of
9 - this software and associated documentation files (the "Software"), to deal in
10 - the Software without restriction, including without limitation the rights to
11 - use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
12 - the Software, and to permit persons to whom the Software is furnished to do so,
13 - subject to the following conditions:
14 - * The above copyright notice and this permission notice shall be included in
15 - all copies or substantial portions of the Software.
16 - * The Software is provided "as is", without warranty of any kind, express or
17 - implied, including but not limited to the warranties of merchantability,
18 - fitness for a particular purpose and noninfringement. In no event shall the
19 - authors or copyright holders be liable for any claim, damages or other
20 - liability, whether in an action of contract, tort or otherwise, arising from,
21 - out of or in connection with the Software or the use or other dealings in the
22 - Software.
23 -->
24 <!DOCTYPE html>
25 <html>
26 <head>
27 <meta charset="UTF-8">
28 <title>FFT and convolution test (JavaScript)</title>
29 </head>
30 <body>
31 <script src="fft.js" type="application/javascript"></script>
32 <pre>
33 <script>
34 /* Main and test functions */
35
36 function main() {
37 // Test power-of-2 size FFTs
38 for (var i = 0; i <= 12; i++)
39 testFft(1 << i);
40
41 // Test small size FFTs
42 for (var i = 0; i < 30; i++)
43 testFft(i);
44
45 // Test diverse size FFTs
46 var prev = 0;
47 for (var i = 0; i <= 100; i++) {
48 var n = Math.round(Math.pow(1500, i / 100.0));
49 if (n > prev) {
50 testFft(n);
51 prev = n;
52 }
53 }
54
55 // Test power-of-2 size convolutions
56 for (var i = 0; i <= 12; i++)
57 testConvolution(1 << i);
58
59 // Test diverse size convolutions
60 prev = 0;
61 for (var i = 0; i <= 100; i++) {
62 var n = Math.round(Math.pow(1500, i / 100.0));
63 if (n > prev) {
64 testConvolution(n);
65 prev = n;
66 }
67 }
68
69 document.write("\nMax log err = " + maxLogError.toFixed(1));
70 document.write("\nTest " + (maxLogError < -10 ? "passed" : "failed"));
71 }
72
73
74 function testFft(size) {
75 var inputreal = randomReals(size);
76 var inputimag = randomReals(size);
77
78 var refoutreal = new Array(size);
79 var refoutimag = new Array(size);
80 naiveDft(inputreal, inputimag, refoutreal, refoutimag, false);
81
82 var actualoutreal = inputreal.slice(0);
83 var actualoutimag = inputimag.slice(0);
84 transform(actualoutreal, actualoutimag);
85
86 document.write("fftsize=" + size + " logerr=" + log10RmsErr(refoutreal, refoutimag, actualoutreal, actualoutimag).toFixed(1) + "\n");
87 }
88
89
90 function testConvolution(size) {
91 var input0real = randomReals(size);
92 var input0imag = randomReals(size);
93
94 var input1real = randomReals(size);
95 var input1imag = randomReals(size);
96
97 var refoutreal = new Array(size);
98 var refoutimag = new Array(size);
99 naiveConvolve(input0real, input0imag, input1real, input1imag, refoutreal, refoutimag);
100
101 var actualoutreal = new Array(size);
102 var actualoutimag = new Array(size);
103 convolveComplex(input0real, input0imag, input1real, input1imag, actualoutreal, actualoutimag);
104
105 document.write("convsize=" + size + " logerr=" + log10RmsErr(refoutreal, refoutimag, actualoutreal, actualoutimag).toFixed(1) + "\n");
106 }
107
108
109 /* Naive reference computation functions */
110
111 function naiveDft(inreal, inimag, outreal, outimag, inverse) {
112 if (inreal.length != inimag.length || inreal.length != outreal.length || outreal.length != outimag.length)
113 throw "Mismatched lengths";
114
115 var n = inreal.length;
116 var coef = (inverse ? 2 : -2) * Math.PI;
117 for (var k = 0; k < n; k++) { // For each output element
118 var sumreal = 0;
119 var sumimag = 0;
120 for (var t = 0; t < n; t++) { // For each input element
121 var angle = coef * (t * k % n) / n; // This is more accurate than t * k
122 sumreal += inreal[t]*Math.cos(angle) - inimag[t]*Math.sin(angle);
123 sumimag += inreal[t]*Math.sin(angle) + inimag[t]*Math.cos(angle);
124 }
125 outreal[k] = sumreal;
126 outimag[k] = sumimag;
127 }
128 }
129
130
131 function naiveConvolve(xreal, ximag, yreal, yimag, outreal, outimag) {
132 if (xreal.length != ximag.length || xreal.length != yreal.length || yreal.length != yimag.length || xreal.length != outreal.length || outreal.length != outimag.length)
133 throw "Mismatched lengths";
134
135 var n = xreal.length;
136 for (var i = 0; i < n; i++) {
137 var sumreal = 0;
138 var sumimag = 0;
139 for (var j = 0; j < n; j++) {
140 var k = (i - j + n) % n;
141 sumreal += xreal[k] * yreal[j] - ximag[k] * yimag[j];
142 sumimag += xreal[k] * yimag[j] + ximag[k] * yreal[j];
143 }
144 outreal[i] = sumreal;
145 outimag[i] = sumimag;
146 }
147 }
148
149
150 /* Utility functions */
151
152 var maxLogError = Number.NEGATIVE_INFINITY;
153
154 function log10RmsErr(xreal, ximag, yreal, yimag) {
155 if (xreal.length != ximag.length || xreal.length != yreal.length || yreal.length != yimag.length)
156 throw "Mismatched lengths";
157
158 var err = 0;
159 for (var i = 0; i < xreal.length; i++)
160 err += (xreal[i] - yreal[i]) * (xreal[i] - yreal[i]) + (ximag[i] - yimag[i]) * (ximag[i] - yimag[i]);
161 err = Math.sqrt(err / Math.max(xreal.length, 1)); // Now this is a root mean square (RMS) error
162 err = err > 0 ? Math.log(err) / Math.log(10) : -99;
163 maxLogError = Math.max(err, maxLogError);
164 return err;
165 }
166
167
168 function randomReals(size) {
169 var result = new Array(size);
170 for (var i = 0; i < result.length; i++)
171 result[i] = Math.random() * 2 - 1;
172 return result;
173 }
174
175
176 main();
177 </script>
178 </pre>
179 </body>
180 </html>