DC Ouput of MSGEQ7 is consistent across all bands regardless of input frequency

Hi,

I've been trying to create an audio visualizer following what seems to be a pretty common example found here:

After hooking up my Arduino Uno as shown in the below schematic, I find that for a given input frequency produced by an online tone generator the DC output of the MSGEQ7 for all frequency bands is relatively constant, regardless of the input frequency.

What's odd is that for a 63 Hz input signal the DC output is pretty high for nearly all bands. This is plotted below, and you can see from the figure that the 160 Hz, 63 Hz, and 400 Hz band outputs have the least amount of noise.

However, for a 160 Hz input you can see that the DC output for all bands falls drastically, even for the 160 Hz centered band of the equalizer. It is worth noting that the output is also much less noisy. This same behavior is seen for 400 Hz, 1 kHz, and 2.5 kHz input signals (also shown below).

Because the all the bands output a relatively high voltage for 63 Hz signals, I can get my visualizer (WS2812B LED strip) to blink along to the bass of music, but I'd like to separate all the frequency bands covered by the MSGEQ7 for a better visualizer.

My code for collecting the the DC output values (which were used to create the plots) is shown below:

// LED setup
#include <FastLED.h>
#define NUM_LEDS 300
#define DATA_PIN 8
CRGB leds[NUM_LEDS];

// Equalizer setup
int strobe = 7;
int reset = 1;
int voltage = A0;

void setup() {
  // LED setup
  FastLED.addLeds<WS2812B, DATA_PIN, RGB>(leds, NUM_LEDS);
  
  // equalizer setup
  pinMode(strobe, OUTPUT);
  pinMode(reset, OUTPUT);
  Serial.begin(9600);
  digitalWrite(reset, HIGH);
  digitalWrite(reset, LOW);
  double volts;
}

void loop() {
  // put your main code here, to run repeatedly:
  
  for (int i=0;i<7;i++){
    digitalWrite(strobe, HIGH);
    digitalWrite(strobe, LOW);
    delayMicroseconds(30);  // time to settle
    double DCoutput = toVolts(analogRead(voltage));
    Serial.print(DCoutput);
    Serial.print(", ");
  }
  
  Serial.println("");
  digitalWrite(reset, HIGH); //reset to 63 Hz centered band
  digitalWrite(reset, LOW);
}

double toVolts(int num) {
  return (double)num * 0.00488;
}

There's a similar post on this forum here:

but it doesn't appear to have been resolved.

Does anyone have an idea for why I might be seeing this behavior?

I have a DFRobot Audio Analyzer, MSGEQ7, taking input from a microphone, processed by a uController, and sent to a LED strip.
Here is the code I am using:

