29struct FFTUnitTest final :
public UnitTest
32 :
UnitTest (
"FFT", UnitTestCategories::dsp)
35 static void fillRandom (Random& random, Complex<float>* buffer,
size_t n)
37 for (
size_t i = 0; i < n; ++i)
38 buffer[i] = Complex<float> ((2.0f * random.nextFloat()) - 1.0f,
39 (2.0f * random.nextFloat()) - 1.0f);
42 static void fillRandom (Random& random,
float* buffer,
size_t n)
44 for (
size_t i = 0; i < n; ++i)
45 buffer[i] = (2.0f * random.nextFloat()) - 1.0f;
48 static Complex<float> freqConvolution (
const Complex<float>* in,
float freq,
size_t n)
50 Complex<float> sum (0.0, 0.0);
51 for (
size_t i = 0; i < n; ++i)
52 sum += in[i] * exp (Complex<float> (0,
static_cast<float> (i) * freq));
57 static void performReferenceFourier (
const Complex<float>* in, Complex<float>* out,
58 size_t n,
bool reverse)
61 /
static_cast<float> (n));
63 for (
size_t i = 0; i < n; ++i)
64 out[i] = freqConvolution (in,
static_cast<float> (i) * base_freq, n);
67 static void performReferenceFourier (
const float* in, Complex<float>* out,
68 size_t n,
bool reverse)
70 HeapBlock<Complex<float>> buffer (n);
72 for (
size_t i = 0; i < n; ++i)
73 buffer.getData()[i] = Complex<float> (in[i], 0.0f);
76 /
static_cast<float> (n));
78 for (
size_t i = 0; i < n; ++i)
79 out[i] = freqConvolution (buffer.getData(),
static_cast<float> (i) * base_freq, n);
84 template <
typename Type>
85 static bool checkArrayIsSimilar (Type* a, Type* b,
size_t n)
noexcept
87 for (
size_t i = 0; i < n; ++i)
88 if (std::abs (a[i] - b[i]) > 1e-3f)
96 static void run (FFTUnitTest& u)
98 Random random (378272);
100 for (
size_t order = 0; order <= 8; ++order)
102 auto n = (1u << order);
104 FFT fft ((
int) order);
106 HeapBlock<float> input (n);
107 HeapBlock<Complex<float>> reference (n), output (n);
109 fillRandom (random, input.getData(), n);
110 performReferenceFourier (input.getData(), reference.getData(), n,
false);
113 zeromem (output.getData(), n * sizeof (Complex<float>));
114 memcpy (
reinterpret_cast<float*
> (output.getData()), input.getData(), n * sizeof (
float));
116 fft.performRealOnlyForwardTransform ((
float*) output.getData());
117 u.expect (checkArrayIsSimilar (reference.getData(), output.getData(), n));
120 zeromem (output.getData(), n * sizeof (Complex<float>));
121 memcpy (
reinterpret_cast<float*
> (output.getData()), input.getData(), n * sizeof (
float));
123 fft.performRealOnlyForwardTransform ((
float*) output.getData(),
true);
124 std::fill (reference.getData() + ((n >> 1) + 1), reference.getData() + n, std::complex<float> (0.0f));
125 u.expect (checkArrayIsSimilar (reference.getData(), output.getData(), (n >> 1) + 1));
127 memcpy (output.getData(), reference.getData(), n * sizeof (Complex<float>));
128 fft.performRealOnlyInverseTransform ((
float*) output.getData());
129 u.expect (checkArrayIsSimilar ((
float*) output.getData(), input.getData(), n));
134 struct FrequencyOnlyTest
136 static void run (FFTUnitTest& u)
138 Random random (378272);
139 for (
size_t order = 0; order <= 8; ++order)
141 auto n = (1u << order);
143 FFT fft ((
int) order);
145 std::vector<float> inout ((
size_t) n << 1), reference ((
size_t) n << 1);
146 std::vector<Complex<float>> frequency (n);
148 fillRandom (random, inout.data(), n);
149 zeromem (reference.data(), sizeof (
float) * ((
size_t) n << 1));
150 performReferenceFourier (inout.data(), frequency.data(), n,
false);
152 for (
size_t i = 0; i < n; ++i)
153 reference[i] = std::abs (frequency[i]);
155 for (
auto ignoreNegative : {
false,
true })
157 auto inoutCopy = inout;
158 fft.performFrequencyOnlyForwardTransform (inoutCopy.data(), ignoreNegative);
159 auto numMatching = ignoreNegative ? (n / 2) + 1 : n;
160 u.expect (checkArrayIsSimilar (inoutCopy.data(), reference.data(), numMatching));
168 static void run (FFTUnitTest& u)
170 Random random (378272);
172 for (
size_t order = 0; order <= 7; ++order)
174 auto n = (1u << order);
176 FFT fft ((
int) order);
178 HeapBlock<Complex<float>> input (n), buffer (n), output (n), reference (n);
180 fillRandom (random, input.getData(), n);
181 performReferenceFourier (input.getData(), reference.getData(), n,
false);
183 memcpy (buffer.getData(), input.getData(), sizeof (Complex<float>) * n);
184 fft.perform (buffer.getData(), output.getData(),
false);
186 u.expect (checkArrayIsSimilar (output.getData(), reference.getData(), n));
188 memcpy (buffer.getData(), reference.getData(), sizeof (Complex<float>) * n);
189 fft.perform (buffer.getData(), output.getData(),
true);
192 u.expect (checkArrayIsSimilar (output.getData(), input.getData(), n));
197 template <
class TheTest>
198 void runTestForAllTypes (
const char* unitTestName)
202 TheTest::run (*
this);
205 void runTest()
override
207 runTestForAllTypes<RealTest> (
"Real input numbers Test");
208 runTestForAllTypes<FrequencyOnlyTest> (
"Frequency only Test");
209 runTestForAllTypes<ComplexTest> (
"Complex input numbers Test");
213static FFTUnitTest fftUnitTest;
UnitTest(const String &name, const String &category=String())
void beginTest(const String &testName)
static constexpr FloatType twoPi