0

I wrote this code that inputs audio from a jack (DC offset at 2.5V), performs the fft on a portion of the data, and then outputs a signal to an LED light strip dependent upon which frequency has the highest magnitude. It works but it would be nice if it was faster. Can anyone help out?

#include <arduinoFFT.h>
#include <FastLED.h>

arduinoFFT FFT = arduinoFFT();

const uint16_t samples = 128; //This value MUST ALWAYS be a power of 2
const double samplingFrequency = 16000;
double vReal[samples];
double vImag[samples];

int freqBounds[] = {0,300,500,800,2000,8000};

int colorValue = 0;
int sensorValue = 0;

#define SCL_INDEX 0x00
#define SCL_TIME 0x01
#define SCL_FREQUENCY 0x02
#define SCL_PLOT 0x03

#define LED_PIN   7
#define NUM_LEDS  5

CRGB leds[NUM_LEDS];

void setup()
{
  Serial.begin(115200);
  pinMode(A0, INPUT);
  FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, NUM_LEDS);
  for(int i = 0; i < NUM_LEDS ; i++) {
      leds[i] = CRGB(0,0,0);
  }
  FastLED.show();
}

void loop()
{

  for (uint16_t i = 0; i<samples; i++){
    vReal[i] = int8_t(analogRead(A0));
    vImag[i] = 0.0;
    delay(1/samplingFrequency);
  }

  FFT.Windowing(vReal, samples, FFT_WIN_TYP_HAMMING, FFT_FORWARD);  /* Weigh data */
  FFT.Compute(vReal, vImag, samples, FFT_FORWARD); /* Compute FFT */
  FFT.ComplexToMagnitude(vReal, vImag, samples); /* Compute magnitudes */
  double x;
  double v;
  FFT.MajorPeak(vReal, samples, samplingFrequency, &x, &v);

  if (v>300){

    if (x>=freqBounds[0] && x<freqBounds[1]){
      Serial.print("BASE ");
      colorValue = (x - freqBounds[0]) * 255 / (freqBounds[1] - freqBounds[0]);
      leds[0] = CRGB(0,colorValue,255);
    }
    if (x>=freqBounds[1] && x<freqBounds[2]){
      Serial.print("TWO  ");
      colorValue = (x - freqBounds[1]) * 255 / (freqBounds[2] - freqBounds[1]);
      leds[0] = CRGB(0,255,255-colorValue);
    }
    if (x>=freqBounds[2] && x<freqBounds[3]){
      Serial.print("MID  ");
      colorValue = (x - freqBounds[2]) * 255 / (freqBounds[3] - freqBounds[2]);
      leds[0] = CRGB(colorValue,255,0);
    }
    if (x>=freqBounds[3] && x<freqBounds[4]){
      Serial.print("FOUR ");
      colorValue = (x - freqBounds[3]) * 255 / (freqBounds[4] - freqBounds[3]);
      leds[0] = CRGB(255,255-colorValue,0);
    }
    if (x>=freqBounds[4] && x<=freqBounds[5]){
      Serial.print("HIGH ");
      colorValue = (x - freqBounds[4]) * 255 / (freqBounds[5] - freqBounds[4]);
      leds[0] = CRGB(255,0,colorValue);
    }

    Serial.print(x,6);
    Serial.print(", ");
    Serial.println(v, 6);
  } else {
    leds[0] = CRGB(0,0,0);
  }
  for(int i = (NUM_LEDS - 1); i > 0 ; i--) {
      leds[i] = leds[i-1];
  }
  FastLED.show();
}
  • the answer to your question is yes ..... is that really all you want to ask? .............. btw: you can remove the serialPrint() calls to speed up the code – jsotola Jan 31 at 0:12
  • use a faster MCU – Jaromanda X Jan 31 at 3:36
  • 1
    Does the code work as it is? The delay near the top looks wrong to me - it will always delay(0). Anyway, how fast does it currently run, how fast do you need it to run, and which parts of the process take the most time? – Mark Smith Jan 31 at 6:33
  • 1
    Ad some code that prints how much micros each part of your code uses. Something tells me that the FFT calculations will take 90% of the loop time, and there is no easy way of optimizing that. You can always use electronic circuits instead of digital MCU logic to calculate the FT at half of speed of light. I found a nice source here sound.whsites.net/project136.htm – Filip Franik Jan 31 at 9:08
  • Use an integer fft algorithm instead of a floating point one. – Majenko Jan 31 at 9:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.