32 Bin FFT to 10kHz Possible

Would like to have 32 bins, about 312 Hz spaced, for a music to light project. THinking that less bins will run faster on a little Nano. Also would like response up to 10kHz since there's a lot of music between 5kHz and 10kHz. Default sample rate is 9kHz but read that can be increased and would need a rate near 20kHz.

Is this possible to do or will I be chasing ghosts? What parameters determine the number of bins and will they be wide bins or sharp with no response between bins?

Of course it's possible. They will be "wide" bins. But the rate at which you can perform transforms is not the same as the sample rate. It depends on processor speed and code efficiency.

This product should help you.

rickso234:
Would like to have 32 bins, about 312 Hz spaced, for a music to light project. THinking that less bins will run faster on a little Nano. Also would like response up to 10kHz since there’s a lot of music between 5kHz and 10kHz. Default sample rate is 9kHz but read that can be increased and would need a rate near 20kHz.

Is this possible to do or will I be chasing ghosts? What parameters determine the number of bins and will they be wide bins or sharp with no response between bins?

The number of bins is determined purely but the order of the FFT. The resolution is (at best) the reciprocal of the period over which you collect the data. In your case with 10 KHz sample rate and 32 bins the resolution is, as you say, 10000/32 i.e. 312 Hz. The Nyquist criteria means that you only get useful information up to half the sample rate so a 10,000 KHz sample rate only gives you 5 KHz bandwidth. Since you only have 312 Hz resolution you will lose most of the bass.

The FFT assumes the data is periodic and this results in a discontinuity at the end points which spreads information from one bin to neighboring bins. One normally uses a Window to help with the discontinuity and, depending on the window being used, this ‘worsens’ the resolution by about 40% (all standard windows have a similar effect). In your case a window would result in about 430 Hz resolution but with values still at 312 Hz separation.

I have just tested a C implementation the Stanford FFT of order 32 and this takes about 15 ms on a Mega2560. This is not an optimized FFT implementation since it does not pre-compute the twiddle factors but since you will have to do other processing as well as do the FFT it is probably about the best you can expect overall. Overall I would be surprised if you can do much better than about 20 frames per second (50 ms per frame). If you want to get much faster than this you will need to find a fixed point block floating point implementation. I wrote one many many years ago for a PDP8e and it is not for the faint hearted.

If you want to get 10 KHz resolution then your sample rate will have to be at least 20 KHz. Most music I have is sampled at 44 KHz.

This is only 7 bands, but they are log spaced: https://www.sparkfun.com/products/10468

takes about 15 ms on a Mega2560.

Would it be the same on a Nano which uses the same 16MHz clock? 15ms is a bit slow as that amount of delay is getting into the noticeable range. Have seen some code that uses fixed point math.

Forgot about that MSGEQ7 chip and believe I've seen Arduino code already written for it, although it doesn't look very difficult to write.

The OpenMusicLabs FFT code for Arduino is highly optimized, and claims slightly over 1 ms for a 64 point (32 bin) calculation.

The example application on that site is not particularly helpful, so I wrote a test program to show that it works as expected for known input data.

Finally, it is not difficult to run the ADC at a higher sample rate, and you can easily get 8 bit resolution sampling at 20 kHz, perhaps even 10 bit.

/*
 fft_test_sine
 example sketch for testing the fft library.
 This generates a simple sine wave data set consisting
 of two frequencies f1 and f2, transforms it, calculates 
 and prints the amplitude of the transform.
 */

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

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

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

void loop() {
  int i,k;
  float f1=2.0,f2=5.0;  //the two input frequencies (bin values)
  for (i = 0 ; i < FFT_N ; i++) { // create samples
    // amplitudes are 1000 for f1 and 500 for f2
    k=1000*sin(2*PI*f1*i/FFT_N)+500.*sin(2*PI*f2*i/FFT_N);
    fft_input[2*i] = k; // 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, it smears
  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(2*fft_lin_out[i]); //*2 for "negative frequency" amplitude
  }
  Serial.println("Done");
  while(1); //wait here
}