adafruit / Adafruit_ZeroFFT

simple FFT for cortex m0
BSD 3-Clause "New" or "Revised" License
42 stars 18 forks source link

Only real part is present #3

Open GiulioQI opened 6 years ago

GiulioQI commented 6 years ago

Hello, Thank you for the usefull library! i'm using your FFT library to realize a spectrum analyzer. For testing i connect a 150mVpp sinusoidal wave with a 500mV DC value to Arduino SAMD21 DAC A0 and select 1V reference voltage.

The software is doing this:

ISSUE: The amplitude of the BIN relative to the central frequency of the sine was oscillating between ZERO and a correct value at every different acquisition

ANALISYS: I retrive the acquired samples from the serial port and analized with matlab. i compared a 256 samples that show 359 as max fft bin value and 256 samples that show 11 as max fft bin value. Both signal has the same VPP anc VDC. the only difference is the phase... using matlab FFT i plot two different procedure:

The first one show me the correct spectrum and the second one show me the same value as ZEROFFT.

CONCLUSION: Looking at the code i see that the imaginary value are discarded and only the ABS of the real part is performed. I think that a correct ABS of complex number should performed as SQRT(REAL^2+IMG^2). An alternative solution could be to output both real and img parts.

Thank you for your great work.

ghost commented 5 years ago

Hi, I used this library to calculate the real part of the FFT from the Arduino Zero in my project. The project does the FFT on the interferogram collected by the Linear Photodiode array (TSL1402R). Then I calculated the same real FFT by importing the data from the serial monitor to the Matlab. The problem is that the two fft values are totally different. The real part of the FFT from the Matlab is 50 times larger than that calculated from the Arduino Zero. Any suggestions is greatly appreciated. Thank you.

nkonopinski commented 4 years ago

Thanks @GiulioQI. I was having the exact same issue and I thought it was something wrong with my code. Spent way too long trying to debug it. Is there any reason for this function to only return the real part? I would assume most folks running FFTs on Arduinos would want the magnitude returned. It's a simple fix and since this ticket has been open for so long, I'm guessing nobody wants to change the current behavior? For any other unfortunate souls that have arrived here for the same reason, here's a patch to get the magnitude response

diff --git a/fftutil.c b/fftutil.c
index 44794c1..36cafa5 100644
--- a/fftutil.c
+++ b/fftutil.c
@@ -332,10 +332,10 @@ int ZeroFFT(q15_t *source, uint16_t length)
        pSrc = source;
        pOut = scratchData;
        for(int i=0; i<length; i++){
-                 q15_t val = *pOut++;
-                 uint32_t v = abs(val);
+                 q15_t real = *pOut++;
+                 q15_t imaginary = *pOut++;
+                 uint32_t v = sqrt(pow(real, 2) + pow(imaginary,2));
                  *pSrc++ = v;
-                 pOut++; //discard imaginary phase val
          }

        return 0;

Although this does increase the runtime for a 1024 fft from ~10ms to ~60ms. There is an arm function to calculate this, arm_cmplx_mag_q15, but I haven't had success with it yet.

ladyada commented 4 years ago

if you'd like to make a new function as a PR for magnitude, we'd merge it in :)