Pages: [1]   Go Down
Author Topic: Help with FFFT of an Array  (Read 584 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 9
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am busy implemeting an FFT routine on an Audio project. I am using the FFFT.h Library and need to trigger an FFT only when a set AnalogRead threshold has been exceeded. The FFT buffer should only be filled with samples when triggered and it should only do so for a set number of itterations (not yet set in the code)

The original code does not accept analogRead() statements, i have tried it every other way. Must be the way the ADC has been set-up but it works continiously and provides the correct data per frequency bin.

Code:
/*
This Example acquire analog signal from A0 of Arduino, and Serial out to Processing application to visualize.
Tested with preamplified audio data. Take a look at http://www.youtube.com/watch?v=drYWullBWcI

Analog signal is captured at 9.6 KHz, 64 spectrum bands each 150Hz which can be change from adcInit()
Load the this file to Arduio, run Processing application.

Original Fixed point FFT library is from ELM Chan, http://elm-chan.org/works/akilcd/report_e.html
Ported to the library and demo codes are from AMurchick http://arduino.cc/forum/index.php/topic,37751.0.html
Processing code is from boolscott http://boolscott.wordpress.com/2010/02/04/arduino-processing-analogue-bar-graph-2/
*/


#include <stdint.h>
#include <ffft.h>


#define  IR_AUDIO  0 // ADC channel to capture


volatile  byte  position = 0;
volatile  long  zero = 0;

int16_t capture[FFT_N]; /* Wave captureing buffer */
complex_t bfly_buff[FFT_N]; /* FFT buffer */
uint16_t spektrum[FFT_N/2]; /* Spectrum output buffer */

void setup()
{
  Serial.begin(57600);
  adcInit();
  adcCalb();
}

void loop()
{
  if (position == FFT_N)
  {
    fft_input(capture, bfly_buff);
    fft_execute(bfly_buff);
    fft_output(bfly_buff, spektrum);

    for (byte i = 0; i < 64; i++){
      Serial.print(",");
    if (spektrum[i]>10){
      Serial.print(spektrum[i]);
      }else{
        Serial.print("_");
      }
    }
    Serial.println("");
   position = 0;
   }
}

// free running ADC fills capture buffer
ISR(ADC_vect)
{
  if (position >= FFT_N)
    return;
 
  capture[position] = ADC + zero;
  if (capture[position] == -1 || capture[position] == 1)
    capture[position] = 0;

  position++;
}
void adcInit(){
  /*  REFS0 : VCC use as a ref, IR_AUDIO : channel selection, ADEN : ADC Enable, ADSC : ADC Start, ADATE : ADC Auto Trigger Enable, ADIE : ADC Interrupt Enable,  ADPS : ADC Prescaler  */
  // free running ADC mode, f = ( 16MHz / prescaler ) / 13 cycles per conversion
  ADMUX = _BV(REFS0) | IR_AUDIO; // | _BV(ADLAR);
//  ADCSRA = _BV(ADSC) | _BV(ADEN) | _BV(ADATE) | _BV(ADIE) | _BV(ADPS2) | _BV(ADPS1) //prescaler 64 : 19231 Hz - 300Hz per 64 divisions
  ADCSRA = _BV(ADSC) | _BV(ADEN) | _BV(ADATE) | _BV(ADIE) | _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0); // prescaler 128 : 9615 Hz - 150 Hz per 64 divisions, better for most music
  sei();
}
void adcCalb(){
  Serial.println("Start to calc zero");
  long midl = 0;
  // get 2 meashurment at 2 sec
  // on ADC input must be NO SIGNAL!!!
  for (byte i = 0; i < 2; i++)
  {
    position = 0;
    delay(100);
    midl += capture[0];
    delay(900);
  }
  zero = -midl/2;
  Serial.println("Done.");
}

My code provides me with garbage numbers in the lower bins from 1 up and it does not seem to fill the data to the correct bins. I am implementing Fast ADC instead of an unterupt Timer as in the original code, could this be the problem?

Code:
#include <stdint.h>
#include <ffft.h>

// Fast ADC defined
#define FASTADC 1

// Fast ADC defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif


int AnalogVal=0;
volatile  byte  position = 0;
volatile  long  zero = 0;

int16_t capture[FFT_N];                 /* Spectrum input Array */
complex_t bfly_buff[FFT_N]; /* FFT buffer */
uint16_t spektrum[FFT_N/2]; /* Spectrum output buffer */

 
void setup()
{
Serial.begin(57600);
calibrateADC();
}

void loop()
{
#if FASTADC
  // set prescale to 16
 sbi(ADCSRA,ADPS2) ;
 cbi(ADCSRA,ADPS1) ;
 cbi(ADCSRA,ADPS0) ;
#endif
sei();

 AnalogVal=analogRead(0);
 if (AnalogVal>=600){// trigger to start getting samples
    FillArray();
 }
}

void FillArray()
{
  position=0;
 
  for (byte i = 0; i < FFT_N; i++){
  int Val= analogRead(A0); 
  capture[i] = ADC + zero;
  position++;
  }
  DoFFT();
}


void DoFFT()
{
if (position == FFT_N)
  {
    fft_input(capture, bfly_buff);
    fft_execute(bfly_buff);
    fft_output(bfly_buff, spektrum);
  }
  DoPrint();
}

void DoPrint()
{
   for (byte p = 0; p < 64; p++){
   Serial.print(","); 
   Serial.print(spektrum[p]);// print the 64 frequency bins
   }
   
   //int samples = endtime/64;
   Serial.println("");
   //Serial.println(endtime);// Total milliseconds to get 128 samples
   //Serial.println(samples);// Sample period in milliseconds
   position = 0;
}


void calibrateADC(){
  Serial.println("Start to calc zero");
  long midl = 0;
  // get 2 meashurment at 2 sec
  // on ADC input must be NO SIGNAL!!!
  for (byte i = 0; i < 2; i++)
  {
    position = 0;
    delay(100);
    midl += capture[0];
    delay(900);
  }
  zero = -midl/2;
  Serial.println("Done.");
}

I am new to FFT etc and I will appreciate any help in this matter
Logged

Pages: [1]   Go Up
Jump to: