FFT output for noise sensor shifts after some time

I am using a noise sensor (ADMP401) along with Arduino Mega. I use openmusiclabs FFT algorithm to convert the noise sensor analog output to frequency domain, then remove the first 30 bins (to remove some board noise), then calculate the rms value of the remaining bins. So, during a period of 10 seconds (which is my polling period), I have a set of 12 rms values from which I take the median value to get the ambient noise equivalent.

Its working fine and I can see the output value responding to noises. I usually get an output of around 7 to 10 for silent conditions. The problem is, for some units, this base value of 7 to 10 shifts to around 2 to 3 after running for some time and then will remain at that lower level. Still the sensor will respond to noises. But since this shifting is happening, I am unable to correlate the output to dB levels.

Has anyone experienced this kind of behavior while working with noise sensors and FFT?

What sampling rate and FFT size are you using?

Pete

Has anyone experienced this kind of behavior while working with noise sensors and FFT?

Most likely not, but without a complete circuit diagram, and the code, one could only guess.

You can be confident that if the FFT output changes, the input has changed.

Hi Pete,

I set the prescaler to 32 and 38.4kHz sampling rate

ADCSRA = bit (ADEN) | bit (ADSC) | bit (ADIF) | bit (ADPS2) | bit (ADPS0)

256 point FFT

This is how the code looks like

void Update_ADMPFFT(){


//Setup bit read
ADCSRA = bit (ADEN) | bit (ADSC) |bit (ADPS2) | bit (ADPS0);
ADMUX = 0x42; // Use A2 where ADMP401 is connected to

while(!(ADCSRA & 0x10)); // Wait for ADC to be ready
// Restart adc, clear flag and  set the prescaler to 32 and 38.4kHz sampling rate
ADCSRA = bit (ADEN) | bit (ADSC) | bit (ADIF) | bit (ADPS2) | bit (ADPS0);

byte m = ADCL; // Fetch adc data
    byte j = ADCH;

    int k = (j << 8) | m; // Form into an int
    k -= 0x0200; // Form into a signed int
    k <<= 6; // Form into a 16b signed int

   fft_input[lCounter] = k; // Put real data into even bins
   fft_input[lCounter+1] = 0; // Set odd bins to 0

    lCounter  = lCounter + 2; // Increment counter until 512

    if (lCounter == 510){
    //Once data is filled in, do FFT

     fft_window(); // Window the data for better frequency response
       fft_reorder(); // Reorder the data before doing the FFT
       fft_run(); // Process the data in the FFT
       fft_mag_lin(); // Take the output of the FFT

       //Filter out the first 30 bins which includes the board noises
       for (byte i = 31; i < FFT_N/2; i++) {
       //Use this after using fft_mag_lin() for finding rms of magnitude power
       rms = rms + (fft_lin_out[i]* fft_lin_out[i]);

          }

       //Find rms value of the remaining 97 bins.
       rms_sum = sqrt(rms/97);


      lCounter = 0;



    }

    //Reset summation variables
    rms = 0;
    rms_sum = 0;

}

Hi jremington,

Confusing part is, it is still responding to noises well. Just that the range shifts from 7-to-10 base value to 2-to-3 base value (silent environment) after running for hours. May be something to do with the electrical characteristics of the supply itself?

~Rahul

May be something to do with the electrical characteristics of the supply itself?

Possibly, or the secret circuit.

There are definitely problems with your code, for example:

    lCounter  = lCounter + 2; // Increment counter until 512

    if (lCounter == 510)

But, what is the point of using the FFT? If all you are doing is removing some low frequency terms, a high pass filter with a resistor and capacitor is all you need.

All you've posted is a snippet of code.
Throwing away the bottom 30 bins of the FFT means that you can only sense noises above about 4500Hz {*}. That removes any low frequency things that go bump in the night plus all human voice, most birdsong, dogs barking. What are you actually listening for?

Your Update_ADMPFFT() function is presumably an interrupt routine, in which case it is not a good idea to do the FFT in the routine.

Pete
{*} Assuming that you do achieve 38.4kHz sampling rate.

Hi jremington,

I am using the counter to check if all the 512 bins have been filled up. Not using it in a for loop because this function is being called from the loop() every 2 ms only.

el_supremo,

Regarding picking up human voices, I am still able to pick up speeches and other patterns. But just concerned about this level shifting which happens once every 2 or 3 hours.

One thing I noticed today is that, when the level shifts, and if I plug the noise sensor out and put it back again, it will go back to normal level again. Does that mean that it is the voltage draw of the sensor which is causing the issue ?

I am using the counter to check if all the 512 bins have been filled up.

They aren't all filled up. The last two contain garbage.

Hi jremington,

Essentialy I am saving 256 samples with this logic

for (int i = 0 ; i < 512 ; i += 2) { // save 256 samples

So the counter starts at 0, increments by 2 and go all the way to 510 (0,2,4 . . . 510) which is 256 samples.

So the counter starts at 0, increments by 2 and go all the way to 510 (0,2,4 . . . 510) which is 256 samples.

Wrong. You check that (counter == 510) AFTER you increment by 2, so the last locations always contain garbage.

    lCounter  = lCounter + 2; // Increment counter until 512

    if (lCounter == 510){