FFT Spectral Analysis: question about the db values obtained from the FFT bins

Hello All,
I am trying to implement a Synthesia project with Neopixel LEDs, where certain LEDs must glow when a partilcuar frequency or its octave is mapped to the LED. I plan to inplement this with the Arduino Uno board. To start with, I came across multiple forums, and as many suggested, used the FFT library by by musical lab. I did use their fft_adc_serial.pde as a template and modified it after I understood what the code was implementing. (Added more comments and changed a few logic to make it easier for me/someoneelse to understand).

For the audio input to the Uno board, I am using a Parralax sound sensor that takes the input from a Stero playing music and outputs the amplified signal to the Arduino board. I am using the Analog input 0 and using the ADC in this pin to sample the signal presented by the sound sensor to the Uno board. I am using a prescaler of 32, which gives me a sampling frequency of (16000000/32/13) = 38.461kHz. From the Nyquist Theorem the effective bandwidth is half the Sampling freqeuncy = 38.461kHz/2 ~ 19kHz. Since The Audio band is 20Hz to 20kHz, we have chosen the correct sampling frequency. I am using a FFT bin size of 256 samples.

With the circuit in place, I am using the Serial console to output the values stored in decibel values stored in fft_log, after calling the command fft_run() and fft_mag_log(). Here the frequency buckets start from 0hz and eac freqeuncy bin is (19kHz/256) = 74.21Hz. So the first bin starts from 0Hz to 74.21kHz, the second bin starts from 74.21Hz to 148.43Hz and so on.

When I run an audio input signal and print out the values in the serial port, I see the following values as attached in serial_with_600Hz_signal.txt. If I do not have any audio signal, I see the following values as attached in serial_wity_silence text file. Basically both have the almost the same value in th 0Hz-75Hz value. For the bucket with 600-700hz, I see the following values:
Frequency: 600Hz 79 dB
Frequency: 675Hz 68 dB

I had expected a large value in this range. But I do not see it. Was wondering if someone can point out where I am goig wrong?

My Code is placed below:

#define LOG_OUT 1 // use the log output function
#include “FastLED.h”
#include “FFT.h” // include the library

#define FFT_N 256 // set to 256 point fft
#define NUM_LEDS 1
#define DATA_PIN 6
#define CLOCK_PIN 13
#define ANALOG_PIN 0
#define ADC_INTERRUPT_ENABLE 0x10
#define BIT_15_HEX 0x8000
#define SAMPLING_FREQ (16000000/(13*32))

int val = 0; // variable to store the value read
CRGB leds[NUM_LEDS]; // Define the array of leds

void setup() {
Serial.begin(9600); // setup serial
FastLED.addLeds<NEOPIXEL, DATA_PIN> (leds, NUM_LEDS);
DIDR0 = 0x01; // turn off the digital input for adc0
ADMUX = 0x40; // use adc0
/*

  • To get 10bit precision, from 50kHz to 200kHz clock must be supplied to the ADC. The
  • chip runs at 16MHHz. If we were set the prescaler value to 128 → 0b011 as part of the
  • ADPS register value, then we get (16MHz/128) = 125kHz as the ADC Input Clock frequency.
  • Since it takes 13 input clock cycles to get one Audio sample, the effective sampling
  • frequency is 125Khz/13 = 9.6kHz. This is not sufficient as the audio frequency range
  • is from 20Hz to 20KHz.
  • If we choose a prescaler of 32, then the sampling frequency becomes 16000/(32*13) ~ 38KhZ
  • From Nyquist’s Theorem, the effective bandwidth is half the sample rate,= 19KhZ

*/
ADCSRA = 0xe5;

}

