Skip to content

Instantly share code, notes, and snippets.

@joslloand
Last active February 1, 2021 19:02
Show Gist options
  • Save joslloand/f0eb392f532f40e729f1bdb7d49e4b47 to your computer and use it in GitHub Desktop.
Save joslloand/f0eb392f532f40e729f1bdb7d49e4b47 to your computer and use it in GitHub Desktop.
/*
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