, , , , , , , ,

This article will describe some experiments with measuring SPL from test signals played into our microphone through a headphone. This post seeks to produce concrete measurements to compare to theory, as compared to the previous posts which have measured SPL compared to a more subjective standard.

This is part of a series of articles on the general subject of audio signal processing from air to information. See the section at the end for the full series and links to the source code.


Previous articles have explored the process of using a MEMS digital microphone to measure sound pressure level. To this point, the measurements have been fairly subjective, and not strongly tied to real signals.

I can honk the bike horn often (ask my neighbors!), but I don’t have any good controls over the consistency from honk to honk. So we want to move from a simple noise source in the room (honk) to something that is much more repeatable.

This article will describe experiments performed with a signal generator driving an earbud style headphone that has been mechanically coupled via a plastic model of an ear to the microphone’s sound port.

Make an Ear

I acquired some InstaMorph plastic pellets. This is a low-temperature plastic material that softens enough to work at temperatures that are safe to handle with bare hands. You drop it in hot water (about 140°F) for a few minutes. When the opaque white pellets turn clear, it is ready to work.

Using the plastic, I formed an adapter that has enough of an ear canal to support a typical earbud headset, with a hole at the bottom aligned with the sound port on my microphone. Nothing is sealed air-tight, and the microphone still responds to louder noises even with the headphone inserted. It also responds to tapping (or even just scratching) the desk top, so I have tried not to touch the table on which the mic is sitting.

Better measurements could be had if I had access to an anechoic chamber. But that isn’t something that can be just tossed together over a weekend.

Feed it Signals

I installed an Android app (Signal Generator by RadonSoft) in my Nexus 5 phone. It provides a very simple user interface, with sliders for volume and frequency, along with a choice of white noise, pink noise, and sine wave. The frequency slider naturally only affects the sine wave.

Its volume control covers a range from -60 dB to 0 dB, where 0 dB is described as full scale without clipping into the Android audio system. It helpfully turned the system volume control all the way up.

The developer claims that the wave forms are synthesized at 44.1 kHz sample rate.

Measure SPL from Loud to Quiet

Here’s the available test sounds observed at a range of amplitudes into the Android’s earphone jack, referenced to full scale audio. We don’t know what the effective loss is in the earphone or its coupling to the mic, but this set of measurements might provide some hints. The dB FS column is the setting of the volume slider on the signal generator app. The other columns are the reported SPL code value, which is reported as a scaled log base two by the SPL firmware.

dB FS    1 kHz   Pink   White
   0       82     72      77    
  -6       74     63      74
 -12       67     54      61
 -18       59     46      52
 -24       51     38      45
 -30       43     31      37
 -36       36     28      31
 -42       30     27      28
 -48       27     27      27   

Examining this table with linear least squares gives a strong hint that the raw SPL code value is about 1.3 times the db FS setting, plus a constant. Solving for dB FS, we find that dB FS is about 0.75 times the raw SPL code, plus a constant.

The scaling difference between raw SPL codes and dB makes sense. We would expect since the coded SPL value is itself scaled as 8 log_2 that:

\mathrm{dB \space SPL} = \frac{20 log_{10}(2)}{8} \mathrm{SPL \space code} + C

which simplifies (since log_{10}(2) = 0.3010...) to

\mathrm{dB \space SPL} = \frac{3}{4} \mathrm{SPL \space code} + C

And that agrees nicely with the bulk of the measurements in the above table.

The highest seen code 82 (1 kHz at 0 dB FS) is 61.5 dB, and the lowest 27 is 20.25 dB. That is a span of 41.25 dB, which does correspond to -42 dB signal that is the quietest seen above the noise floor.

Naturally, things are a little messy at the edges, especially at the low end. There is clearly a noise floor in the SPL firmware. We know the microphone itself has a noise floor, and there is documented signal to noise level. Look for a future post that pokes at this a bit more, and tries to take a stab at discovering the constant C that will relate SPL codes to actual dB SPL.

Measure SPL of a Frequency Sweep

Here’s a frequency sweep at three steps per decade at a constant amplitude. The first column is the frequency set for the sine wave generator at 0 dB FS in Android. The raw SPL column is the code value reported by the firmware. The third column is raw SPL scaled and offset to be relative to the SPL computed from a full scale PDM signal from the microphone, which would be at raw SPL code 104.

0 dB FS
sine Hz  raw SPL   dB FS PDM
    20    84       -15
    50    94        -7.5
   100    96        -6
   200    95        -6.75
   500    86       -13.5
  1000    83       -15.75
  2000    74       -22.5
  5000    60       -33
 10000    29       -56.25
 20000    25       -59.25

You can see the roll-off at the low end introduced by the firmware’s simulated DC blocking filter, and at the high end introduced by sampling at about 8 kHz, with the skewed pass band that is typical of an uncorrected CIC filter as used to implement the PDM to PCM conversion by the firmware.


As we move this toy from an interesting stunt in a breadboard and toward a possible product, it will be important to understand what it is actually measuring.

Although no changes were made to the firmware directly in support of this effort, all of the code supporting this demonstration is in a public fossil repository. This post documents work that was checked in as [1d38441bbc].

Previous installments in the series include:

(Written with StackEdit.)