Getting decibel /volume values from microphone

Hi, I am currently working on a project, where I need to be able to read the volume of music. Later iI should get the decibel values, but I will get the values by comparing the decibel values of my multimeter with the values from the arduino.
My teacher told me that RMS is a possiblilty, however since im kinda new to arduino i would have to get a complete code for this and i failed to find one on the internet.
I am using an normal microphon with an amplifier and lifted the signal to be positive (new 0 value is now approximitly 2,5V).
Does anybody know of any other ways to get the volume expect the RMS or does anybody have a code for it?
In my code I am using the FHT aswell:

//FHT
#define LIN_OUT8 1 // use the lin8bit output function
#define FHT_N 256 // set to 256 point fht
#define SCALE 64 //Improves resolution of the fht_mag_lin8()
#include <FHT.h>
int k;
int j=0;

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

void loop() {
  //FHT
  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 = 0xf7; // 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();
    fht_reorder(); // reorder the data before doing the fht
    fht_run(); // process the data in the fht
    fht_mag_lin8(); // take the output of the fht
    sei();
}
}

As you can see my code resembels the example code a lot, however i lowered the sample rate to get a better read of low (bass) frequencies.
I am using an Arduino UNO.
For the reading of the analog0 pin(where the mic is) i would have to use this code right:

byte m = ADCL; // fetch adc data
      byte j = ADCH;
      int k = (j << 8) | m; // form into an int

Where k would be the actual read. I know that analogRead() doesnt work but this should give similar values, right?
If anybody could help me i'd be really thankful :slight_smile:
Thanks and greetings!
Crocs

If you don't need frequency information you don't need FHT.

My teacher told me that RMS is a possiblilty.

I'd start-out with a simple average. Depending on the nature of the sound and what kind of results you're interested in, you might be able to simply use the peak.

It's really not that critical since you'll need to calibrate your project anyway. For example, if you have a constant tone at 90dB and you drop it by 3dB, the peak, average, and RMS will all drop by 3dB. So no matter how your setup was calibrated (as long as it was calibrated), the new reading would be 87dB.

If you were are making a "real" calibrated instrument, your measurements need to be [u]weighted[/u] to take response-time and frequency into account. But for casual use, I'd choose peak or average (or both).

Since you're biased at 2.5V, subtract 512 from the readings before any further math.

If you use the average, you need to take the absolute valuebefore taking the average, or else ignore the negative readings. With RMS, you don't have to worry about that since you square the value (making it positive). Otherwise the average of an AC signal will always be zero (positive half the time and negative half the time after removing the bias).

You can use [u]analogRead()[/u] to read the ADC directly into an integer, and you won't have to do any of that bit-shifting stuff.

I am using an normal microphon with an amplifier and lifted the signal to be positive (new 0 value is now approximitly 2,5V).

Run the AnalogSerialRead example code to see what kind of data you're getting.

however i lowered the sample rate to get a better read of low (bass) frequencies.

