Dear arduino geeks,
please, I need your help. I am a new member of the arduino world and I need to realize my project. The problem I would like to solve is how to process the audio signal comming from my audio module with amplifier MAX9814. I already know all the functions of the module and how to use it, however, I still do not know how to process an analog signal from it for my purpose. I have also read many posts about this issue in this forum but I am still confused. I know it is not so easy.
I know that in the serial plotter I can see the sound wave in real time expressed as a voltage (analogRead(A0)). The amplitude of the wave should be the "loudness" or "intensity" of the sound. And now the key point: I need to somehow get that sound intensity, regardless of units, scale, etc., to work with the arduino as a pseudo sound level meter. I thought about it this way. The baseline of the sound wave in my serial plotter is about 250 and it oscillates up and down. So I substracted 250 and I got a zero baseline, but then the negative half of the sound wave was in negative numbers. So i calculated the absolute value and everything was now positive, seems fine. But - I think, it's not the right conversion, because the original amplitude is then half and in addition expressed as two peaks. It should only be one peak, right? So the question is, how should I go to obtain the relative intensity of the sound comming out of my sound module?
Hi @pokornja,
actually the baseline should be the value you get when the mic does not receive any sound (there will be some noise of course). As microprocessors usually work with positive signal levels sound waves are "moved" so that they fit into this area in most applications.
You may find very comprehensive explanations and sample code in
https://blog.yavilevich.com/2016/08/arduino-sound-level-meter-and-spectrum-analyzer/
There is actually a chapter on " Sound level measurement" ...!
Feel free to have a look and good luck!
ec2021
P.S.: You may find the example code at https://github.com/ayavilevich/ArduinoSoundLevelMeter
It depends, not how you measure it, but how you define it. If you are trying to measure peak to peak voltage, you can measure any peak and multiply by two. RMS voltages can either be measured with numerical integration, or by applying a conversion factor to the peak value. Which method will you use?
But, since ADC readings aren't any official form of measurement, some form of scaling means that you are performing a "blind calibration", i.e. applying your best guess calibration factor without performing any calibration.
However, it is fairly obvious that an SPL meter should be calibrated against a reference source.
Here is the code for an SPL meter I made. There are lots of comments (and caveats) so it should make a good tutorial. (Different sound sensor.)
Normally the sound sensor is biased at half of Vcc and a regular Arduino (with a 10-bit ADC) will read about 512.
Perfect!
Perfect again! If you do an RMS calculation the values are squared so that also takes care of the negative values but it's "complicated" and it eats-up CPU time.
The maximum peak (1) or an average of the absolute values will also work. Of course that requires a "time window". With a digital display you don't want to updated more than about once per second so you can read & comprehend the numbers.
If you don't use absolute values (or ignore the negatives) the average of an AC waveform is zero.
Note that since you are sampling a waveform the raw data will "look random", even with a constant tone.
(1) I say "maximum" peak because there is a peak every cycle and with real-world audio every "cycle" is different, with a different duration and a different peak.
The intensity is proportional to the amplitude squared.
Most people take the average of the squared values over some short period of time, then the negative amplitude values are no longer a problem.
Has automatic gain control. Doesn't seem like the best choice for a SPL meter.
Guys, thank you very much for your ideas! I do not need actually an accurate SPL meter, although I have now a noise level meter borrowed from a faculty so I could somehow make some calibration. But I do not need it for my purpose I guess. I just want to get numbers as simple as possible to compare the peak values and set a treshold for them, so I tried to do it as you suggested: 1) Substract to zero baseline and 2) square that values. Now I have some kind of intensity. But there is a problem When I am making really loud sound the intensity peaks about 5 000 000, when I am silent, it is about 2 000. There is quite a wide range between these values. Is it good idea to calculate some logarithm to make it more "linear"?
I know the MAX 9814 has gain control but it's OK for me. As I mentioned, I just need to capture the peak values in real time so that I can react immediately to these loud noises (i.e. digitalWrite(something)).
Human hearing is logarithmic in response, so a 10x increase in intensity sounds about "twice as loud". Sound levels are usually measured on the dB scale, which is logarithmic, relative to some arbitrarily chosen minimum sound intensity.
@jremington
Yes, I know this. But I don't know, how to calculate it
Maybe I should be more detailed in my needs.
I need to "guard" the silence in our apartment. As soon as there is noise from our neighbors, say with a frequency of up to 5 peaks per second, I need to make an immediate reaction. So the key element for me is to monitor the noise intensity in the room and react immediately when a certain level is exceeded. Thats why I need to get the intensity from my audio signal. But I have no idea how to work it out.
dB = 10.0*log10(measured_intensity/reference_intensity);
OK, thank you, so something like this?
int sample = analogRead(A0);
int measured_intensity = abs(sample - 250);
int dB = 10.0*log10(measured_intensity/reference_intensity);
Serial.println(dB);
But where can I find the reference intensity?
Sound intensity measured when the neighbors aren't making noise?
Don't forget that the intensity is the square of the signal voltage. If you don't want to square the voltage, use the formula
float dB = 20.0*log10(measured_intensity/reference_intensity);
I am sorry but I am still lost
When neighbors are not making noise then the intensity should be 0, or?
dB is always measured relative to some reference.
If you are looking, for example, for an increase of 10 dB above some base level, the base level is the reference.
This is clear for me, but I still don't understand if the reference is one specific number or how to measure it / how to obtain it in the code. I am sorry
Did you see the divide operator "/" in this formula, which suggests that you divide the current measured level by the reference level?
float dB = 10.0*log10(measured_intensity/reference_intensity);
If I really have to spell it out:
reference_intensity = sound intensity when the neighbors are not making noise.
measured_intensity = sound intensity when the neighbors are making noise.
Here, dB represents the increase in decibels from the reference intensity level.
I guess most of your questions are answered in the link I posted in #2
Might be worth reading it ...
ec2021
Guys, I am sorry. I have read everything posted above, but you can try to imagine that I am a chemist and I know almost nothing about programming, sound theory etc. so it's quite difficult for me to understand all these things. Fortunately, I still understand the calculations you are talking about. So if I am right, the reference intensity should be the value I measure when the room is quiet in the evening to get the dB increase above that silence. I just need to be sure how to get this value practically. So should I normally start the measurement in the evening, watch the serial monitor and grab the mean value where the signal is oscilating?
So if the signal of intensity oscillates around 8, is the whole code OK with it?
int sample = analogRead(A0);
int measured_intensity = abs(sample - 250);
float dB = 20.0*log10(measured_intensity/8);
Serial.println(dB);
If you are a chemist, then you already know how to educate yourself on new topics, as well as how to learn by experimentation.
Put those hard-learned lessons to work on this project. Forum members can't tell you what will work best in your particular situation.
Maybe the target of your application has got lost and probably does not require all those calculations?
From your post #1:
I need to somehow get that sound intensity, regardless of units, scale, etc., to work with the arduino as a pseudo sound level meter.
From your post #7:
I just need to capture the peak values in real time so that I can react immediately to these loud noises (i.e. digitalWrite(something)).
This is what wikipedia (https://en.wikipedia.org/wiki/Amplitude) tells us:
As your sound signals has a baseline of 250, the peak amplitudes go up from there and down from there. Though most acoustical signals will be kind of symmetrical you are not really interested in peak-to-peak; you are just interested in "loud signals" ...
So you might have a look at the following code example to check whether it solves your task:
int measureddata = 0;
int baseline = 250;
int maxPeakToPeak = 600;
int Threshold = 200;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
Serial.println("Start");
randomSeed(millis());
}
void loop() {
// put your main code here, to run repeatedly:
measureddata = random(maxPeakToPeak); // Simulates "sound data" from 0 to (maxPeakToPeak-1)
if (measureddata < 0) measureddata = 0; // Clip data at Zero , not really necessary here, just a little bit paranoid ... ;-)
if (measureddata > 2*baseline) measureddata = 2*baseline; // Clip data at 2 * baseline
int absAmplitude = abs(measureddata-baseline); // Now we can be sure that 0 <= absAmplitude <= baseline
Serial.print("Amplitude =\t"+String(measureddata));
Serial.print("\tAbsolute Amplitude =\t"+String(absAmplitude));
if (absAmplitude >= Threshold)
Serial.println("\t LOUD!");
else
Serial.println();
delay(500);
}
The clipping of measureddata at zero and 2*baseline makes sure that we work within a defined range ...
The value of Threshold depends on your application.