@@ -969,10 +969,10 @@ void FFT::perform (const Complex<float>* input, Complex<float>* output, bool inv | |||
engine->perform (input, output, inverse); | |||
} | |||
void FFT::performRealOnlyForwardTransform (float* inputOutputData, bool ignoreNeagtiveFreqs) const noexcept | |||
void FFT::performRealOnlyForwardTransform (float* inputOutputData, bool ignoreNegativeFreqs) const noexcept | |||
{ | |||
if (engine != nullptr) | |||
engine->performRealOnlyForwardTransform (inputOutputData, ignoreNeagtiveFreqs); | |||
engine->performRealOnlyForwardTransform (inputOutputData, ignoreNegativeFreqs); | |||
} | |||
void FFT::performRealOnlyInverseTransform (float* inputOutputData) const noexcept | |||
@@ -981,18 +981,20 @@ void FFT::performRealOnlyInverseTransform (float* inputOutputData) const noexcep | |||
engine->performRealOnlyInverseTransform (inputOutputData); | |||
} | |||
void FFT::performFrequencyOnlyForwardTransform (float* inputOutputData) const noexcept | |||
void FFT::performFrequencyOnlyForwardTransform (float* inputOutputData, bool ignoreNegativeFreqs) const noexcept | |||
{ | |||
if (size == 1) | |||
return; | |||
performRealOnlyForwardTransform (inputOutputData); | |||
performRealOnlyForwardTransform (inputOutputData, ignoreNegativeFreqs); | |||
auto* out = reinterpret_cast<Complex<float>*> (inputOutputData); | |||
for (int i = 0; i < size; ++i) | |||
const auto limit = ignoreNegativeFreqs ? (size / 2) + 1 : size; | |||
for (int i = 0; i < limit; ++i) | |||
inputOutputData[i] = std::abs (out[i]); | |||
zeromem (&inputOutputData[size], static_cast<size_t> (size) * sizeof (float)); | |||
zeromem (inputOutputData + limit, static_cast<size_t> (size * 2 - limit) * sizeof (float)); | |||
} | |||
} // namespace dsp | |||
@@ -70,22 +70,22 @@ public: | |||
As the coefficients of the negative frequencies (frequencies higher than | |||
N/2 or pi) are the complex conjugate of their positive counterparts, | |||
it may not be necessary to calculate them for your particular application. | |||
You can use dontCalculateNegativeFrequencies to let the FFT | |||
You can use onlyCalculateNonNegativeFrequencies to let the FFT | |||
engine know that you do not plan on using them. Note that this is only a | |||
hint: some FFT engines (currently only the Fallback engine), will still | |||
calculate the negative frequencies even if dontCalculateNegativeFrequencies | |||
calculate the negative frequencies even if onlyCalculateNonNegativeFrequencies | |||
is true. | |||
The size of the array passed in must be 2 * getSize(), and the first half | |||
should contain your raw input sample data. On return, if | |||
dontCalculateNegativeFrequencies is false, the array will contain size | |||
onlyCalculateNonNegativeFrequencies is false, the array will contain size | |||
complex real + imaginary parts data interleaved. If | |||
dontCalculateNegativeFrequencies is true, the array will contain at least | |||
onlyCalculateNonNegativeFrequencies is true, the array will contain at least | |||
(size / 2) + 1 complex numbers. Both outputs can be passed to | |||
performRealOnlyInverseTransform() in order to convert it back to reals. | |||
*/ | |||
void performRealOnlyForwardTransform (float* inputOutputData, | |||
bool dontCalculateNegativeFrequencies = false) const noexcept; | |||
bool onlyCalculateNonNegativeFrequencies = false) const noexcept; | |||
/** Performs a reverse operation to data created in performRealOnlyForwardTransform(). | |||
@@ -99,8 +99,13 @@ public: | |||
/** Takes an array and simply transforms it to the magnitude frequency response | |||
spectrum. This may be handy for things like frequency displays or analysis. | |||
The size of the array passed in must be 2 * getSize(). | |||
On return, if onlyCalculateNonNegativeFrequencies is false, the array will contain size | |||
magnitude values. If onlyCalculateNonNegativeFrequencies is true, the array will contain | |||
at least size / 2 + 1 magnitude values. | |||
*/ | |||
void performFrequencyOnlyForwardTransform (float* inputOutputData) const noexcept; | |||
void performFrequencyOnlyForwardTransform (float* inputOutputData, | |||
bool onlyCalculateNonNegativeFrequencies = false) const noexcept; | |||
/** Returns the number of data points that this FFT was created to work with. */ | |||
int getSize() const noexcept { return size; } | |||
@@ -135,7 +135,7 @@ struct FFTUnitTest : public UnitTest | |||
struct FrequencyOnlyTest | |||
{ | |||
static void run(FFTUnitTest& u) | |||
static void run (FFTUnitTest& u) | |||
{ | |||
Random random (378272); | |||
for (size_t order = 0; order <= 8; ++order) | |||
@@ -144,19 +144,23 @@ struct FFTUnitTest : public UnitTest | |||
FFT fft ((int) order); | |||
HeapBlock<float> inout (n << 1), reference (n << 1); | |||
HeapBlock<Complex<float>> frequency (n); | |||
std::vector<float> inout ((size_t) n << 1), reference ((size_t) n << 1); | |||
std::vector<Complex<float>> frequency (n); | |||
fillRandom (random, inout.getData(), n); | |||
zeromem (reference.getData(), sizeof (float) * ((size_t) n << 1)); | |||
performReferenceFourier (inout.getData(), frequency.getData(), n, false); | |||
fillRandom (random, inout.data(), n); | |||
zeromem (reference.data(), sizeof (float) * ((size_t) n << 1)); | |||
performReferenceFourier (inout.data(), frequency.data(), n, false); | |||
for (size_t i = 0; i < n; ++i) | |||
reference.getData()[i] = std::abs (frequency.getData()[i]); | |||
fft.performFrequencyOnlyForwardTransform (inout.getData()); | |||
u.expect (checkArrayIsSimilar (inout.getData(), reference.getData(), n)); | |||
reference[i] = std::abs (frequency[i]); | |||
for (auto ignoreNegative : { false, true }) | |||
{ | |||
auto inoutCopy = inout; | |||
fft.performFrequencyOnlyForwardTransform (inoutCopy.data(), ignoreNegative); | |||
auto numMatching = ignoreNegative ? (n / 2) + 1 : n; | |||
u.expect (checkArrayIsSimilar (inoutCopy.data(), reference.data(), numMatching)); | |||
} | |||
} | |||
} | |||
}; | |||