void loop() {
//Serial.println(“Start of for loop”);
cli();
while(1){
for (int i = 0 ; i < 512 ; i+=2) { // we need 256 samples that represent the real into 256 bins of the FFT
while(!(ADC_INTERRUPT_ENABLE & ADCSRA)); // wait till the interrupt flag is 0. Which means conversion is in process
ADCSRA = 0xf5; // Set ADIF to 1 and ADSC to 1, as the first conversion was made and we need to be ready for the next conversion
byte low = ADCL; // fetch adc data
byte high = ADCH;
int value = (high << 8) | low; // form into an int
/*

  • The value we have over here is the value from bit to bit 10. We need to shift high 8 times, so that the first two bits (0 and 1)
  • in ADCH now occupy bit 8 and bit 9. We now need to make this value left shifted as to provide scaled values. By left shifting
  • the value by 6, the MSB in ADCH is now at bit 15 and the LSB of ADCL is at bit 6.
    */
    int adc_val = value << 6;

adc_val = (adc_val - BIT_15_HEX); // form into a 16b signed int
fft_input = adc_val; // put real data into even bins

  • fft_input[i+1] = 0; // set odd bins to 0*
  • }*
  • 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_log(); // take the output of the fft*
  • sei();*
    _ /*_
    _ * the 20kHz signal bandwidth,is divided into 256 equal-sized sections, each covering 78.125kHz band_
    _ * we will be printing the decibel level of the input signal at each of these bands._
    _ */_
  • Serial.println(“start”);*
  • for (byte i = 0 ; i < FFT_N/2 ; i++) {*
    Serial.print("Frequency: “); Serial.print(i* ((SAMPLING_FREQ/2)/FFT_N)); Serial.print(” ");
    Serial.println(fft_log_out*); // send out the data to the serial port so I can see what it’s doing*
    * }*

* }*

}
serial_with_silence.txt (5.65 KB)
serial_with 600 Hz sine wave sound.txt (5.99 KB)

One place you are going wrong, is that you have posted code without using code tags. This creates certain problems and obstacles for other forum members. The code tags make the code look

like this

when posting source code files. It makes it easier to read, and can be copied with a single mouse click.
If you have already posted without using code tags, open your message and select “modify” from the pull down menu labelled, “More”, at the lower left corner of the message. Before posting the code, use Ctrl-T in the IDE to reformat the code in a standard format, which makes it easier for us to read. Highlight your code by selecting it (it turns blue), and then click on the “</>” icon at the upper left hand corner. Click on the “Save” button. Code tags can also be inserted manually in the forum text using the [code] and [/code] metatags.

When you are finished that, please read this post:

How to use this forum - please read.

Hi All,
My apologies. Clearly I did not work as hard on the forum ettiquetes, as much as I had on my code. This shall not happen again. That being said, here is the code that is autoformated and within the code blocks.

#define LOG_OUT 1 // use the log output function
#include "FastLED.h"
#include "FFT.h" // include the library


#define FFT_N 256 // set to 256 point fft
#define NUM_LEDS 1
#define DATA_PIN 6
#define CLOCK_PIN 13
#define ANALOG_PIN 0
#define ADC_INTERRUPT_ENABLE 0x10
#define BIT_15_HEX 0x8000
#define SAMPLING_FREQ (16000000/(13*32))

int val = 0;           // variable to store the value read
CRGB leds[NUM_LEDS];   // Define the array of leds

void setup() {
  Serial.begin(9600);          //  setup serial
  FastLED.addLeds<NEOPIXEL, DATA_PIN> (leds, NUM_LEDS);
  DIDR0 = 0x01; // turn off the digital input for adc0
  ADMUX = 0x40; // use adc0
  /*
     To get 10bit precision, from 50kHz to 200kHz clock must be supplied to the ADC. The
     chip runs at 16MHHz. If we were set the prescaler value to 128 -> 0b011 as part of the
     ADPS register value, then we get (16MHz/128) = 125kHz as the ADC Input Clock frequency.
     Since it takes 13 input clock cycles to get one Audio sample, the effective sampling
     frequency is 125Khz/13 = 9.6kHz. This is not sufficient as the audio frequency range
     is from 20Hz to 20KHz.
      If we choose a prescaler of 32, then the sampling frequency becomes 16000/(32*13) ~ 38KhZ
      From Nyquist’s Theorem, the effective bandwidth is half the sample rate,= 19KhZ

  */
  ADCSRA = 0xe5;

}

