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)
