Go Down

Topic: Help using ArduinoFFT (Read 15639 times) previous topic - next topic

el_supremo

Quote
the 0th frequency is the most dominant, and the 128th frequency is the least dominant


No, that's not it at all. As g_u_e_s_t has explained, each bin represents a range of frequencies. The 0th bin has the amplitude of the zero frequency (DC) component of the signal. The next bin will have the amplitude of frequencies around 150Hz, then 300Hz etc. up to the 127th bin with the amplitude of frequencies around 19050Hz.
If you want to know the frequency with the highest amplitude you would have to search the array to find the highest amplitude and then the index of that entry multiplied by 150 gives its frequency.

Pete
Don't send me technical questions via Private Message.

g_u_e_s_t

to find the highest amplitude, you can go through and check each value, saving the largest you have found.  for example:

Code: [Select]

int j = 0;
int k;
for (int i = 0; i < FHT_N/2; i++) {
  if (fht_log_out[i] > j) {
    j = fht_log_out[i];
    k = i;
  }
}
Serial.println(k);


again, this just gives you the bin number. you will need to multiply by 150 to get the frequency.

austincb90

Arvis . Perfect thank you. Rock on

austincb90

el_supremo:
Thanksyou this clarified a fundamental  misunderstanding i had with the code i.e. bins vs actual frequency.


austincb90

g_u_e_s_t: thanks very much for taking the time to post the code.

very much appreciated.

austincb90

#20
Jul 26, 2013, 10:31 pm Last Edit: Jul 26, 2013, 10:45 pm by austincb90 Reason: 1
The highest amplitude bin code seems to be working now ( thank you g_u_e_s_t)

I believe my only remaining issue is that I need to reduce the bin increment size.
I am using is to detect the frequency of a strobing  light, and  since a strobing light at all realistic frequencies will likely fall below 150hz, thus all frequencies will lie in bin 0 and I am unable to see any differentiation among the different strobe frequencies.  and for clarity is again shown below:
Code: [Select]
/*
fht_adc.pde
guest openmusiclabs.com 9.5.12
example sketch for testing the fht library.
it takes in data on ADC0 (Analog0) and processes them
with the fht. the data is sent out over the serial
port at 115.2kb.  there is a pure data patch for
visualizing the data.
*/

#define LOG_OUT 1 // use the log output function
#define FHT_N 256 // set to 256 point fht

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

void setup() {
 Serial.begin(115200); // use the serial port
 TIMSK0 = 0; // turn off timer0 for lower jitter
 ADCSRA = 0xe5; // set the adc to free running mode
 ADMUX = 0x40; // use adc0
 DIDR0 = 0x01; // turn off the digital input for adc0
}

void loop() {
 while(1) { // reduces jitter
   cli();  // UDRE interrupt slows this way down on arduino1.0
   for (int i = 0 ; i < FHT_N ; i++) { // save 256 samples
     while(!(ADCSRA & 0x10)); // wait for adc to be ready
     ADCSRA = 0xf5; // restart adc
     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
     fht_input[i] = k; // put real data into bins
   }
   fht_window(); // window the data for better frequency response
   fht_reorder(); // reorder the data before doing the fht
   fht_run(); // process the data in the fht
   fht_mag_log(); // take the output of the fht
   sei();
   Serial.write(255); // send a start byte
   Serial.println("here starts the list");
  int j = 0;
int k;
for (int i = 0; i < FHT_N/2; i++) {
 if (fht_log_out[i] > j) {
   j = fht_log_out[i];
   k = i;
 }
}
Serial.println(k);
   Serial.flush();
 }
}




TLDR: how do i reduce the size of my bins? , perhaps so that each bin is ideally only 2hz instead of 150 hz.


Again I have extreme gratitude to those of you who have  helped me

g_u_e_s_t

there are only 2 ways to reduce the bin size: 1. increase the number of bins, 2. decrease the sampling frequency.  since you are already using FHT_N = 256, you can't go any higher in terms of number of bins.  but, since you don't care about frequencies above 150Hz, you can easily drop the sampling rate.  that is done with ADCSRA.  the last 3 bits set the rate.  if you set it to 7, the slowest rate, you get /128.  so sampling frequency is 16MHz/128/13 = 9.6kHz, and each bin is therefore 37Hz.  this is probably not slow enough for your application, so you will have to set up the ADC another way.  one way is to setup a timer to trigger the ADC, and another is to use a delay loop.  the delay loop is easier, so i will show that.

Code: [Select]

void setup() {
  Serial.begin(115200); // use the serial port

/*  dont do any of this, especially the TIMSK0 business
     also got rid of cli() and sei() below as analogRead might need the interrupts?
  TIMSK0 = 0; // turn off timer0 for lower jitter
  ADCSRA = 0xe5; // set the adc to free running mode
  ADMUX = 0x40; // use adc0
  DIDR0 = 0x01; // turn off the digital input for adc0
*/
}