void loop() {
  //Serial.println("Start of for loop");
  cli();
  while (1) {
    for (int i = 0 ; i < 512 ; i += 2) { // we need 256 samples that represent the real  into 256 bins of the FFT
      while (!(ADC_INTERRUPT_ENABLE & ADCSRA)); // wait till the interrupt flag is 0. Which means conversion is in process
      ADCSRA = 0xf5; // Set ADIF to 1 and ADSC to 1, as the first conversion was made and we need to be ready for the next conversion
      byte low = ADCL; // fetch adc data
      byte high = ADCH;
      int value = (high << 8) | low; // form into an int
      /*
         The value we have over here is the value from bit to bit 10. We need to shift high 8 times, so that the first two bits (0 and 1)
         in ADCH now occupy bit 8 and bit 9. We now need to make this value left shifted as to provide scaled values. By left shifting
         the value by 6, the MSB in ADCH is now at bit 15 and the LSB of ADCL is at bit 6.
      */
      int adc_val = value << 6;

      adc_val = (adc_val - BIT_15_HEX); // form into a 16b signed int
      fft_input[i] = adc_val; // put real data into even bins
      fft_input[i + 1] = 0; // set odd bins to 0
    }
    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_log(); // take the output of the fft
    sei();

    /*
       the 20kHz signal bandwidth,is divided into 256 equal-sized sections, each covering 78.125kHz band
       we will be printing the decibel level of the input signal at each of these bands.
    */
    Serial.println("start");
    for (byte i = 0 ; i < FFT_N / 2 ; i++) {
      Serial.print("Frequency: "); Serial.print(i * ((SAMPLING_FREQ / 2) / FFT_N)); Serial.print(" ");
      Serial.println(fft_log_out[i]); // send out the data to the serial port so I can see what it's doing
    }

    leds[0] = CRGB::Red;
    FastLED.show();
    //delay(500);
    leds[0] = CRGB::Black;
    FastLED.show();
    //delay(500);

  }

}

i have also attached a picture of my Circuit.

The microphone looks like this one from Adafruit https://www.adafruit.com/product/1063

Pete

There are a couple of problems.

You do not appear to be properly converting the ADC values into signed integers, so you either get a large DC offset, or perhaps even complete nonsense. Take a look at the OpenMusicLabs example code.

The output values of fft_log_out are not dB, they are simply the log of whatever amplitudes arise from the input.

HI jremigton,
Thanks for taking a look. My logic does the same thing as the musiclibrary code:
This can be explained with a following example:

a) The Original code:
Let ADCH have the value 010b and ADCL = 11100001b. The decimal equivalent of ADCH is 2 and ADCL is 225. We derieve the following signed integer value:

byte m = ADCL; // fetch adc data
byte j = ADCH;
int k = (j << 8) | m; // form into an int
                             // 2 * 256 + 225 = 737
k -= 0x0200; // form into a signed int 
                   // k = 737 - 512 = 225
k <<= 6; // form into a 16b signed int
              // k =225 * 64 = 14400  --------> (a)

Here is my code

byte low = ADCL; // fetch adc data
byte high = ADCH;
int value = (high << 8) | low; // form into an int
                                          //  2 * 256 + 225 = 737
int adc_val = value << 6;       //  737 * 64 =  47168
                                      
adc_val = (adc_val - BIT_15_HEX); // form into a 16b signed int
                                                 // adc_val = 47168 - 0x8000
                                                 // adc_val = 47168 - 32768
                                                 // adc_val = 14400 -----------------> (b)

I tried the original code, and still see the same issue where the Frequency bins 0 and 75hz have a large value without any music playing. And with music or a single tone, I expected the higher frequency bins to have a large value, which I don’t. For the sake of curiosity I had commented out the fft_reorder and when I played the music, I had seen the value 203 in the 4khz bin. I do not see that again.

I was thinking the values that I ouput are in decibels, based on the following explanation from FFT’s readme section.

“fft_mag_log() - this gives the magnitude of each bin in the fft. it sums
the squares of the imaginary and real, and then takes the square root, and then
takes the log base 2 of that value. so the output is compressed in a logrithmic
fashion, and is essentially in decibels (times a scaling factor).”

To answer el_supremo’s question, I swapped my audio sensor, to see if it works any better. I have both the Parralax and the electrefect sensors for this project. I dont think it should matter, but I could be wrong.

