annotate fft/test.js @ 40:223f770b5341 kissfft-double tip

Try a double-precision kissfft
author Chris Cannam
date Wed, 07 Sep 2016 10:40:32 +0100
parents a47f895d79c0
children
rev   line source
Chris@3 1
Chris@26 2 /* Utility functions to generate arbitrary input in various formats */
Chris@3 3
Chris@3 4 function inputReals(size) {
Chris@8 5 var result = new Float32Array(size);
Chris@3 6 for (var i = 0; i < result.length; i++)
Chris@26 7 result[i] = (i % 2) / 4.0;
Chris@3 8 return result;
Chris@3 9 }
Chris@3 10
Chris@3 11 function zeroReals(size) {
Chris@8 12 var result = new Float32Array(size);
Chris@3 13 for (var i = 0; i < result.length; i++)
Chris@3 14 result[i] = 0.0;
Chris@3 15 return result;
Chris@3 16 }
Chris@3 17
Chris@37 18 function inputInterleaved(size) {
Chris@37 19 var result = new Float32Array(size*2);
Chris@37 20 for (var i = 0; i < size; i++)
Chris@37 21 result[i*2] = (i % 2) / 4.0;
Chris@37 22 return result;
Chris@37 23 }
Chris@37 24
Chris@3 25 function inputReal64s(size) {
Chris@3 26 var result = new Float64Array(size);
Chris@3 27 for (var i = 0; i < result.length; i++)
Chris@26 28 result[i] = (i % 2) / 4.0;
Chris@3 29 return result;
Chris@3 30 }
Chris@3 31
Chris@7 32 function zeroReal64s(size) {
Chris@7 33 var result = new Float64Array(size);
Chris@7 34 for (var i = 0; i < result.length; i++)
Chris@26 35 result[i] = 0.0;
Chris@7 36 return result;
Chris@7 37 }
Chris@7 38
Chris@3 39 function inputComplexArray(size) {
Chris@3 40 var result = new complex_array.ComplexArray(size);
Chris@3 41 for (var i = 0; i < size; i++) {
Chris@26 42 result.real[i] = (i % 2) / 4.0;
Chris@3 43 result.imag[i] = 0.0;
Chris@3 44 }
Chris@3 45 return result;
Chris@3 46 }
Chris@3 47
Chris@19 48 var iterations = 2000;
Chris@3 49
Chris@3 50 function report(name, start, middle, end, total) {
Chris@19 51 function addTo(tag, thing) {
Chris@19 52 document.getElementById(name + "-" + tag).innerHTML += thing + "<br>";
Chris@19 53 }
Chris@19 54 addTo("result", total);
Chris@19 55 addTo("1", Math.round(middle - start) + " ms");
Chris@19 56 addTo("2", Math.round(end - middle) + " ms");
Chris@19 57 addTo("itr", Math.round((1000.0 /
Chris@19 58 ((end - middle) / iterations))) + " itr/sec");
Chris@3 59 }
Chris@3 60
Chris@19 61 function testNayuki(size) {
Chris@3 62
Chris@3 63 var start = performance.now();
Chris@3 64 var middle = start;
Chris@3 65 var end = start;
Chris@3 66
Chris@3 67 var total = 0.0;
Chris@3 68
Chris@3 69 for (var i = 0; i < 2*iterations; ++i) {
Chris@3 70 if (i == iterations) {
Chris@3 71 middle = performance.now();
Chris@3 72 }
Chris@3 73 var real = inputReals(size);
Chris@3 74 var imag = zeroReals(size);
Chris@3 75 transform(real, imag);
Chris@3 76 for (var j = 0; j < size; ++j) {
Chris@4 77 total += Math.sqrt(real[j] * real[j] + imag[j] * imag[j]);
Chris@3 78 }
Chris@3 79 }
Chris@3 80
Chris@3 81 var end = performance.now();
Chris@3 82
Chris@3 83 report("nayuki", start, middle, end, total);
Chris@3 84 }
Chris@3 85
Chris@19 86 function testNayukiObj(size) {
Chris@17 87
Chris@17 88 var fft = new FFTNayuki(size);
Chris@17 89
Chris@17 90 var start = performance.now();
Chris@17 91 var middle = start;
Chris@17 92 var end = start;
Chris@17 93
Chris@17 94 var total = 0.0;
Chris@17 95
Chris@17 96 for (var i = 0; i < 2*iterations; ++i) {
Chris@17 97 if (i == iterations) {
Chris@17 98 middle = performance.now();
Chris@17 99 }
Chris@17 100 var real = inputReals(size);
Chris@17 101 var imag = zeroReals(size);
Chris@17 102 fft.forward(real, imag);
Chris@17 103 for (var j = 0; j < size; ++j) {
Chris@17 104 total += Math.sqrt(real[j] * real[j] + imag[j] * imag[j]);
Chris@17 105 }
Chris@17 106 }
Chris@17 107
Chris@17 108 var end = performance.now();
Chris@17 109
Chris@17 110 report("nayukiobj", start, middle, end, total);
Chris@17 111 }
Chris@17 112
Chris@32 113 function testNayukiC(size) {
Chris@32 114
Chris@32 115 var fft = new FFTNayukiC(size);
Chris@32 116
Chris@32 117 var start = performance.now();
Chris@32 118 var middle = start;
Chris@32 119 var end = start;
Chris@32 120
Chris@32 121 total = 0.0;
Chris@32 122
Chris@32 123 for (var i = 0; i < 2*iterations; ++i) {
Chris@32 124 if (i == iterations) {
Chris@32 125 middle = performance.now();
Chris@32 126 }
Chris@33 127 var real = inputReal64s(size);
Chris@33 128 var imag = zeroReal64s(size);
Chris@32 129 fft.forward(real, imag);
Chris@32 130 for (var j = 0; j < size; ++j) {
Chris@32 131 total += Math.sqrt(real[j] * real[j] + imag[j] * imag[j]);
Chris@32 132 }
Chris@32 133 }
Chris@32 134
Chris@32 135 var end = performance.now();
Chris@32 136
Chris@32 137 fft.dispose();
Chris@32 138
Chris@32 139 report("nayukic", start, middle, end, total);
Chris@32 140 }
Chris@32 141
Chris@37 142 function testNayukiCF(size) {
Chris@37 143
Chris@37 144 var fft = new FFTNayukiCFloat(size);
Chris@37 145
Chris@37 146 var start = performance.now();
Chris@37 147 var middle = start;
Chris@37 148 var end = start;
Chris@37 149
Chris@37 150 total = 0.0;
Chris@37 151
Chris@37 152 for (var i = 0; i < 2*iterations; ++i) {
Chris@37 153 if (i == iterations) {
Chris@37 154 middle = performance.now();
Chris@37 155 }
Chris@37 156 var real = inputReals(size);
Chris@37 157 var imag = zeroReals(size);
Chris@37 158 fft.forward(real, imag);
Chris@37 159 for (var j = 0; j < size; ++j) {
Chris@37 160 total += Math.sqrt(real[j] * real[j] + imag[j] * imag[j]);
Chris@37 161 }
Chris@37 162 }
Chris@37 163
Chris@37 164 var end = performance.now();
Chris@37 165
Chris@37 166 fft.dispose();
Chris@37 167
Chris@37 168 report("nayukicf", start, middle, end, total);
Chris@37 169 }
Chris@37 170
Chris@19 171 function testNockert(size) {
Chris@3 172
Chris@3 173 var fft = new FFT.complex(size, false);
Chris@3 174
Chris@3 175 var start = performance.now();
Chris@3 176 var middle = start;
Chris@3 177 var end = start;
Chris@3 178
Chris@3 179 total = 0.0;
Chris@3 180
Chris@3 181 for (var i = 0; i < 2*iterations; ++i) {
Chris@3 182 if (i == iterations) {
Chris@3 183 middle = performance.now();
Chris@3 184 }
Chris@3 185 var ri = inputReal64s(size);
Chris@3 186 var co = new Float64Array(2 * size);
Chris@3 187 fft.simple(co, ri, 'real');
Chris@4 188 for (var j = 0; j < size; ++j) {
Chris@4 189 total += Math.sqrt(co[j*2] * co[j*2] + co[j*2+1] * co[j*2+1]);
Chris@3 190 }
Chris@3 191 }
Chris@3 192
Chris@3 193 var end = performance.now();
Chris@3 194
Chris@3 195 report("nockert", start, middle, end, total);
Chris@3 196 }
Chris@3 197
Chris@19 198 function testDntj(size) {
Chris@3 199
Chris@3 200 var start = performance.now();
Chris@3 201 var middle = start;
Chris@3 202 var end = start;
Chris@3 203
Chris@3 204 total = 0.0;
Chris@4 205 var scale = Math.sqrt(size);
Chris@3 206
Chris@3 207 for (var i = 0; i < 2*iterations; ++i) {
Chris@3 208 if (i == iterations) {
Chris@3 209 middle = performance.now();
Chris@3 210 }
Chris@3 211 var ci = inputComplexArray(size);
Chris@3 212 var co = ci.FFT();
Chris@3 213 for (var j = 0; j < size; ++j) {
Chris@4 214 total += scale *
Chris@4 215 Math.sqrt(co.real[j] * co.real[j] + co.imag[j] * co.imag[j]);
Chris@3 216 }
Chris@3 217 }
Chris@3 218
Chris@3 219 var end = performance.now();
Chris@3 220
Chris@4 221 report("dntj", start, middle, end, total);
Chris@3 222 }
Chris@3 223
Chris@19 224 function testCross(size) {
Chris@7 225
Chris@7 226 var fft = new FFTCross(size);
Chris@7 227
Chris@7 228 var start = performance.now();
Chris@7 229 var middle = start;
Chris@7 230 var end = start;
Chris@7 231
Chris@7 232 total = 0.0;
Chris@7 233
Chris@7 234 for (var i = 0; i < 2*iterations; ++i) {
Chris@7 235 if (i == iterations) {
Chris@7 236 middle = performance.now();
Chris@7 237 }
Chris@7 238 var ri = inputReal64s(size);
Chris@7 239 var out = fft.transformReal(ri, false);
Chris@7 240 for (var j = 0; j < size; ++j) {
Chris@7 241 total +=
Chris@7 242 Math.sqrt(out.real[j] * out.real[j] + out.imag[j] * out.imag[j]);
Chris@7 243 }
Chris@7 244 }
Chris@7 245
Chris@7 246 var end = performance.now();
Chris@8 247
Chris@8 248 report("cross", start, middle, end, total);
Chris@7 249
Chris@19 250 fft.dispose();
Chris@8 251 }
Chris@8 252
Chris@19 253 function testKissFFT(size) {
Chris@8 254
Chris@37 255 var fft = new KissFFTR(size);
Chris@8 256
Chris@8 257 var start = performance.now();
Chris@8 258 var middle = start;
Chris@8 259 var end = start;
Chris@8 260
Chris@8 261 total = 0.0;
Chris@8 262
Chris@8 263 for (var i = 0; i < 2*iterations; ++i) {
Chris@8 264 if (i == iterations) {
Chris@8 265 middle = performance.now();
Chris@8 266 }
Chris@8 267 var ri = inputReals(size);
Chris@8 268 var out = fft.forward(ri);
Chris@8 269 for (var j = 0; j <= size/2; ++j) {
Chris@8 270 total += Math.sqrt(out[j*2] * out[j*2] + out[j*2+1] * out[j*2+1]);
Chris@8 271 }
Chris@37 272 // KissFFTR returns only the first half of the output (plus
Chris@8 273 // DC/Nyquist) -- synthesise the conjugate half
Chris@8 274 for (var j = 1; j < size/2; ++j) {
Chris@8 275 total += Math.sqrt(out[j*2] * out[j*2] + out[j*2+1] * out[j*2+1]);
Chris@8 276 }
Chris@8 277 }
Chris@8 278
Chris@8 279 var end = performance.now();
Chris@8 280
Chris@8 281 report("kissfft", start, middle, end, total);
Chris@8 282
Chris@19 283 fft.dispose();
Chris@7 284 }
Chris@7 285
Chris@37 286 function testKissFFTCC(size) {
Chris@37 287
Chris@37 288 var fft = new KissFFT(size);
Chris@37 289
Chris@37 290 var start = performance.now();
Chris@37 291 var middle = start;
Chris@37 292 var end = start;
Chris@37 293
Chris@37 294 total = 0.0;
Chris@37 295
Chris@37 296 for (var i = 0; i < 2*iterations; ++i) {
Chris@37 297 if (i == iterations) {
Chris@37 298 middle = performance.now();
Chris@37 299 }
Chris@37 300 var cin = inputInterleaved(size);
Chris@37 301 var out = fft.forward(cin);
Chris@37 302 for (var j = 0; j < size; ++j) {
Chris@37 303 total += Math.sqrt(out[j*2] * out[j*2] + out[j*2+1] * out[j*2+1]);
Chris@37 304 }
Chris@37 305 }
Chris@37 306
Chris@37 307 var end = performance.now();
Chris@37 308
Chris@37 309 report("kissfftcc", start, middle, end, total);
Chris@37 310
Chris@37 311 fft.dispose();
Chris@37 312 }
Chris@37 313
Chris@19 314 function testFFTW(size) {
Chris@19 315
Chris@19 316 var fft = new FFTW(size);
Chris@19 317
Chris@19 318 var start = performance.now();
Chris@19 319 var middle = start;
Chris@19 320 var end = start;
Chris@19 321
Chris@19 322 total = 0.0;
Chris@19 323
Chris@19 324 for (var i = 0; i < 2*iterations; ++i) {
Chris@19 325 if (i == iterations) {
Chris@19 326 middle = performance.now();
Chris@19 327 }
Chris@19 328 var ri = inputReals(size);
Chris@19 329 var out = fft.forward(ri);
Chris@19 330 for (var j = 0; j <= size/2; ++j) {
Chris@19 331 total += Math.sqrt(out[j*2] * out[j*2] + out[j*2+1] * out[j*2+1]);
Chris@19 332 }
Chris@19 333 // FFTW returns only the first half of the output (plus
Chris@19 334 // DC/Nyquist) -- synthesise the conjugate half
Chris@19 335 for (var j = 1; j < size/2; ++j) {
Chris@19 336 total += Math.sqrt(out[j*2] * out[j*2] + out[j*2+1] * out[j*2+1]);
Chris@19 337 }
Chris@19 338 }
Chris@19 339
Chris@19 340 var end = performance.now();
Chris@19 341
Chris@19 342 report("fftw", start, middle, end, total);
Chris@19 343
Chris@19 344 fft.dispose();
Chris@19 345 }
Chris@19 346
Chris@40 347 var sizes = [ 4, 8, 512, 2048 ];
Chris@37 348 var tests = [ testNayuki, testNayukiObj, testNayukiC, testNayukiCF,
Chris@37 349 testKissFFT, testKissFFTCC, testCross, testFFTW,
Chris@37 350 testNockert, testDntj ];
Chris@16 351 var nextTest = 0;
Chris@19 352 var nextSize = 0;
Chris@16 353 var interval;
Chris@16 354
Chris@3 355 function test() {
Chris@16 356 clearInterval(interval);
Chris@19 357 if (nextTest == tests.length) {
Chris@19 358 nextSize++;
Chris@19 359 nextTest = 0;
Chris@19 360 if (nextSize == sizes.length) {
Chris@19 361 return;
Chris@19 362 }
Chris@16 363 }
Chris@19 364 f = tests[nextTest];
Chris@19 365 size = sizes[nextSize];
Chris@19 366 nextTest++;
Chris@19 367 f(size);
Chris@19 368 interval = setInterval(test, 100);
Chris@16 369 }
Chris@3 370
Chris@16 371 window.onload = function() {
Chris@3 372 document.getElementById("test-description").innerHTML =
Chris@19 373 "Running " + 2*iterations + " iterations per implementation.<br>Timings are given separately for the first half of the run (" + iterations + " iterations) and the second half, in case the JS engine takes some warming up.<br>Each cell contains results for the following sizes: " + sizes;
Chris@19 374 interval = setInterval(test, 100);
Chris@3 375 }
Chris@3 376