Need help with FFT!

Hi guys! I need help with a school project. I need to collect the frequency of lung sounds using an electret and FFT microphone, only the frequencies I can pick up are wrong. Any suggestion?

This is my code:

#include "arduinoFFT.h"
 
#define SAMPLES 512                 //Must be a power of 2
#define SAMPLING_FREQUENCY 20000    //Hz, must be less than 10000 due to ADC   //Frequencia mais alta esperada dobrada
 
arduinoFFT FFT = arduinoFFT();
 
unsigned int sampling_period_us;
unsigned long microseconds;
 
double vReal[SAMPLES];
double vImag[SAMPLES];
 
void setup() {
    Serial.begin(115200);
    sampling_period_us = round(1000000*(1.0/SAMPLING_FREQUENCY));
}
 
void loop() {
   
    /*SAMPLING*/
    for(int i=0; i<SAMPLES; i++)
    {
        microseconds = micros();    //Overflows after around 70 minutes!
     
        vReal[i] = analogRead(A1);
        vImag[i] = 0;
     
        while(micros() < (microseconds + sampling_period_us)){
        }
    }
 
    /*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, SAMPLING_FREQUENCY) - 300;
 
    /*PRINT RESULTS*/
    Serial.print("xp - "); Serial.println(peak);  //Print out what frequency is the most dominant.
 
    //for(int i=0; i<(SAMPLES/2); i++)
   // {
        /*View all these three lines in serial terminal to see which frequencies has which amplitudes*/
    //     Serial.print("ff - "); Serial.println((i * 1.0 * SAMPLING_FREQUENCY) / SAMPLES, 1);
    //     Serial.print("xa"); 
    //        Serial.println(vReal[i]);    //View only this line in serial plotter to visualize the bins
    //}
 
  //Serial.println("-");
  //delay(100);

  delayMicroseconds(sampling_period_us);
}

Tkss!!!! =)

What are you running this on?

What is the aim of the project? If it is a futility exercise in using Nano and its ADC for pretended FFT analysis, is one thing. If however you need proper signal processing with good quality FFT analysis, look no further than Arduino - ArduinoSound, I2S microphone and MKR board

I need a project of low-cost embedded systems for pulmonary auscultation, but with the sensors I have, the FFT doesn't have a good accuracy

Please edit your post to add code tags ("</>" post editor button), and tell us which Arduino you are using. Also, post a link to the microphone module.

1 Like

Hi, Arduino Mega2560 and Module MAX9814

You won't be able to sample at 20kHz using that code, on the Mega2560. If you try, the results will be complete nonsense.

Did you not see the comment in this line of code?

#define SAMPLING_FREQUENCY 20000    //Hz, must be less than 10000 due to ADC  

The default analog sample rate on AVR based Arduinos like the Mega is about 9.6 kHz, which is fine for your purpose. However, you must have a low pass filter to make sure that audio signals with frequencies no higher than 4 kHz reach the analog input, or you will have severe artifacts from aliasing.

Please post a link to where you obtained the "Module MAX9814"

1 Like

low cost and quality are normally at the opposite ends of a scale, not that MKR board and I2S mic are unaffordable

1 Like

You need to increase the ADC sampling rate.

May be this help little.

No, the OP does not need to do that.

During pulmonary auscultation, the sounds will generally in the range of 60 Hz to 1000 Hz. So the default ADC sample rate of just under 10 kHz is fine. A low pass filter is needed, though.

From https://www.atsjournals.org/doi/10.1164/ajrccm.162.3.9905104

In subjects with healthy lungs, the frequency range of the vesicular breathing sounds extends to 1,000 Hz, whereas the majority of the power within this range is found between 60 Hz and 600 Hz (7, 11). Other sounds, such as wheezing or stridor, can sometimes appear at frequencies above 2,000 Hz (7).

I was thinking about using INMP441, it has a low pass filter, what do you think? Of course, I would have to use esp32. The MAX9814 module has only one amplifier.

I would probably use a Sallen-Key active low pass filter and a microphone like you have. Such filters are really simple to make, using about six inexpensive components on a piece of perfboard.

Example:

Design info:

Any Arduino, even an Uno, would be fine for collecting the low frequency audio data. The question is where do you put the result.

1 Like

Thank you so much for all your help!! Just one more question, do you think that by setting up this filter I can capture lower frequencies like 60Hz???

A low pass filter passes signals from zero Hz (DC) to the upper cutoff (roughly speaking).

Response curve of first and second order filters:

Capture

A Sallen Key low pass filter is second order.

Personally I'd prefer the MAX9814 electret module (link above) - the adafruit looks to be in a convenient form for auscultation and the amp should be able to give good output to feed to a s&k filter.

The LM358 op amp is a poor choice. I'd suggest the mcp6002 which will run happily from a single supply from 5V or even 3.6V.

You could consider using an 8266 NODE or ESP32 for better processing power and storage - the DREADFUL adc would not be an issue as you would be using it in the middle of its range.

Okay. I just saw in the code.
define SELECTION FREQUENCY 20000

That board has only 8k of RAM, this might be a show-stopper if you want good frequency resolution.

For instance if you want 5Hz resolution and are sampling at 20kHz, you'll need a 4096 point FFT. And in fact as you'll need to apply a spectral window the resolution will be even lower as windows widen the peaks.