the Frequency bins 0 and 75hz have a large value without any music playing.

This is because you have a large DC offset.

If you subtract the average value of the ADC reading without any music playing, and forget the bit-shifting nonsense, you can correct this.

dB = 10*log(power ratio). If the ratio is not defined, the actual values are meaningless.

hi jremington, If I understood this right, do you want me to set the ADC mode to left shift mode and then just take the value in the ADC resgitser? I havent tried this out, but I think its worth the shot. So, this way, I believe we are taking only the value in the ADCH register and dont care about the value in the ADCL register. Is that correct?

Appreciate all the help. I can sense that i am closer to a solution.

Thanks, Prakash

do you want me to set the ADC mode to left shift mode and then just take the value in the ADC resgitser?

No. Re-read my reply.

jremington: If you subtract the average value of the ADC reading without any music playing, and forget the bit-shifting nonsense, you can correct this.

dB = 10*log(power ratio). If the ratio is not defined, the actual values are meaningless.

hi jremington, Looks like I did not understand this statement. What is this value that needs to get subtracted with the average value of the ADC reading? Is it each of the individual values of the fft_log_out values?

For example, let the average of the array fft_log_out be some value X. Should I then subtract each of the corresponding elements of the array with this value X?

Thanks Prakash

The OP's code looks a bit odd but it does handle the DC offset correctly. The values seen by the FFT will be in the range -32768 to +32767 as they should be. Although, I'm not sure that they need to be shifted up by 6 bits. Perhaps try not shifting them at all and subtract 512 to do the DC offset.

I'm wondering if the microphone circuit is generating enough of a signal.

Pete

Hi Pete,
Thanks for the quick response. I tried using the left shift flag set from the ADC MUX and used only the ADC register for my calculations.

#define LOG_OUT 1 // use the log output function
#include "FastLED.h"
#include "FFT.h" // include the library


#define FFT_N 256 // set to 256 point fft
#define NUM_LEDS 1
#define DATA_PIN 6
#define CLOCK_PIN 13
#define ANALOG_PIN 0
#define ADC_INTERRUPT_ENABLE 0x10
#define BIT_15_HEX 0x8000
#define SAMPLING_FREQ (16000000/(13*32))

int val = 0;           // variable to store the value read
CRGB leds[NUM_LEDS];   // Define the array of leds

void setup() {
  Serial.begin(9600);          //  setup serial
  FastLED.addLeds<NEOPIXEL, DATA_PIN> (leds, NUM_LEDS);
  DIDR0 = 0x01; // turn off the digital input for adc0
  ADMUX = 0x60; // use adc0 and turn on left shifted value for the ADC calculation
  /*
     To get 10bit precision, from 50kHz to 200kHz clock must be supplied to the ADC. The
     chip runs at 16MHHz. If we were set the prescaler value to 128 -> 0b011 as part of the
     ADPS register value, then we get (16MHz/128) = 125kHz as the ADC Input Clock frequency.
     Since it takes 13 input clock cycles to get one Audio sample, the effective sampling
     frequency is 125Khz/13 = 9.6kHz. This is not sufficient as the audio frequency range
     is from 20Hz to 20KHz.
      If we choose a prescaler of 32, then the sampling frequency becomes 16000/(32*13) ~ 38KhZ
      From Nyquist’s Theorem, the effective bandwidth is half the sample rate,= 19KhZ

  */
  ADCSRA = 0xe5;

}

void loop() {
  //Serial.println("Start of for loop");
  cli();
  while (1) {
    for (int i = 0 ; i < 512 ; i += 2) { // we need 256 samples that represent the real  into 256 bins of the FFT
      while (!(ADC_INTERRUPT_ENABLE & ADCSRA)); // wait till the interrupt flag is 0. Which means conversion is in process
      ADCSRA = 0xf5; // Set ADIF to 1 and ADSC to 1, as the first conversion was made and we need to be ready for the next conversion
     int value = ADC - BIT_15_HEX;
      fft_input[i] = value; // put real data into even bins
      fft_input[i + 1] = 0; // set odd bins to 0
    }
    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_log(); // take the output of the fft
    sei();


    FastLED.show();
    Serial.println("start");
    for (byte i = 0 ; i < FFT_N / 2 ; i++) {
      Serial.print("Frequency: "); Serial.print(i * ((SAMPLING_FREQ / 2) / FFT_N)); Serial.print(" ");
      Serial.println(fft_log_out[i]); // send out the data to the serial port so I can see what it's doing
    }

    leds[0] = CRGB::Red;
    FastLED.show();
    //delay(500);
    leds[0] = CRGB::Black;
    FastLED.show();
    //delay(500);

  }

}

