@@ -969,10 +969,10 @@ void FFT::perform (const Complex<float>* input, Complex<float>* output, bool inv | |||||
engine->perform (input, output, inverse); | 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) | if (engine != nullptr) | ||||
engine->performRealOnlyForwardTransform (inputOutputData, ignoreNeagtiveFreqs); | |||||
engine->performRealOnlyForwardTransform (inputOutputData, ignoreNegativeFreqs); | |||||
} | } | ||||
void FFT::performRealOnlyInverseTransform (float* inputOutputData) const noexcept | void FFT::performRealOnlyInverseTransform (float* inputOutputData) const noexcept | ||||
@@ -981,18 +981,20 @@ void FFT::performRealOnlyInverseTransform (float* inputOutputData) const noexcep | |||||
engine->performRealOnlyInverseTransform (inputOutputData); | engine->performRealOnlyInverseTransform (inputOutputData); | ||||
} | } | ||||
void FFT::performFrequencyOnlyForwardTransform (float* inputOutputData) const noexcept | |||||
void FFT::performFrequencyOnlyForwardTransform (float* inputOutputData, bool ignoreNegativeFreqs) const noexcept | |||||
{ | { | ||||
if (size == 1) | if (size == 1) | ||||
return; | return; | ||||
performRealOnlyForwardTransform (inputOutputData); | |||||
performRealOnlyForwardTransform (inputOutputData, ignoreNegativeFreqs); | |||||
auto* out = reinterpret_cast<Complex<float>*> (inputOutputData); | 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]); | 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 | } // namespace dsp | ||||
@@ -70,22 +70,22 @@ public: | |||||
As the coefficients of the negative frequencies (frequencies higher than | As the coefficients of the negative frequencies (frequencies higher than | ||||
N/2 or pi) are the complex conjugate of their positive counterparts, | N/2 or pi) are the complex conjugate of their positive counterparts, | ||||
it may not be necessary to calculate them for your particular application. | 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 | 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 | 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. | is true. | ||||
The size of the array passed in must be 2 * getSize(), and the first half | 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 | 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 | 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 | (size / 2) + 1 complex numbers. Both outputs can be passed to | ||||
performRealOnlyInverseTransform() in order to convert it back to reals. | performRealOnlyInverseTransform() in order to convert it back to reals. | ||||
*/ | */ | ||||
void performRealOnlyForwardTransform (float* inputOutputData, | void performRealOnlyForwardTransform (float* inputOutputData, | ||||
bool dontCalculateNegativeFrequencies = false) const noexcept; | |||||
bool onlyCalculateNonNegativeFrequencies = false) const noexcept; | |||||
/** Performs a reverse operation to data created in performRealOnlyForwardTransform(). | /** 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 | /** Takes an array and simply transforms it to the magnitude frequency response | ||||
spectrum. This may be handy for things like frequency displays or analysis. | spectrum. This may be handy for things like frequency displays or analysis. | ||||
The size of the array passed in must be 2 * getSize(). | 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. */ | /** Returns the number of data points that this FFT was created to work with. */ | ||||
int getSize() const noexcept { return size; } | int getSize() const noexcept { return size; } | ||||
@@ -135,7 +135,7 @@ struct FFTUnitTest : public UnitTest | |||||
struct FrequencyOnlyTest | struct FrequencyOnlyTest | ||||
{ | { | ||||
static void run(FFTUnitTest& u) | |||||
static void run (FFTUnitTest& u) | |||||
{ | { | ||||
Random random (378272); | Random random (378272); | ||||
for (size_t order = 0; order <= 8; ++order) | for (size_t order = 0; order <= 8; ++order) | ||||
@@ -144,19 +144,23 @@ struct FFTUnitTest : public UnitTest | |||||
FFT fft ((int) order); | 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) | 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)); | |||||
} | |||||
} | } | ||||
} | } | ||||
}; | }; | ||||