Help With Sound Measurer Project

Hello everyone, I need help with a sound level detector that I was trying to build.

The plan of the project was the following. I wanted a blue LED to light up when there is a low sound level, 3 green LED to light up when the sound level is medium, 4 yellow LED to light up when the sound level is high and 5 red LED to blink fast when the sound level is very high.

I am using LEDs, 220 ohm resistors to pull down and an Adafruit MAX4466 microphone with an Arduino Uno. Here is the schematic of the project.

My LED all light up and work fine but I can not get to pair the sound level with the colors in a good way.

I tried to do a code where I split the analog readout and that would open the blue LED from a range of 0 to 600. Then the green LED would light up from 600 to 800. Yellow LED from 800 to 900 and then red LED blinking over 900. Is the analog scale of 0 to 1023 for sound linear? It doesn't seem so to me.

Unfortunately it does not seem to work right. Whenever I make a loud noise and the red LED lights up, they do but the blue LED stays on while I would want it to turn off. I don't want to have many colors on at the same time, but rather only 1 color per range.

Here is the code I tried to do. If someone could help and tell my noob ass what I am doing wrong it would be appreciated

#define REDLED 13
#define REDLED2 12
#define REDLED3 11
#define REDLED4 10
#define REDLED5 9

#define YELLOWLED 8
#define YELLOWLED2 7
#define YELLOWLED3 6
#define YELLOWLED4 5

#define GREENLED 4
#define GREENLED2 3
#define GREENLED3 2

#define BLUELED 1

void setup()
{
  pinMode(REDLED,OUTPUT);
  pinMode(REDLED2,OUTPUT);
  pinMode(REDLED3,OUTPUT);
  pinMode(REDLED4,OUTPUT);
  pinMode(REDLED5,OUTPUT);
  pinMode(YELLOWLED,OUTPUT);
  pinMode(YELLOWLED2,OUTPUT);
  pinMode(YELLOWLED3,OUTPUT);
  pinMode(YELLOWLED4,OUTPUT);
  pinMode(GREENLED,OUTPUT);
  pinMode(GREENLED2,OUTPUT);
  pinMode(GREENLED3,OUTPUT);
  pinMode(BLUELED,OUTPUT);
  pinMode(A0,INPUT);
}

void loop()
{
  int volume = analogRead(A0);

  digitalWrite(BLUELED,LOW);
  digitalWrite(GREENLED,LOW);
  digitalWrite(GREENLED2,LOW);
  digitalWrite(GREENLED3,LOW);
  digitalWrite(YELLOWLED,LOW);
  digitalWrite(YELLOWLED2,LOW);
  digitalWrite(YELLOWLED3,LOW);
  digitalWrite(YELLOWLED4,LOW);
  digitalWrite(REDLED,LOW);
  digitalWrite(REDLED2,LOW);
  digitalWrite(REDLED3,LOW);
  digitalWrite(REDLED4,LOW);
  digitalWrite(REDLED5,LOW);

  if (volume>=1 && volume<600){
    digitalWrite(BLUELED,HIGH);
  }
  
  if (volume>=600 && volume<800){
    digitalWrite(GREENLED,HIGH);
    digitalWrite(GREENLED2,HIGH);
    digitalWrite(GREENLED3,HIGH);
  }

  if (volume>=800 && volume<900){
    digitalWrite(YELLOWLED,HIGH);
    digitalWrite(YELLOWLED2,HIGH);
    digitalWrite(YELLOWLED3,HIGH);
    digitalWrite(YELLOWLED4,HIGH);
  }

  if (volume>=900)
  {
    digitalWrite(REDLED,HIGH);
    digitalWrite(REDLED2,HIGH);
    digitalWrite(REDLED3,HIGH);
    digitalWrite(REDLED4,HIGH);
    digitalWrite(REDLED5,HIGH);
    delay(100);
    digitalWrite(REDLED,LOW);
    digitalWrite(REDLED2,LOW);
    digitalWrite(REDLED3,LOW);
    digitalWrite(REDLED4,LOW);
    digitalWrite(REDLED5,LOW);
    delay(100);
  }
}

It may simply be that the blue light was on before and after a loud noise and you didn't notice it go off. Try getting some sustained loud sound and see what happens.

Ok will do as soon as I get back home. The thing is that I am not able to scale the analog sensing with colors properly.

Like it will go immidiately from blue to red without really using the green or yellow LED and I tried to produce different sound levels to try and trigger the other levels.

Is the sensitivity of such microphones too bad for this application?

Not to your ears. Human senses respond logarithmically, so a sound that has 10 times the amplitude sounds "twice as loud".

Right so to better map my sensor, I could convert the analog scale to voltage using the 5V input I have and then voltages into decibels which would give me a better idea on how to map the ranges of each LED?

