arm_cfft_q15: What am I doing wrong?

pr8x

Member
To color some waveforms I decided to experiment a bit with FFTs:

Code:
 constexpr auto FFTSize = 256;

  // imaginary & real buffer combined
  std::vector<short> fftBuffer(FFTSize * 2 + FFTSize);

    auto fftRealBuffer = fftBuffer.data() + FFTSize * 2;

    for (size_t i = 0; i < numSamples; i += FFTSize) {
      auto samplesToCopy = std::min<size_t>(numSamples - i, FFTSize);

      APC_TRACE(memcpy(fftBuffer.data(), samples.data() + i, samplesToCopy));

      if (samplesToCopy < FFTSize) {
        memset(fftBuffer.data() + samplesToCopy, 0, FFTSize - samplesToCopy);
      }

      APC_TRACE(arm_cfft_q15(&arm_cfft_sR_q15_len256, fftBuffer.data(), 0, 1));
      APC_TRACE(arm_cmplx_mag_q15(fftBuffer.data(), fftRealBuffer, FFTSize));

      Serial.print("FFT:\n\n");
      for (size_t i = 0; i < FFTSize; i++) {
        Serial.printf("%d ", fftRealBuffer[i]);
      }


     //....
     //Omitted, calculate RMS of 3 frequency bands to determine waveform color

    }

However, I only get these results:

FFT:

3066 2745 1941 905 0 543 600 313 0 313 404 255 0 181 255 181 0 0 181 0 0 0 181 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 181 0 0 181 255 181 0 255 362 255 0 443 701 572 0 957 1991 2786

So values only in the lower and higher frequency bins? I checked multiple audio files and they all have the same issue. According to this thread I should use arm_shift_q15 to convert the samples back into q15 before arm_cmplx_mag_q15 and after arm_cmplx_mag_q15. I am not sure about it since the official docs don't seem to mention it? Does anybody know what's happening here? I got similar results with the deprecated radix4_* version.

PS: If anybody has a better way (than FFT) to color waveform based on lows,mids,highs let me know :)
 
q15 is too small for real-world use for FFTs. A 256 point FFT takes 8 stages, and each will lose accuracy due to rounding, so you probably only have 10 bits left, so small value coefficients may simply fall to zero. Try q31 for comparison.

The spectrum is symmetric if you take a real-valued signal and compute the FFT - only with a complex input signal do you get information in the second half of the output spectrum.
 
Back
Top