I still see the values 220-224 in frequency bin 0-74hz and 200-203 in 75hz to 150hz.

If I use the 10 bits from the ADCH and ADCL registers, the maximum value that I can get from the ADC is (2^10) -1 = 1023, if the values are right shifted. So shouldn’t my offset be 1024 instead of 512?

I haven’t thought from the microphone’s point of view, but with the Parralax sound sensor, I do see a tiny led in the sensor flash, whenever it receives a sound of a particular decibel level. Previously I had used the same circuit without the ADC free run mode but the single capture mode. I used to get some value as I could print them on the screen.

So shouldn't my offset be 1024 instead of 512?

No. The ADC range is 0 to 1023. You want these values to be shifted so that they are centred around zero, so subtract 512 which gives a range of -512 to +511.

I would try to print out the raw ADC values to see if they are changing significantly when there's a change in the sound level at the microphone.

I have a vague memory that if you increase the sampling of the ADC, it reduces the number of significant bits. You may only be getting 8 bits.

Pete

I still see the values 220-224 in frequency bin 0-74hz and 200-203 in 75hz to 150hz.

Again, this is due to a DC offset.
You are not subtracting the average value of the signal, with no audio input.
That value has to be measured for your input circuit.

Here is what I mean for handling the ADC:

byte low = ADCL; // fetch adc data
byte high = ADCH;
int value = (high << 8) | low; // form into an int
value = value - zero_offset; //zero_offset is the average ADC value with no audio input

When you have determined zero_offset properly, the value of the 0 Hz amplitude bin should be about 0 (assuming you are using fft_mag_lin() to determine amplitudes).

The window function spreads the DC offset into neighboring bins.

Hi jremington, I believe this was where I was going wrong. Thanks for pointing this out. I will try this out and inform the forum of my results.

Here is a very simple test to demonstrate the DC offset and the effect that windowing has on it.

The program creates a constant data set and then transforms it.

Run it with and without the “fft_window()” line to see the effect of that operation.

/*
 
 fft_test_constant.ino
 example sketch for testing the fft library.
 This generates a constant data set demonstrating the DC
 offset term. Enable/disable the fft_window() line to see the effect of 
 windowing.
 
 */

// do #defines BEFORE #includes
#define LIN_OUT 1 // use the lin output function
#define FFT_N 32 // set to 32 point fft

#include <FFT.h> // include the library

void setup() {
  Serial.begin(9600); // output on the serial port
}

void loop() {
  int i,k;
  for (i = 0 ; i < FFT_N ; i++) { // create samples
    fft_input[2*i] = 100; // put real data into even bins
    fft_input[2*i+1] = 0; // set odd bins to 0
  }

  fft_window();  //Try with and without this line

// print the windowed data, if desired

/*
for (i=0; i<FFT_N; i++) {
    Serial.print(i);
    Serial.print("       ");
    Serial.println(fft_input[i]); 
  }
*/

  fft_reorder(); // reorder the data before doing the fft
  fft_run(); // process the data using the fft
  fft_mag_lin(); // calculate the magnitude of the output
  // print the frequency index and amplitudes
  Serial.println("bin  amplitude");
  for (i=0; i<FFT_N/2; i++) {
    Serial.print(i);
    Serial.print("       ");
    Serial.println(fft_lin_out[i]);
  }
  Serial.println("Done");
  while(1); //wait here
}

Hi jremington,
As suggested, I am trying to figure out the average zero offset value. To do that, I made some changes to the code. What I am doing is to make the ADC run in the Free running mode, with the ADC value left shifted like my above code and output just the ADC value without any music or sound.

