# HG changeset patch # User Chris Cannam # Date 1444035191 -3600 # Node ID b3243c84ccb3c7398becc600dcc5a42088175569 # Parent 44f670784d5fc95f24bd801d87323fb11166dc9f Tidy up, run each test in two halves (to warm up any JIT stuff) diff -r 44f670784d5f -r b3243c84ccb3 fft/test.html --- a/fft/test.html Thu Oct 01 17:33:28 2015 +0100 +++ b/fft/test.html Mon Oct 05 09:53:11 2015 +0100 @@ -1,127 +1,64 @@ - - - -

If 2150 iterations of real-to-complex FFT of size 2048 takes less than 10 seconds, then we may be able to make a high quality real-time phase vocoder (just).

+ -

A phase-vocoder of course must use overlapped -windowed FFT (although you can choose the size, within limits), IFFT, -and cartesian-polar conversion to calculate the phase for the -instantaneous frequency.

+ -

A reasonable estimate of CPU cost for the whole thing is somewhere -around 10x the cost of simple non-overlapping short-time forward -Fourier transforms across the signal.

+ + + + + + + -

2150 iterations corresponds to 100 seconds of audio non-overlapped at -44.1kHz, so if that takes less than 10 second, then in theory we might -be OK.

+ - - - - - - - - - diff -r 44f670784d5f -r b3243c84ccb3 fft/test.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/fft/test.js Mon Oct 05 09:53:11 2015 +0100 @@ -0,0 +1,136 @@ + +/* for a phase vocoder, we probably want 2048-point real-to-complex + * FFTs (if available) */ + +function inputReals(size) { + var result = new Array(size); + for (var i = 0; i < result.length; i++) + result[i] = (i % 20) / 10.0 - 1.0; + return result; +} + +function zeroReals(size) { + var result = new Array(size); + for (var i = 0; i < result.length; i++) + result[i] = 0.0; + return result; +} + +function inputReal64s(size) { + var result = new Float64Array(size); + for (var i = 0; i < result.length; i++) + result[i] = (i % 20) / 10.0 - 1.0; + return result; +} + +function inputComplexArray(size) { + var result = new complex_array.ComplexArray(size); + for (var i = 0; i < size; i++) { + result.real[i] = (i % 20) / 10.0 - 1.0; + result.imag[i] = 0.0; + } + return result; +} + +var iterations = 2150; +var size = 2048; + +function report(name, start, middle, end, total) { + document.getElementById(name + "-result").innerHTML = total; + document.getElementById(name + "-1").innerHTML = + Math.round(middle - start) + " ms"; + document.getElementById(name + "-2").innerHTML = + Math.round(end - middle) + " ms"; + document.getElementById(name + "-itr").innerHTML = + Math.round((1000.0 / ((end - middle) / iterations))) + " itr/sec"; +} + +function testNayuki() { + + 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); + transform(real, imag); + for (var j = 0; j < size; ++j) { + total += real[j] + imag[j]; + } + } + + var end = performance.now(); + + report("nayuki", start, middle, end, total); +} + +function testNockert() { + + var fft = new FFT.complex(size, false); + + var start = performance.now(); + var middle = start; + var end = start; + + total = 0.0; + + for (var i = 0; i < 2*iterations; ++i) { + if (i == iterations) { + middle = performance.now(); + } + var ri = inputReal64s(size); + var co = new Float64Array(2 * size); + fft.simple(co, ri, 'real'); + for (var j = 0; j < 2 * size; ++j) { + total += co[j]; + } + } + + var end = performance.now(); + + report("nockert", start, middle, end, total); +} + +function testDntj() { + + var start = performance.now(); + var middle = start; + var end = start; + + total = 0.0; + + for (var i = 0; i < 2*iterations; ++i) { + if (i == iterations) { + middle = performance.now(); + } + var ci = inputComplexArray(size); + var co = ci.FFT(); + for (var j = 0; j < size; ++j) { + total += co.real[j] + co.imag[j]; + } + } + + var end = performance.now(); + + report("dntj", start, middle, end, total * Math.sqrt(size)); +} + +function test() { + + document.getElementById("test-description").innerHTML = + "For " + iterations + " iterations per half (" + 2*iterations + + " total) of size " + size; + + testNayuki(); + testNockert(); + testDntj(); +} + +window.onload = test; +