NaN's from frequency detection

Hello all,

I'm attempting to use an arduino board to continuously detect a (only semi-accurate) peak frequency, with the hope of eventually having the frequency detected control some lights. I've been trying to do so using the below code, which I found from a tutorial on youtube, however whenever I run it, it will only print a frequency for maybe 10-15 lines, then it continuously prints nan's, until I reset the board.

Is there a way to continuously calculate peak frequency using MajorPeak() on an Arduino, without running into this NaN issue (or without having to reset the board everytime)? The code and equipment I'm using is posted below.

Equipment
Arduino Uno R3
Electrect Microphone Amplifier MAX4466 (powered by arduino board, 5V, and connected to A0)

Code

#include "arduinoFFT.h"

#define samples 128
#define Fs 2048

arduinoFFT FFT = arduinoFFT();

unsigned int FsPeriod;
unsigned long ms;

double vReal[samples];
double vImag[samples];

void setup() {
  Serial.begin(115200);
  FsPeriod = round(1e6 * (1.0 / Fs)); //period in ms

}

void loop() {
  
  for (int i = 0; i < samples; i++) {

    ms = micros(); //num seconds since board began

    vReal[i] = analogRead(A0); //Store Analog data
    vImag[i] = 0;

    // wait FsPeriod seconds
    while (micros() < (ms + FsPeriod)) {
      // do nothing
    }

    // Compute FFT
    FFT.Windowing(vReal, samples, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
    FFT.Compute(vReal, vImag, samples, FFT_FORWARD);
    FFT.ComplexToMagnitude(vReal, vImag, samples);

    double peak = FFT.MajorPeak(vReal, samples, Fs);
    Serial.println(peak);

    delay(250);

  }
}

Any other help on this is appreciated, as FFT and handling audio is a bit new to me. Thanks

You need to collect a full array of samples prior to computing the FFT. That is, the "for loop" closing bracket should be prior to the comment "// Compute FFT".

Yes, you mis-nested things.

step 1, populate the FFT array fully.
step 2, call the FFT on the whole array.
step 3, analyze the frequency bins.

Thus:

void loop() {
 
  for (int i = 0; i < samples; i++) {

    ms = micros(); //num seconds since board began

    vReal[i] = analogRead(A0); //Store Analog data
    vImag[i] = 0;
  }

  // wait FsPeriod seconds
  while (micros() - ms < FsPeriod) {   // ALSO FIXED WRAPAROUND ISSUE
    // do nothing
  }
  ms += FsPeriod ;

  // Compute FFT
  FFT.Windowing(vReal, samples, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
  FFT.Compute(vReal, vImag, samples, FFT_FORWARD);
  FFT.ComplexToMagnitude(vReal, vImag, samples);

  double peak = FFT.MajorPeak(vReal, samples, Fs);
  Serial.println(peak);

  delay(250);

}

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.