#define LOG_OUT 1 // use the log output function
#include "FastLED.h"
#include "FFT.h" // include the library


#define FFT_N 256 // set to 256 point fft
#define NUM_LEDS 1
#define DATA_PIN 6
#define CLOCK_PIN 13
#define ANALOG_PIN 0
#define ADC_INTERRUPT_ENABLE 0x10
#define BIT_15_HEX 0x8000
#define SAMPLING_FREQ (16000000/(13*32))

int val = 0;           // variable to store the value read
CRGB leds[NUM_LEDS];   // Define the array of leds

void setup() {
  Serial.begin(9600);          //  setup serial
  FastLED.addLeds<NEOPIXEL, DATA_PIN> (leds, NUM_LEDS);
  DIDR0 = 0x01; // turn off the digital input for adc0
  ADMUX = 0x60; // use adc0 and left shifted value
  /*
     To get 10bit precision, from 50kHz to 200kHz clock must be supplied to the ADC. The
     chip runs at 16MHHz. If we were set the prescaler value to 128 -> 0b011 as part of the
     ADPS register value, then we get (16MHz/128) = 125kHz as the ADC Input Clock frequency.
     Since it takes 13 input clock cycles to get one Audio sample, the effective sampling
     frequency is 125Khz/13 = 9.6kHz. This is not sufficient as the audio frequency range
     is from 20Hz to 20KHz.
      If we choose a prescaler of 32, then the sampling frequency becomes 16000/(32*13) ~ 38KhZ
      From Nyquist’s Theorem, the effective bandwidth is half the sample rate,= 19KhZ

  */
  ADCSRA = 0xe5;

}

void loop() {
  //Serial.println("Start of for loop");
  cli();
  while (1) {
    for (int i = 0 ; i < 512 ; i += 2) { // we need 256 samples that represent the real  into 256 bins of the FFT
      loop_until_bit_is_set(ADCSRA, ADIF); // wait till the interrupt flag is 0. Which means conversion is in process
      ADCSRA = 0xf5; // Set ADIF to 1 and ADSC to 1, as the first conversion was made and we need to be ready for the next conversion
      Serial.println(ADC);

    }
    sei();
  }

}

When I tried some iterations of this code, by resetting the board every now and then, I get values that are not very consistent. For example, for one of my tests, the 512 values were almost equal to 4096. After the second reset, the 512 values were close to 3900. After the third reset, the values fell to 2900. After the most current reset, the latest value is now 2300. With six such test results, I calculated the average to be close to 3000. Was wondering if you would recommend the same approach?

hi jremington,
Please disregard my last post. I will try out your DC offset code first and that could help me with my problem.

Thanks
Prakash

hi jremington, From the sample code posted, I got the following result:

Without Windowing
bin  amplitude
0       100
1       0
2       0
3       0
4       0
5       0
6       0
7       0
8       0
9       0
10       0
11       0
12       0
13       0
14       0
15       0
Done

With Windowing
bin  amplitude
0       46
1       27
2       2
3       2
4       0
5       1
6       2
7       3
8       0
9       0
10       0
11       0
12       0
13       1
14       1
15       2
Done

From this and some prior reading of FFT, I came to the conclusion that windowing is necessary so as to prevent spectral leakage and also to ensure the sense of continuity in the audio signals. As we can see with windowing test, some of the signals in other frequency bands have some energy present which would not have been noticed had windowing not been used.

Now I can also confirm one more thing. Even a tiny value of 100 can result in a significant value present in the frequency bins 0 and 1. Is this why we need to subtract this offset from our input audio sampled signal?

And now that I have gone through this exercise, is my approach to calculate the average zero offset value the right approach?

Thanks for all the explanation and the help, especially with the DC offset test code. I believe I have learnt a lot over the course of our correspondence. Appreciate it.

Thanks Prakash

I still see a big value in the frequency bins 0-74hz and 75 to 150hz. This is the code that have used that incorporates the DC offset value:

#define LOG_OUT 1 // use the log output function
#include "FastLED.h"
#include "FFT.h" // include the library


