35 :
UnitTest (
"FFT", UnitTestCategories::dsp)
38 static void fillRandom (
Random& random, Complex<float>* buffer,
size_t n)
40 for (
size_t i = 0; i < n; ++i)
41 buffer[i] = Complex<float> ((2.0f * random.
nextFloat()) - 1.0f,
45 static void fillRandom (
Random& random,
float* buffer,
size_t n)
47 for (
size_t i = 0; i < n; ++i)
48 buffer[i] = (2.0f * random.
nextFloat()) - 1.0f;
51 static Complex<float> freqConvolution (
const Complex<float>* in,
float freq,
size_t n)
53 Complex<float> sum (0.0, 0.0);
54 for (
size_t i = 0; i < n; ++i)
55 sum += in[i] * exp (Complex<float> (0,
static_cast<float> (i) * freq));
60 static void performReferenceFourier (
const Complex<float>* in, Complex<float>* out,
61 size_t n,
bool reverse)
64 /
static_cast<float> (n));
66 for (
size_t i = 0; i < n; ++i)
67 out[i] = freqConvolution (in,
static_cast<float>(i) * base_freq, n);
70 static void performReferenceFourier (
const float* in, Complex<float>* out,
71 size_t n,
bool reverse)
75 for (
size_t i = 0; i < n; ++i)
76 buffer.
getData()[i] = Complex<float> (in[i], 0.0f);
79 /
static_cast<float> (n));
81 for (
size_t i = 0; i < n; ++i)
82 out[i] = freqConvolution (buffer.
getData(),
static_cast<float>(i) * base_freq, n);
87 template <
typename Type>
88 static bool checkArrayIsSimilar (Type* a, Type* b,
size_t n)
noexcept
90 for (
size_t i = 0; i < n; ++i)
91 if (std::abs (a[i] - b[i]) > 1e-3f)
103 for (
size_t order = 0; order <= 8; ++order)
105 auto n = (1u << order);
107 FFT fft ((
int) order);
112 fillRandom (random, input.
getData(), n);
113 performReferenceFourier (input.
getData(), reference.getData(), n,
false);
116 zeromem (output.
getData(), n * sizeof (Complex<float>));
117 memcpy (
reinterpret_cast<float*
> (output.
getData()), input.
getData(), n * sizeof (
float));
120 u.
expect (checkArrayIsSimilar (reference.getData(), output.
getData(), n));
123 zeromem (output.
getData(), n * sizeof (Complex<float>));
124 memcpy (
reinterpret_cast<float*
> (output.
getData()), input.
getData(), n * sizeof (
float));
127 std::fill (reference.getData() + ((n >> 1) + 1), reference.getData() + n, std::complex<float> (0.0f));
128 u.
expect (checkArrayIsSimilar (reference.getData(), output.
getData(), (n >> 1) + 1));
130 memcpy (output.
getData(), reference.getData(), n * sizeof (Complex<float>));
142 for (
size_t order = 0; order <= 8; ++order)
144 auto n = (1u << order);
146 FFT fft ((
int) order);
151 fillRandom (random, inout.getData(), n);
152 zeromem (reference.
getData(), sizeof (
float) * (n << 1));
153 performReferenceFourier (inout.getData(), frequency.
getData(), n,
false);
155 for (
size_t i = 0; i < n; ++i)
160 u.
expect (checkArrayIsSimilar (inout.getData(), reference.
getData(), n));
171 for (
size_t order = 0; order <= 7; ++order)
173 auto n = (1u << order);
175 FFT fft ((
int) order);
179 fillRandom (random, input.getData(), n);
180 performReferenceFourier (input.getData(), reference.
getData(), n,
false);
182 memcpy (buffer.getData(), input.getData(), sizeof (Complex<float>) * n);
183 fft.
perform (buffer.getData(), output.getData(),
false);
185 u.
expect (checkArrayIsSimilar (output.getData(), reference.
getData(), n));
187 memcpy (buffer.getData(), reference.
getData(), sizeof (Complex<float>) * n);
188 fft.
perform (buffer.getData(), output.getData(),
true);
191 u.
expect (checkArrayIsSimilar (output.getData(), input.getData(), n));
196 template <
class TheTest>
197 void runTestForAllTypes (
const char* unitTestName)
201 TheTest::run (*
this);
206 runTestForAllTypes<RealTest> (
"Real input numbers Test");
207 runTestForAllTypes<FrequencyOnlyTest> (
"Frequency only Test");
208 runTestForAllTypes<ComplexTest> (
"Complex input numbers Test");
212static FFTUnitTest fftUnitTest;
Very simple container class to hold a pointer to some data on the heap.
ElementType * getData() const noexcept
Returns a raw pointer to the allocated data.
A random number generator.
float nextFloat() noexcept
Returns the next random floating-point number.
This is a base class for classes that perform a unit test.
UnitTest(const String &name, const String &category=String())
Creates a test with the given name and optionally places it in a category.
void beginTest(const String &testName)
Tells the system that a new subsection of tests is beginning.
void expect(bool testResult, const String &failureMessage=String())
Checks that the result of a test is true, and logs this result.
Performs a fast fourier transform.
void performRealOnlyInverseTransform(float *inputOutputData) const noexcept
Performs a reverse operation to data created in performRealOnlyForwardTransform().
void performRealOnlyForwardTransform(float *inputOutputData, bool dontCalculateNegativeFrequencies=false) const noexcept
Performs an in-place forward transform on a block of real data.
void perform(const Complex< float > *input, Complex< float > *output, bool inverse) const noexcept
Performs an out-of-place FFT, either forward or inverse.
void performFrequencyOnlyForwardTransform(float *inputOutputData) const noexcept
Takes an array and simply transforms it to the magnitude frequency response spectrum.
Commonly used mathematical constants.
void runTest() override
Implement this method in your subclass to actually run your tests.