Last active
February 1, 2021 19:02
-
-
Save joslloand/f0eb392f532f40e729f1bdb7d49e4b47 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Compare sclang inbuilt fft with SignalBox rfft - refactor of tests by @spluta | |
What we're seeing is that sclang's complex fft is by far the fastest. | |
Relatedly, if a real fft (+freqs only) is desired, the quickest approach is to discard -freqs, | |
and then use rfftToFft to create a mirrored spectrum for resynthesis via ifft. | |
It would be worth investigating refactoring the algorithms found in SignalBox, keeping in mind | |
preserving the current interface(s). | |
https://gitlab.com/dxarts/projects/SignalBox.quark | |
NOTE: in testing SignalBox implementations, consider -bench | |
*/ | |
// fft, imag = zeros | |
// elapsed time: 0.32782895606942 | |
// db difference: -142.43620707737 | |
( | |
var size = 256, cosTable, real, imag, complex, ifft, ifftReal; | |
var times = 10000, elapsed; | |
// fft | |
cosTable = Signal.fftCosTable(size); | |
// real | |
real = Signal.newClear(size); | |
real.sineFill2([[8], [13, 0.5], [21, 0.25], [55, 0.125, 0.5pi]]); | |
// imag | |
imag = Signal.newClear(size); // zeros | |
// loop | |
elapsed = Main.elapsedTime; | |
times.do{|i| | |
complex = fft(real, imag, cosTable); | |
ifft = complex.real.ifft(complex.imag, cosTable); | |
ifftReal = ifft.real; // keep real!! | |
}; | |
"elapsed time: %".format(Main.elapsedTime-elapsed).postln; | |
// analyze last iteration | |
"db difference: %".format((real - ifftReal).rms.ampdb).postln | |
) | |
// fft, imag = zeros, mirror spectrum | |
// elapsed time: 0.57792912703007 | |
// db difference: -141.67949967795 | |
( | |
var size = 256, cosTable, real, imag, complex, ifft, ifftReal; | |
var rsize = (size/2 + 1).asInteger; | |
var times = 10000, elapsed; | |
// fft | |
cosTable = Signal.fftCosTable(size); | |
// real | |
real = Signal.newClear(size); | |
real.sineFill2([[8], [13, 0.5], [21, 0.25], [55, 0.125, 0.5pi]]); | |
// imag | |
imag = Signal.newClear(size); // zeros | |
// loop | |
elapsed = Main.elapsedTime; | |
times.do{|i| | |
complex = fft(real, imag, cosTable); | |
// mirror spectrum | |
complex = complex.real.keep(rsize).rfftToFft(complex.imag.keep(rsize)); | |
ifft = complex.real.ifft(complex.imag, cosTable); | |
ifftReal = ifft.real; // keep real!! | |
}; | |
"elapsed time: %".format(Main.elapsedTime-elapsed).postln; | |
// analyze last iteration | |
"db difference: %".format((real - ifftReal).rms.ampdb).postln | |
) | |
// fft, imag = nil, mirror spectrum | |
/* | |
NOTE: no checking for NaNs | |
NOTE: inconsistent resynthesis | |
*/ | |
// elapsed time: 0.55441648198757 | |
// db difference: -66.226529919968 | |
// | |
// elapsed time: 0.53545523795765 | |
// db difference: -140.65801028913 | |
( | |
var size = 256, cosTable, real, imag, complex, ifft, ifftReal; | |
var rsize = (size/2 + 1).asInteger; | |
var times = 10000, elapsed; | |
// fft | |
cosTable = Signal.fftCosTable(size); | |
// real | |
real = Signal.newClear(size); | |
real.sineFill2([[8], [13, 0.5], [21, 0.25], [55, 0.125, 0.5pi]]); | |
// imag | |
imag = nil; // force use of rfft | |
// loop | |
elapsed = Main.elapsedTime; | |
times.do{|i| | |
complex = fft(real, imag, cosTable); | |
// mirror spectrum | |
complex = complex.real.keep(rsize).rfftToFft(complex.imag.keep(rsize)); | |
ifft = complex.real.ifft(complex.imag, cosTable); | |
ifftReal = ifft.real; // keep real!! | |
}; | |
"elapsed time: %".format(Main.elapsedTime-elapsed).postln; | |
// analyze last iteration | |
"db difference: %".format((real - ifftReal).rms.ampdb).postln | |
) | |
// rfftTwo | |
// elapsed time: 0.75525017094333 | |
// db difference: -140.61664340803 | |
( | |
var size = 256, rcosTable, real, complex, complexDict, irfftDict, irfft1, irfft2; | |
var rsize = (size/2 + 1).asInteger; | |
var times = (10000 / 2).asInteger, elapsed; | |
// rfft | |
rcosTable = Signal.rfftTwoCosTable(rsize); | |
// real | |
real = Signal.newClear(size); | |
real.sineFill2([[8], [13, 0.5], [21, 0.25], [55, 0.125, 0.5pi]]); | |
// loop | |
elapsed = Main.elapsedTime; | |
times.do{|i| | |
complexDict = rfftTwo(real, real, rcosTable); | |
irfftDict = complexDict[\rfft1].real.irfftTwo( | |
complexDict[\rfft1].imag, | |
complexDict[\rfft2].real, | |
complexDict[\rfft2].imag, | |
rcosTable | |
); | |
irfft1 = irfftDict.irfft1; // real | |
irfft2 = irfftDict.irfft2; // real | |
}; | |
"elapsed time: %".format(Main.elapsedTime-elapsed).postln; | |
// analyze last iteration | |
"db difference: %".format((real - irfft1).rms.ampdb).postln | |
) | |
// rfft | |
// elapsed time: 6.3424224969931 | |
// db difference: -139.80574232918 | |
( | |
var size = 256, rcosTable, real, rcomplex, irfft; | |
var rsize = (size/2 + 1).asInteger; | |
var times = 10000, elapsed; | |
// rfft | |
rcosTable = Signal.rfftCosTable(rsize); | |
// real | |
real = Signal.newClear(size); | |
real.sineFill2([[8], [13, 0.5], [21, 0.25], [55, 0.125, 0.5pi]]); | |
// loop | |
elapsed = Main.elapsedTime; | |
times.do{|i| | |
rcomplex = rfft(real, rcosTable); | |
irfft = rcomplex.real.irfft(rcomplex.imag, rcosTable); // real | |
}; | |
"elapsed time: %".format(Main.elapsedTime-elapsed).postln; | |
// analyze last iteration | |
"db difference: %".format((real - irfft).rms.ampdb).postln | |
) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment