(Possible Bug) JUCE FFT produces small Nyquist signal during Inverse Transform

Hi all!

I’ve been working with juce::dsp::FFT recently and I’ve encountered what may possibly be a bug. At first I attributed it to a floating-point rounding error, but I’m beginning to believe there may be something more fundamental going on here.

Behavior:

When passed a fully-zeroed buffer of FFT data, the JUCE FFT returns time-domain data with a small, but non-negligible (?) Nyquist frequency signal present.

Example:

All values were read during an LLDB debugging session. These readings are from the same buffer, before and after a single call to performRealOnlyInverseTransform(). Buffer size is 2048.

  // buffer: pre-transform
  (float) [0] = 0
  (float) [1] = 0
  (float) [2] = 0
  (float) [3] = 0
  ...
  // buffer: post-transform
  (float) [0] = 0.000221714377
  (float) [1] = -0.000221714377
  (float) [2] = 0.000221714377
  (float) [3] = -0.000221714377
  ... 
  // this pattern repeats to the end of the buffer

The value in this repeating nyquist signal (i.e. its amplitude) seem to be different every time I run this, but the pattern is always the same — one number, alternating positive and negative every sample. Is this enough to chock up to floating point rounding error? I’m not familiar enough with the vDSP implementation of the FFT algorithm to know where such errors could crop up.

This could also easily be from a simple oversight on my part, hence this being a possible bug report. Thank you in advance for any help you can provide with this!

My first reaction is to take these number seriously, they are certainly not small enough to neglect.

Maybe this is related to some tweaks in the class related to DC and Nyquist, where and how they are stored in the forward result and the input for the inverse? Wouldn’t surprise me, as there are some confusing tweaks in the code for this. I am not using this class for FFTs.

1 Like

Because I’m on Mac, dsp::FFT is defaulting to the vDSP engine—I did notice in the code for that, the Nyquist bin (or specifically just the magnitude) is shuffled to the float index [1] as vDSP uses the same tactic as PFFFT, i.e. storing the Nyquist amplitude where the DC phase would be stored if it wasn’t always 0.

Looking back at it again, I’m realizing this shuffling of the Nyquist amplitude only occurs in the code for the inverse transform, which either means this is a bug or there’s some quirk of how vDSP accepts/returns data that I’m not understanding. Thank you so much for the advice!

A step forward, great :slight_smile:
The API for vDSP can be confusing, also with the strides, etc. I believe the API also goes back some 30-40 years, back into Fortran years.

1 Like

For any who come to this post with a similar issue, it ended up being user error — we were passing a buffer of size N and not 2*N, meaning the nyquist bin and above technically outside our allocated heap block. If you’re having a similar issue and also getting a lot of Incorrect checksum for freed object crashes, check your buffer sizes!!!

1 Like