I wouldn't. Just do some experiments with a radio or whatever you can adjust the volume on and use serial print to see what raw value you get from the analogRead. Then pick the limits for your if statements based on what you observed.

I am working on the sensor right now and using the serial monitor to see what data I get. I don't know if the microphone is broken but it seems to respond weirdly to noise levels. I have to be very close to the microphone in order to notice a change in the analog values or I need to produce super loud claping noise, even screaming doesn't really work. I ordered new microphones maybe there is a hardware issue with the one I have.

On another note, I have figured that the blue LED is always on high since it is on PIN #1 which is the TX pin. I learned that this pin is also used for USB communication but I thought that if I set it on LOW unless one of the statements is true it would still behave like a regular digital pin. I guess I was wrong?

The output from the microphone PCB is an audio waveform (with a DC bias of about 2.5V). It's not a voltage representing sound volume.

So the analog signal that is measured can not necessarily be used to characterize the sound level?

You can get your Arduino to measure the analogue waveform at frequent intervals ("sampling"). Then subtract the DC component (about 2.5V) from each sample and use the abs() function to derive a measure of the amplitude of each sample (irrespective of whether it's positive or negative). If you then average those values over a number of samples, say 20 samples, that gives you a basic measure of volume. There are more sophisticated methods. I am not sure whether a Uno is really fast enough to do that satisfactorily.

Alternatively you could put electronics between your microphone PCB and Uno. For example this could be a diode, capacitor and resistor network to give you a peak detector circuit which would give a voltage from 2.5V to 5V representing volume.

You can set your thresholds for each LED colour to be logarithmic.

I see what you mean but I would have to think more about it if I were to try and implement it because I suck too much lol. The problem is I don't even know if the microphone is functioning correctly. I tried looking at the serial plotter and by having the microphone sitting in a quiet room this is what I obtained. It seems too eratic and high to me. When I talk there isn't really a change in the plotter. I have to do a loud finger snapping noise next to the microphone or to tap it in order to produce a noticeable peak.

Two things...

First, I would test your code by removing the microphone and connecting a potentiometer to the input of the Arduino, so you can sweep the input between 0V and 5V and observe what happens with the LED.

Second: pay attention to what @Archibald says. The output from the microphone does not represent the volume of the sound, it represents the waveform of the sound. It will oscillate wildly all over the place, because that's what a sound waveform looks like. Only the peak levels give any kind of indication of the volume level, and that is non-linear, as already said.

You certainly can't just take one sample from the microphone input port and use that to determine the volume level. All you are doing is taking a snapshot of the waveform at that instant.

The first thing you must do is check your code using a potentiometer. Then when satisfied, you need to look into ways of extracting the volume level from the sound, either using software in the Arduino or some simple external electronics.

1 Like

Brilliant!

@SteveThackery said that twice and I thought it was a good idea, so I am quoting it to say it again.

a7

I posted a little example project a couple of years ago - World's Simplest Lighting Effect

It's simpler that what you're doing but it should work with your microphone board and it MIGHT get you on the right track...

It finds the peaks and calculates a 20-second moving-average. Whenever the peaks are above average the built-in LED turns-on, and it's off when the signal is below average.

In my project the peak is updated every 50ms which MIGHT be too fast with 5 LEDs. Maybe you want to update your LEDs once per second or so. And in your application you don't need the average unless you want to use the average instead of the peaks. If you do use an average you probably want probably something faster than 20-seconds.

Also with my code you can un-comment the serial.Print() statements to see your readings.

"Clapping" is somewhat unreliable because you aren't reading the analog input continuously.* You are reading it for an instant, once every time through the loop, and it takes some microseconds to run-through the loop and you might not "catch" the loudest part of the hand-clap.

For testing you can use Audacity to generate test-tone files at different loudness levels that you can play on your computer speakers. Note that the digital dB levels shown in Audacity are negative and they are not calibrated to acoustic dB SPL levels, which are positive. But they are correlated. i.e. If the digital level drops from -10dB to -20dB, the acoustic sound level also drops by -10dB.

* There is an op-amp circuit called an envelope follower or Peak Detector. It puts-out a varying DC voltage that "follows" the peaks so your Arduino can catch the peaks and respond to a hand-clap (etc.). It has an added advantage that it only puts-out positive voltages so you don't have to deal with the biased readings. (If you want the full 0-5V range, you need a couple of "tweaks" in including positive & negative power supplies for the op-amp.)

There are microphone boards with an envelope-follower built-in.

I've made a few sound activated lighting effects and my "real" effects all use a peak detector. (I wanted to make my little example easier to build.)

1 Like

I tested the code by fixing values for my variable that records analog readings and I also tried with the potentiometer and it works fine.

I also tried to implement better data acquisition as @DVDdoug did with his example and it does seem to provide better results but I would need something that is faster since the average computed makes it have a delayed reaction, I will try what you mentioned Doug and see if I can get a faster but still representative acquisition!