Browse Source

FFT: Allow performFrequencyOnlyForwardTransform to ignore negative frequencies

v6.1.6
reuk 3 years ago
parent
commit
bb724761f2
No known key found for this signature in database GPG Key ID: 9ADCD339CFC98A11
3 changed files with 34 additions and 23 deletions
  1. +8
    -6
      modules/juce_dsp/frequency/juce_FFT.cpp
  2. +11
    -6
      modules/juce_dsp/frequency/juce_FFT.h
  3. +15
    -11
      modules/juce_dsp/frequency/juce_FFT_test.cpp

+ 8
- 6
modules/juce_dsp/frequency/juce_FFT.cpp View File

@@ -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


+ 11
- 6
modules/juce_dsp/frequency/juce_FFT.h View File

@@ -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; }


+ 15
- 11
modules/juce_dsp/frequency/juce_FFT_test.cpp View File

@@ -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));
}
} }
} }
}; };


Loading…
Cancel
Save