erikvold
erikvold

Reputation: 16558

Measuring decibels (dB) using soundmeter

I'm able to use soundmeter to measure the "root-mean-square (RMS) of sound fragments". Now I want to get the decibels dB measurement from this value somehow.

Afaict the formula is something like:

dB = 20 * log(RMS * P, 10)

where log is base 10, and P is some unknown value power, which (as far as I can tell from https://en.wikipedia.org/wiki/Decibel) depends on the microphone that is used.

Now if I use a sound level app on my iPhone I see the avg noise in the room is 68dB, and the measurements that I receive from the soundmeter --collect --seconds 10 are:

Collecting RMS values... 149 Timeout Collected result: min: 97 max: 149 avg: 126

Is something wrong with this logic? and how can I determine what value of P to use without calculating it (which I'm tempted to do, and seems to work). I'd assume I'd have to look it up online in some specs page, but that seems quite difficult, and using osx I'm not sure now to figure out what the value of P would be. Also this seems to be dependent on the microphone volume level setting for osx.

Upvotes: 4

Views: 2866

Answers (1)

jaket
jaket

Reputation: 9341

soundmeter is not returning the RMS in the unit one would normally expect, which would be calibrated such that a full-scale digital sine wave is 1.0 and silence is 0.0.

I found these snippets of code:

In https://github.com/shichao-an/soundmeter/blob/master/soundmeter/meter.py

data = self.output.getvalue()
segment = pydub.AudioSegment(data)
rms = segment.rms

which calls https://github.com/jiaaro/pydub/blob/master/pydub/audio_segment.py

def rms(self):
    if self.sample_width == 1:
        return self.set_sample_width(2).rms
    else:
        return audioop.rms(self._data, self.sample_width)

The function immediately below you can see that the data is divided by the maximum sample value to give the desired scale. I assume ratio_to_db is 20*log10(x)

def dBFS(self):
    rms = self.rms
    if not rms:
        return -float("infinity")
    return ratio_to_db(self.rms / self.max_possible_amplitude)

In your particular case you need to take the collected RMS level divided by the 2^N where N is the number of bits per sample to get the RMS level scaled and then convert to dB. This number will be dBFS or decibels relative to digital full-scale and will be between +0 and -inf. To get a positive dBSPL value you need to find the sensitivity of your microphone. You can do this by looking up the specs or calibrating to a known reference. If you want to trust the app on your iPhone and it reports the room noise is 68 dBSPL while your program reads -40 dBFS then you can do simple arithmetic to convert by simply adding the difference of the two (108) to the dBFS number you get.

Upvotes: 5

Related Questions