#include "esp_system.h" //This inclusion configures the peripherals in the ESP system.
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/timers.h"
#include "freertos/event_groups.h"
#include <Adafruit_NeoPixel.h>
#include "AudioAnalyzer.h"
////
/* define event group and event bits */
EventGroupHandle_t eg;
#define evtDo_AudioReadFreq       ( 1 << 0 ) // 1
////
TickType_t xTicksToWait0 = 0;
////
QueueHandle_t xQ_LED_Info;
////
const int NeoPixelPin = 26;
const int LED_COUNT = 24; //total number of leds in the strip
const int NOISE = 10; // noise that you want to chop off
const int SEG = 6; // how many parts you want to seperate the led strip into
const int Priority4 = 4;
const int TaskStack40K = 40000;
const int TaskCore1  = 1;
const int TaskCore0 = 0;
const int AudioSampleSize = 6;
const int Brightness = 180;
const int A_D_ConversionBits = 4096; // arduino use 1024, ESP32 use 4096
////
Analyzer Audio = Analyzer( 5, 15, 36 );//Strobe pin ->15  RST pin ->2 Analog Pin ->36
// When we setup the NeoPixel library, we tell it how many pixels, and which pin to use to send signals.
Adafruit_NeoPixel leds = Adafruit_NeoPixel( LED_COUNT, NeoPixelPin, NEO_GRB + NEO_KHZ800 );
////
int FreqVal[7];//create an array to store the value of different freq
////
void setup()
{
  eg = xEventGroupCreate();
  Audio.Init(); // start the audio analyzer
  leds.begin(); // Call this to start up the LED strip.
  clearLEDs();  // This function, defined below, de-energizes all LEDs...
  leds.show();  // ...but the LEDs don't actually update until you call this.
  ////
  xQ_LED_Info = xQueueCreate ( 1, sizeof(FreqVal) );
  //////////////////////////////////////////////////////////////////////////////////////////////
  xTaskCreatePinnedToCore( fDo_AudioReadFreq, "fDo_ AudioReadFreq", TaskStack40K, NULL, Priority4, NULL, TaskCore1 ); //assigned to core
  xTaskCreatePinnedToCore( fDo_LEDs, "fDo_ LEDs", TaskStack40K, NULL, Priority4, NULL, TaskCore0 ); //assigned to core
  xEventGroupSetBits( eg, evtDo_AudioReadFreq );
} // setup()
////
void loop() {} // void loop
////
void fDo_LEDs( void *pvParameters )
{
  int iFreqVal[7];
  int j;
  leds.setBrightness( Brightness ); //  1 = min brightness (off), 255 = max brightness.
  for (;;)
  {
    if (xQueueReceive( xQ_LED_Info, &iFreqVal,  portMAX_DELAY) == pdTRUE)
    {
      j = 0;
      //assign different values for different parts of the led strip
      for (j = 0; j < LED_COUNT; j++)
      {
        if ( (0 <= j) && (j < (LED_COUNT / SEG)) )
        {
          set(j, iFreqVal[0]); // set the color of led
        }
        else if ( ((LED_COUNT / SEG) <= j) && (j < (LED_COUNT / SEG * 2)) )
        {
          set(j, iFreqVal[1]); //orginal code
        }
        else if ( ((LED_COUNT / SEG * 2) <= j) && (j < (LED_COUNT / SEG * 3)) )
        {
          set(j, iFreqVal[2]);
        }
        else if ( ((LED_COUNT / SEG * 3) <= j) && (j < (LED_COUNT / SEG * 4)) )
        {
          set(j, iFreqVal[3]);
        }
        else if ( ((LED_COUNT / SEG * 4) <= j) && (j < (LED_COUNT / SEG * 5)) )
        {
          set(j, iFreqVal[4]);
        }
        else
        {
          set(j, iFreqVal[5]);
        }
      }
      leds.show();
    }
    xEventGroupSetBits( eg, evtDo_AudioReadFreq );
  }
  vTaskDelete( NULL );
} // void fDo_ LEDs( void *pvParameters )
////
void fDo_AudioReadFreq( void *pvParameters )
{
  int64_t EndTime = esp_timer_get_time();
  int64_t StartTime = esp_timer_get_time(); //gets time in uSeconds like Arduino Micros
  for (;;)
  {

    //    if ( uxQueueMessagesWaiting(xQ_LED_Info) == 0 );
    //    {
    xEventGroupWaitBits (eg, evtDo_AudioReadFreq, pdTRUE, pdTRUE, portMAX_DELAY);
    EndTime = esp_timer_get_time() - StartTime;
    log_i( "TimeSpentOnTasks: %d", EndTime );
    Audio.ReadFreq(FreqVal);
    for (int i = 0; i < 7; i++)
    {
      FreqVal[i] = constrain( FreqVal[i], NOISE, A_D_ConversionBits );
      FreqVal[i] = map( FreqVal[i], NOISE, A_D_ConversionBits, 0, 255 );
      log_i( "Freq %d Value: %d", i, FreqVal[i]);//used for debugging and Freq choosing
    }
    xQueueSend( xQ_LED_Info, ( void * ) &FreqVal, xTicksToWait0 );
    StartTime = esp_timer_get_time();
    // }
  }
  vTaskDelete( NULL );
} // fDo_ AudioReadFreq( void *pvParameters )
////
//the following function set the led color based on its position and freq value
void set(byte position, int value)
{
  // segment 0, red
  if ( (0 <= position) && (position < LED_COUNT / SEG) ) // segment 0 (bottom to top), red
  {
    if ( value == 0 )
    {
      leds.setPixelColor( position, 0, 0, 0 );
    }
    else
    {
      leds.setPixelColor( position, leds.Color( value , 0, 0) );
    }
  }
  else if ( (LED_COUNT / SEG <= position) && (position < LED_COUNT / SEG * 2) ) // segment 1 yellow
  {
    if ( value == 0 )
    {
      leds.setPixelColor(position, leds.Color(0, 0, 0));
    }
    else
    {
      leds.setPixelColor(position, leds.Color( value, value, 0)); // works better to make yellow
    }
  }
  else if ( (LED_COUNT / SEG * 2 <= position) && (position < LED_COUNT / SEG * 3) ) // segment 2 pink
  {
    if ( value == 0 )
    {
      leds.setPixelColor(position, leds.Color(0, 0, 0));
    }
    else
    {
      leds.setPixelColor(position, leds.Color( value, 0, value * .91) ); // pink
    }
  }
  else if ( (LED_COUNT / SEG * 3 <= position) && (position < LED_COUNT / SEG * 4) ) // seg 3, green
  {
    if ( value == 0 )
    {
      leds.setPixelColor(position, leds.Color( 0, 0, 0));
    }
    else //
    {
      leds.setPixelColor( position, leds.Color( 0, value, 0) ); //
    }
  }
  else if ( (LED_COUNT / SEG * 4 <= position) && (position < LED_COUNT / SEG * 5) ) // segment 4, leds.color( R, G, B ), blue
  {
    // Serial.println( position );
    if ( value == 0 )
    {
      leds.setPixelColor(position, leds.Color( 0, 0, 0));
    }
    else //
    {
      leds.setPixelColor(position, leds.Color( 0, 0, value) ); // blue
    }
  }
  else // segment 5
  {
    if ( value == 0 )
    {
      leds.setPixelColor(position, leds.Color( 0, 0, 0)); // only helps a little bit in turning the leds off
    }
    else
    {
      leds.setPixelColor( position, leds.Color( value, value * .3, 0) ); // orange
    }
  }
} // void set(byte position, int value)
////
void clearLEDs()
{
  for (int i = 0; i < LED_COUNT; i++)
  {
    leds.setPixelColor(i, 0);
  }
} // void clearLEDs()