void loop() {
  while(1) { // reduces jitter
    for (int i = 0 ; i < FHT_N ; i++) { // save 256 samples
      fht_input[i] = analogRead(0); // put real data into bins
      delay(1); // delay 1ms betwee samples
    }
    fht_window(); // window the data for better frequency response
    fht_reorder(); // reorder the data before doing the fht
    fht_run(); // process the data in the fht
    fht_mag_log(); // take the output of the fht
    Serial.write(255); // send a start byte
    Serial.println("here starts the list");
   int j = 0;
int k;
for (int i = 0; i < FHT_N/2; i++) {
  if (fht_log_out[i] > j) {
    j = fht_log_out[i];
    k = i;
  }
}
Serial.println(k);
    Serial.flush();
  }
}


this will take a sample every 1ms, so 1kHz sampling rate, and therefore 4Hz bin size.  on the down side, it takes 256ms to get a full set of samples, so its slower, but this is a neccessary  tradeoff.  to get finer resolution, you have to take longer.

austincb90

wow , thank you so much g_u_e_s_t. I want to genuinely thank you for your generosity in helping me.
the monitor is certainly responding. the code uploads perfectly. Especially as a beginner, I would still be stuck at square 1 without your help. Thank you!

Something still seems to be amiss . Just so i am sure i understand, a bin value of "0" corresponds to 0-4hz, and a bin value of "1" corresponds to 4-8 hz correct?

Strangely, in a blackened room with the photresistor covered a value of 1 is displayed. when i subject to the photoresistor to a strobe of 8 hz pretty consistently displays a value of "0". And as soon as the strobe is cutoff, the monitor proceeds to display 1's. Occasionly while the strobe is on perhaps every 5th value may read "1" and about every 20th value correctly displays a "2" , although the strobe light frequency goes unchanged. Im definitely puzzled.

Again I cant thank you enough g_u_e_s_t

g_u_e_s_t

a lot of how it works depends upon your signal coming in, and what the circuit is like.  bins 0, 1, and probably 2 as well have a lot of the DC signal in them (bin 0 because it is DC, and the other ones because there is a bit bleed).  you can either filter your signal to minimize the amount of DC coming in, or just ignore those bins.  for example, if you know the lowest frequency you will probably see is 4Hz, dont bother checking bin 0 or bin 1 in the max checking loop.  start with i = 2.

for very slow things, often measuring the time between signals is easier and more accurate.  you could put your photoresistor through a gain circuit, so that its mostly all on (5v) when there is light, and mostly all off (0v) when there is no light.  you then just monitor the pin, and when it goes high, you start counting.  you then wait for it to go low, and go high again, and then stop counting.  the time it took between high transitions is the period, and the frequency is just 1/period.

Arvis

btw I'm making this together with a LED matrix using 4 shift registers 74hc595.

Is there any way that
Code: [Select]

    cli();  // UDRE interrupt slows this way down on arduino1.0
    for (int i = 0 ; i < FHT_N ; i++) { // save 256 samples
      while(!(ADCSRA & 0x10)); // wait for adc to be ready
      ADCSRA = 0xf5; // restart adc
      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
      fht_input[i] = k; // put real data into bins
    }
    fht_window(); // window the data for better frequency response
    fht_reorder(); // reorder the data before doing the fht
    fht_run(); // process the data in the fht
    fht_mag_log(); // take the output of the fht
    sei();

This part could somehow make one line of LEDs (one pin of a shift register) being constantly set to HIGH, even when the latch pin is LOW?
Without that part of the code my LED matrix functions normally^ but then I can't get the frequency/amplitude data.

g_u_e_s_t

its most likely the interrupt stuff, which isnt really necessary.  try it without it and see what happens

Code: [Select]

    for (int i = 0 ; i < FHT_N ; i++) { // save 256 samples
      while(!(ADCSRA & 0x10)); // wait for adc to be ready
      ADCSRA = 0xf5; // restart adc
      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
      fht_input[i] = k; // put real data into bins
    }
    fht_window(); // window the data for better frequency response
    fht_reorder(); // reorder the data before doing the fht
    fht_run(); // process the data in the fht
    fht_mag_log(); // take the output of the fht

Arvis

Nothing changes.
I've noticed that the problem is reduced (not solved however - one line is still brighter than the others, just not as much) by setting
#define FHT_N 256 to #define FHT_N 16

g_u_e_s_t

can you post the rest of your code?  the FHT takes a while to run, so its probably messing up the timing on when the LEDs are set.

Arvis

Sure, here is the code:
http://pastebin.com/sJhK5j40

g_u_e_s_t

it looks like the way you set how long an LED is on for, is by the amount of time it takes to run 8 clock() functions.  the reason why the last row is brighter than the rest, is because it also has to run the fht() function, so it takes much longer.  the easiest fix, is to put in 1 more row, which is a blank row, and write it out to the LEDs.  that way all of your data rows will be on for the same time, and then there will be a blank row (which you can not see) which will be on for longer.

Go Up