That will make things worse (if you're using FHT or otherwise trying to gather frequency information). If the signal contains frequencies higher than half the sample rate (the [u]Nyquist limit[/u]) you'll get aliasing (false frequencies).

but I will get the values by comparing the decibel values of my multimeter with the values from the arduino.

Unless you have some kind of special calibrated microphone/adapter your mutimeter does NOT read dB SPL. You'll need a calibrated [u]SPL meter[/u] in order to calibrate the SPL meter you're building.

Theoretically, if you know the sensitivity of the microphone and the gain of your amplifier you could calibrate from that information. But, there are production variations and in practice SPL meters are calibrated acoustically.

Thanks for the fast reply!
The project im working on uses the FHT to control the color of an RGB LED, therefore it is necasarry. The project isnt calibratet yet, since i couldnt find a code to get the actual volume, so that it is atleast to some extend precise

The analogRead function is not working anymore, I suspect this is because of the settings for the ADCSRA or an other register. There is the samplerate, the free running mode of the ADC and stuff defined. The bit shifting stuff doesnt give a wrong result i think, so ill be just using this one.

I am aware of the fact, that it is dangerous to lower the sample rate too low, however if i dont change it and let it be standart, ill get about 2 values that represent the bass. For my project 2 just arent enough :/. The sample rate for my code is about 20kHz and should therefore be able to read frequencies between 0 and 10'000. Are the results getting that wrong when there are any Frequencies above that?

Since i am rather new to Arduino (Using it for about 2 weeks) I am not quite sure that i will be able to actually get a proper function to get the average value. According to my teacher the RMS would be the best possibility, but i cant find any code online and I am unable to write it myself.

Do you know how precise the average, peak or both are? And if there are any example codes?
The best thing would be an example code for the RMS, but i spent quite some time searching for one and didnt find anything.
I know of lots of codes for vu-meters that let LED light up. But these arent anywhere close to being accurate.
And thanks again for the reply!

Since i am rather new to Arduino (Using it for about 2 weeks) I am not quite sure that i will be able to actually get a proper function to get the average value.

FHT/FFT/DFT is advanced shtuff! You don't need Arduino experience, but you should have some programming experience before getting into it, even if you are using someone else's code or library.

So, I recommend you start simple... Read the ADC and send the reading to the serial monitor. Then, take several readings, take an average and send that to the serial monitor.

When the basics are working, try FTH and send some of those results to the serial monitor.

When you know you are getting good data, you can try calculating dB or driving an LED, etc.

I am aware of the fact, that it is dangerous to lower the sample rate too low, however if i dont change it and let it be standart, ill get about 2 values that represent the bass.

That doesn't make sense... At lower frequencies (bass) you get more samples per cycle. i.e. If your sample rate is 20kHz and you are sampling a 200Hz signal, that's 100 samples per cycle (50 samples per half-cycle). If you are sampling a 2kHz signal you get 10 samples per cycle.

A 20kHz sample rate should be OK. You will get some aliasing, assuming your microphone picks-up audio (including harmonics & overtones) above 10khz. But, these higher frequency components are low-level in "ordinary" sound so your aliases will also be low-level, so you'll probably be OK. All "proper" analog-to-digital converters have an analog low-pass filter in front of the ADC.

According to my teacher the RMS would be the best possibility, but i cant find any code online and I am unable to write it myself.

[u]Root Mean Square[/u] - Take a known-number of samples. Square each value. Divide by the number of samples. Take the square root.

Do you know how precise the average, peak or both are?

If you don't know how to take an average, you are way-way over your head... You have limited RAM so you should probably limit the number of samples in each average to 100 or less. And, convert your values to type-float so you can handle large sums and avoid any integer math problems.

To find the peak, create a variable (i.e. Xmax) to hold the maximum (peak) and initialize it to zero.

Then make an if-statement that updates Xmax if the current reading is greater than the existing maximum. That's easy because you only need two variables (the current reading and the maximum) and you don't need any calculations.

I know of lots of codes for vu-meters that let LED light up. But these arent anywhere close to being accurate.

...so, you calibrate it! i.e. If your ADC is getting an average reading of 95 at 100dB SPL, or at 0dBv, etc. You take that as a reference and scale/calibrate your readings from there... You can calibrate in software.

When you're getting some good-reliable numbers, we can talk about how to calculate dB.

P.S
If you had more time, I'd suggest the [u]MSGEQ7 chip[/u]. It has 7 bandpass filters built-in so your software doesn't have to do the frequency analysis. It also eliminates your waveform sampling, and eliminates the need for DC offset (it takes AC-in sends-out varying time-mulitiplexed DC). It requires some critical timing, so it's probably 10 times harder than a VU meter but 10 times easier than FFT/FHT.

Ok thanks i didnt know it was that easy to get the RMS value, ill try it as soon as i get home.
The FHT part is working already without a problem and i know how it works, how to change stuff and what changes i should do.
I was kinda confused about the better output with the lower sample rate aswell. I got a program to visualize the FHT output and i could tell the output was much better (I tried it with an online hearing test that goes through the frequencies and watched where the peak in the FHT was.
I thoght it was because you still have the same amount of samples that you make with the FHT (256) itself, but you got a lower sample rate of the ADC so you can't read the higher frequencies anymore but have the same amount of samples for the FHT and therefore more information about the frequencies you still get.

I am new to C and Arduino, however i have some experience in Java, Python and in Webdesign(HTML,CSS,PHP). Wanted to learn C a while ago but was busy with school at that time. It took me about 15 hours to understand the FHT (both the function and sytax(mostly because i had to understand all the registers there are and what i can do with them (which is a ton))), write the color code (although it is pretty simple at the moment).
The basics of the ADC, the serial stuff and so on are not a problem. Since i am a student at the moment i dont have that much experience of corse, but I think if the RMS is that easy i can get my project done next week. Including the calibration and the essay part.

I read some stuff about the chip you mentioned, but I still decided to do it with the FHT. This has several reasons: Since i am doing this for a school project ill get more points when i use the FHT and understand it, and the FHT got a much more useful output (since you get 128 numbers and not just 7). At the moment i dont need 128 output since i have to keep the code rather short and simple (Not that i want to but i have to since it is a school project and shouldnt get too complicated, even though it is in 12th grade). But since I am amazed by what you can do all with the Arduino i definitly want to keep working with it. I was thinking of making an LED cube or do some stuff with some LED stripes later on and extending the code. When this time comes i will also buy a better microphone since the output has to be more precise.
I actually borrowed one of these chips from a friend just to see how it works, however since the whole stuff is pretty simple i decided not to do it that way(i need to write an essay of about 20-25 pages with the code, since this is kind of a lot i decided to go for the FHT.

I got the stuff with the average wrong cause i kinda messed up there. I accidentaly set the refrence voltage of the A0 pin to something wrong (messed up to set the correct bits in the ADMUX i think) and this messed up my results, all this was thanks to a typo that i didnt notice.
I then thought it didnt work because i messed up in another part of the code so i got confused.

Btw since it seems you know a lot about Arduino and stuff like that:
I am trying to improve in that stuff at the moment, but i dont know where to start. I understand the basics of the software and hardware, but i dont know where to start with the advanced stuff. Do you have any recommendations what to learn next? Should i start with a corse in C?
And thanks again for the help!

dont know where to start with the advanced stuff. Do you have any recommendations what to learn next? Should i start with a corse in C?

I'm NOT an expert programmer. I've programmed in various languages on & off over the years. I've taken a couple of classes in different languages but I studied C and C++ on my own. And, I've been fooling around with audio for many years.

A class is almost always best but since you already have some programming under your belt you should be able to learn the basics of C/C++ from a book or online. I started-out with Teach Yourself C in 21 days and Teach Yourself C++ in 21 days. Some people hate those books, but I liked them and I already experience with other programming languages. Now I have a shelf-full of programming books. [u]Cprogramming.com[/u] has a good introductory tutorial.

C++ is a complex language and I don't know of any book that covers the entire standard language other than the ANSI/ISO language standard itself. There may be a couple of complete online references. But, the standard language doesn't include things like graphics or the mouse. Those are additional-optional libraries.

If you want to learn about FHT and FFT, that would be digital signal processing. There is a good FREE online DSP book called [u]The Scientist and Engineer's Guide to Digital Signal Processing, by Steven W. Smith[/u]. It's not specific to any particular programming language (he uses some kind of "simplified BASIC" in his examples).