Mercurial > hg > js-dsp-test
changeset 17:9619d2da67c2
Add object version of Nayuki code
author | Chris Cannam |
---|---|
date | Mon, 05 Oct 2015 15:37:41 +0100 |
parents | a8a89f74338b |
children | 8db794ca3e0b |
files | fft/nayuki-obj/fft.js fft/test.html fft/test.js |
diffstat | 3 files changed, 126 insertions(+), 3 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fft/nayuki-obj/fft.js Mon Oct 05 15:37:41 2015 +0100 @@ -0,0 +1,92 @@ +/* + * Free FFT and convolution (JavaScript) + * + * Copyright (c) 2014 Project Nayuki + * http://www.nayuki.io/page/free-small-fft-in-multiple-languages + * + * (MIT License) + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * - The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * - The Software is provided "as is", without warranty of any kind, express or + * implied, including but not limited to the warranties of merchantability, + * fitness for a particular purpose and noninfringement. In no event shall the + * authors or copyright holders be liable for any claim, damages or other + * liability, whether in an action of contract, tort or otherwise, arising from, + * out of or in connection with the Software or the use or other dealings in the + * Software. + */ + +"use strict"; + +function FFTNayuki(n) { + this.n = n; + this.levels = -1; + + for (var i = 0; i < 32; i++) { + if (1 << i == n) { + this.levels = i; // Equal to log2(n) + } + } + if (this.levels == -1) { + throw "Length is not a power of 2"; + } + + this.cosTable = new Array(n / 2); + this.sinTable = new Array(n / 2); + for (var i = 0; i < n / 2; i++) { + this.cosTable[i] = Math.cos(2 * Math.PI * i / n); + this.sinTable[i] = Math.sin(2 * Math.PI * i / n); + } + + this.forward = function(real, imag) { + + for (var i = 0; i < n; i++) { + var j = reverseBits(i, this.levels); + if (j > i) { + var temp = real[i]; + real[i] = real[j]; + real[j] = temp; + temp = imag[i]; + imag[i] = imag[j]; + imag[j] = temp; + } + } + + for (var size = 2; size <= n; size *= 2) { + var halfsize = size / 2; + var tablestep = n / size; + for (var i = 0; i < n; i += size) { + for (var j = i, k = 0; j < i + halfsize; j++, k += tablestep) { + var tpre = real[j+halfsize] * this.cosTable[k] + + imag[j+halfsize] * this.sinTable[k]; + var tpim = -real[j+halfsize] * this.sinTable[k] + + imag[j+halfsize] * this.cosTable[k]; + real[j + halfsize] = real[j] - tpre; + imag[j + halfsize] = imag[j] - tpim; + real[j] += tpre; + imag[j] += tpim; + } + } + } + + function reverseBits(x, bits) { + var y = 0; + for (var i = 0; i < bits; i++) { + y = (y << 1) | (x & 1); + x >>>= 1; + } + return y; + } + } + + this.inverse = function(real, imag) { + forward(imag, real); + } +} +
--- a/fft/test.html Mon Oct 05 15:06:39 2015 +0100 +++ b/fft/test.html Mon Oct 05 15:37:41 2015 +0100 @@ -10,6 +10,7 @@ </style> <script src="nayuki/fft.js"></script> + <script src="nayuki-obj/fft.js"></script> <script src="fft.js/lib/complex.js"></script> <script src="jsfft/lib/complex_array.js"></script> <script src="jsfft/lib/fft.js"></script> @@ -32,7 +33,9 @@ </tr> <tr> <td>Nayuki</td><td id="nayuki-result"></td><td id="nayuki-1"></td><td id="nayuki-2"></td><td id="nayuki-itr"></td> - </tr><tr> + </tr><tr> + <td>Nayuki (obj)</td><td id="nayukiobj-result"></td><td id="nayukiobj-1"></td><td id="nayukiobj-2"></td><td id="nayukiobj-itr"></td> + </tr><tr> <td>Nockert</td><td id="nockert-result"></td><td id="nockert-1"></td><td id="nockert-2"></td><td id="nockert-itr"></td> </tr><tr> <td>Dntj</td><td id="dntj-result"></td><td id="dntj-1"></td><td id="dntj-2"></td><td id="dntj-itr"></td> @@ -47,8 +50,9 @@ <ul> <li><b>Nayuki</b>: in-place single-precision complex-complex</li> + <li><b>Nayuki (obj)</b>: Nayuki with the sin/cos tables pre-calculated on object construction</li> <li><b>Nockert</b>: double-precision real-complex</li> - <li><b>Nayuki</b>: double-precision complex-complex. Forward + <li><b>Dntj</b>: double-precision complex-complex. Forward transform is scaled and I've scaled it back again here, which may introduce rounding error.</li> <li><b>Cross</b>: double-precision real-complex in C, compiled
--- a/fft/test.js Mon Oct 05 15:06:39 2015 +0100 +++ b/fft/test.js Mon Oct 05 15:37:41 2015 +0100 @@ -77,6 +77,33 @@ report("nayuki", start, middle, end, total); } +function testNayukiObj() { + + var fft = new FFTNayuki(size); + + var start = performance.now(); + var middle = start; + var end = start; + + var total = 0.0; + + for (var i = 0; i < 2*iterations; ++i) { + if (i == iterations) { + middle = performance.now(); + } + var real = inputReals(size); + var imag = zeroReals(size); + fft.forward(real, imag); + for (var j = 0; j < size; ++j) { + total += Math.sqrt(real[j] * real[j] + imag[j] * imag[j]); + } + } + + var end = performance.now(); + + report("nayukiobj", start, middle, end, total); +} + function testNockert() { var fft = new FFT.complex(size, false); @@ -192,7 +219,7 @@ fft.discard(); } -var tests = [ testNayuki, testNockert, testDntj, testCross, testKissFFT ]; +var tests = [ testNayuki, testNayukiObj, testNockert, testDntj, testCross, testKissFFT ]; var nextTest = 0; var interval;