Hope it can give you some ideas on solving your issue.

Are you sure you have the component values correct? In particular C1 and R2 are critical in this circuit. They form the clock frequency of the switch capacitor filter and if they do not oscillate at the right frequency the bands respond to different frequencies.

Given the higher bands don’t give anything out would make me think that the master oscillator is not going as fast as it should, like if you had a 30nF capacitor instead of a 30pF one.

Can you post a picture of your wiring please.

Grumpy_Mike:
Are you sure you have the component values correct? In particular C1 and R2 are critical in this circuit. They form the clock frequency of the switch capacitor filter and if they do not oscillate at the right frequency the bands respond to different frequencies.

Given the higher bands don’t give anything out would make me think that the master oscillator is not going as fast as it should, like if you had a 30nF capacitor instead of a 30pF one.

Can you post a picture of your wiring please.

I've double checked the capacitor and resistor values and they are as shown in the figure. I saw that the example I'm following incorrectly uses a 22k resistor rather than a 220k resistor for R1, however I have made sure to follow the MSGEQ7 data sheet and use something closer to 200 k.

I am attaching two picture of my wiring for reference--sorry for the long wires.

From those pictures you don’t seem to have anything connected to an analogue input pin. But you do have a wire to digital pin 1, what is that going to do for you?

I have made sure to follow the MSGEQ7 data sheet and use something closer to 200 k.

It needs to be 220K, even a reduction to 200K will shift the frequency of the outputs when you get an output.

What is the value code on that pin_8 (C1) capacitor??

Grumpy_Mike:
From those pictures you don’t seem to have anything connected to an analogue input pin. But you do have a wire to digital pin 1, what is that going to do for you?

One end of the yellow wire is going to Analog in 0, its tough to see in the pic. Digital pin 1 is for my reset signal.

Grumpy_Mike:
It needs to be 220K, even a reduction to 200K will shift the frequency of the outputs when you get an output.

Thanks for clarifying, that's what I'm using.

runaway_pancake:
What is the value code on that pin_8 (C1) capacitor??

The code is 300

OK spotted it, but you have to admit it was well hidden.

The code is 300

I can’t see how that can possibly evaluate to 30pF. At the least it could be 300pF.
To make sure you would need to put an oscilloscope on the none ground end and check what frequency it goes at. A value of 30pF is quite small, to give you an idea the capacitance between two strip board tracks is about 4pF per hole.

I agree.
Can't recall having seen such a small value epoxy dipped.
Usually a disc sort and not 3-digit code like, but two-digit underlined
30

Digital pin 1 is for my reset signal.

And which blithering idiot picked that one? You have a whole Arduino at your disposal and he picks one of the two difficult to use pins. Mind you you were warned, the URL had the word instructables in it, and in English that means “someone who thinks he knows a lot more that he actually does”.

In case you don’t know pins 0 and 1 are involved with the serial output and also in uploading code to the Arduino. Pick another pin for your reset.