#define FFT_N 256 // set to 256 point fft
#define NUM_LEDS 1
#define DATA_PIN 6
#define CLOCK_PIN 13
#define ANALOG_PIN 0
#define ADC_INTERRUPT_ENABLE 0x10
#define BIT_15_HEX 0x8000
#define SAMPLING_FREQ (16000000/(13*32))
#define DC_OFFSET 3000

int val = 0;           // variable to store the value read
CRGB leds[NUM_LEDS];   // Define the array of leds

void setup() {
  Serial.begin(9600);          //  setup serial
  FastLED.addLeds<NEOPIXEL, DATA_PIN> (leds, NUM_LEDS);
  DIDR0 = 0x01; // turn off the digital input for adc0
  ADMUX = 0x60; // use adc0 and left shifted ADC
  /*
     To get 10bit precision, from 50kHz to 200kHz clock must be supplied to the ADC. The
     chip runs at 16MHHz. If we were set the prescaler value to 128 -> 0b011 as part of the
     ADPS register value, then we get (16MHz/128) = 125kHz as the ADC Input Clock frequency.
     Since it takes 13 input clock cycles to get one Audio sample, the effective sampling
     frequency is 125Khz/13 = 9.6kHz. This is not sufficient as the audio frequency range
     is from 20Hz to 20KHz.
      If we choose a prescaler of 32, then the sampling frequency becomes 16000/(32*13) ~ 38KhZ
      From Nyquist’s Theorem, the effective bandwidth is half the sample rate,= 19KhZ

  */
  ADCSRA = 0xe5;

}

void loop() {
  //Serial.println("Start of for loop");
  cli();
  while (1) {
    for (int i = 0 ; i < 512 ; i += 2) { // we need 256 samples that represent the real  into 256 bins of the FFT
      while (!(ADC_INTERRUPT_ENABLE & ADCSRA)); // wait till the interrupt flag is 0. Which means conversion is in process
      ADCSRA = 0xf5; // Set ADIF to 1 and ADSC to 1, as the first conversion was made and we need to be ready for the next conversion
      /*byte low = ADCL; // fetch adc data
        byte high = ADCH;
        int value = (high << 8) | low; // form into an int
      */
      /*
         The value we have over here is the value from bit to bit 10. We need to shift high 8 times, so that the first two bits (0 and 1)
         in ADCH now occupy bit 8 and bit 9. We now need to make this value left shifted as to provide scaled values. By left shifting
         the value by 6, the MSB in ADCH is now at bit 15 and the LSB of ADCL is at bit 6.
      */
      /*int adc_val = value << 6;

        adc_val = (adc_val - BIT_15_HEX); // form into a 16b signed int
        value -= 0x0200; // form into a signed int
        value <<= 6; // form into a 16b signed int
      */
      int value = ADC - DC_OFFSET;
      fft_input[i] = value; // put real data into even bins
      fft_input[i + 1] = 0; // set odd bins to 0
    }
    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_log(); // take the output of the fft
    sei();


    FastLED.show();
    Serial.println("start");
    for (byte i = 0 ; i < FFT_N / 2 ; i++) {
      Serial.print("Frequency: "); Serial.print(i * ((SAMPLING_FREQ / 2) / FFT_N)); Serial.print(" ");
      Serial.println(fft_log_out[i]); // send out the data to the serial port so I can see what it's doing
    }

    leds[0] = CRGB::Red;
    FastLED.show();
    //delay(500);
    leds[0] = CRGB::Black;
    FastLED.show();
    //delay(500);

  }

}

I have also attached the serial port output with two tests. One had no sound and the other has a 600hz sine wave sound input to the sound sensor. Are we expected to see numbers in the frequency bins 0-74hz and 75-150 hz? Even in the DC offset code, even though we had the same value of 100 at each of the samples, It was the Frequeny bin 0 and 1 that had reading of amplitude magnitude greater than 20. I am I missing something here? Looks like no matter what values you have, the first two bins have a greater value than the other frequency bins. Is this expected?

Thanks
Prakash

DC_offset_no_signal.txt (2.48 KB)

sine_wave_600hz.txt (2.49 KB)