Estimate sound pressure level from audio recordings

Sound pressure level (dB SPL) is a quantitative value that allows comparison of audio recordings coming from different datasets and environments. Sound pressure level corresponds to a quantitative measurement of the acoustic pressure energy. An Automated Recording Unit (ARU) can be converted into a pseudo sound meter level knowing few parameters: the sensitivity of the microphone, the amplification gain, the bit depth and the voltage range of the analog to digital converter. This is sufficient to convert a wav file (array of intergers) into pressure (Pa). Of course, as the frequency response of the ARUs’s microphone is never flat, the result is an approximation of the real sound pressure level. In order to be more precise, one should correct the frequency response of the microphone.

In this example, we will evaluate the variation of the sound pressure level of the ambient sound in a cold temperate forest in France during 24h.

Load required modules

Load required packages

import pandas as pd
import os
import numpy as np
import matplotlib.pyplot as plt
from maad import sound, util, spl

Set variables

It is very important to always keep the parameters of the ARU that was used to collect the audio dataset. This is a mandatory to compute the sound pressure level of the audio file (dB SPL) as a sound meter level would do. For this experiment, we used a Songmeter 4 (SM4, from Wildlife Acoustics) with an amplification gain of 16dB.

S = -35         # Sensibility of the microphone -35dBV (SM4) / -18dBV (Audiomoth)
G = 26+16       # Total amplification gain in dB (SM4 has a +26dB preamplifier)
VADC = 2        # Voltage range of the analog to digital converter (ADC)

First, we parse the directory /indices in order to get a DataFrame with date and fullfilename. As the data was collected with a SM4 audio recording device, we set the dateformat agument to ‘SM4’ in order to be able to parse the date from the filename. In case of Audiomoth, the date is coded as Hex in the filename.

df = util.date_parser("../../data/indices/", dateformat='SM4', verbose=True)

Load and preprocess audio

Then we process all the files found in the directory /indices. Initialisation of an empty dataframe df_spl to store all the dB SPL values extracted from the whole audio dataset.

df_spl = pd.DataFrame()

# Main loop to go through all audio files
for index, row in df.iterrows() :

    # initialisation of an empty list to store the dB SPL of the current
    # audio recording.
    leq_list = []

    # get the full filename of the corresponding row
    fullfilename = row['file']
    # Save file basename
    path, filename = os.path.split(fullfilename)
    print ('\n**************************************************************')
    print (filename)

    #### Load the original sound (16bits, only left channel) and get the sampling
    # frequency fs
    try :
        wave,fs = sound.load(filename=fullfilename, channel='left', detrend=True, verbose=False)

    except:
        # Delete the row if the file does not exist or raise a value error (i.e. no EOF)
        df.drop(index, inplace=True)
        continue

    """ =======================================================================
                    Computation in the frequency domain
    ========================================================================"""

    # Compute the Power Spectrogram Density (PSD) : Sxx_power
    Sxx_power,tn,fn,ext = sound.spectrogram (wave, fs, window='hann',
                                            nperseg = 1024, noverlap=1024//2,
                                            verbose = False, display = False,
                                            savefig = None)


    #### Average PSD (It's a mandatory to compute the mean on the PSD for
    # energy conservation)
    mean_PSD = np.mean(Sxx_power, axis = 1)

    #### Compute the Leq of each frequency band (1kHz step)
    leq_list+=[spl.psd2leq(mean_PSD[util.index_bw(fn,(0,1000))],
                            gain=G,
                            sensitivity=S,
                            Vadc=VADC)]
    leq_list+=[spl.psd2leq(mean_PSD[util.index_bw(fn,(1000,2000))],
                            gain=G,
                            sensitivity=S,
                            Vadc=VADC)]
    leq_list+=[ spl.psd2leq(mean_PSD[util.index_bw(fn,(2000,3000))],
                            gain=G,
                            sensitivity=S,
                            Vadc=VADC)]
    leq_list+=[spl.psd2leq(mean_PSD[util.index_bw(fn,(3000,4000))],
                            gain=G,
                            sensitivity=S,
                            Vadc=VADC)]
    leq_list+=[spl.psd2leq(mean_PSD[util.index_bw(fn,(4000,5000))],
                            gain=G,
                            sensitivity=S,
                            Vadc=VADC)]
    leq_list+=[spl.psd2leq(mean_PSD[util.index_bw(fn,(5000,6000))],
                            gain=G,
                            sensitivity=S,
                            Vadc=VADC)]
    leq_list+=[spl.psd2leq(mean_PSD[util.index_bw(fn,(6000,7000))],
                            gain=G,
                            sensitivity=S,
                            Vadc=VADC)]
    leq_list+=[spl.psd2leq(mean_PSD[util.index_bw(fn,(7000,8000))],
                            gain=G,
                            sensitivity=S,
                            Vadc=VADC)]
    leq_list+=[spl.psd2leq(mean_PSD[util.index_bw(fn,(8000,9000))],
                            gain=G,
                            sensitivity=S,
                            Vadc=VADC)]
    leq_list+=[spl.psd2leq(mean_PSD[util.index_bw(fn,(9000,10000))],
                            gain=G,
                            sensitivity=S,
                            Vadc=VADC)]
    leq_list+=[spl.psd2leq(mean_PSD[util.index_bw(fn,(10000,11000))],
                            gain=G,
                            sensitivity=S,
                            Vadc=VADC)]

    #### Create a dataframe from the list
    df_leq = pd.DataFrame([leq_list],
                        columns = ['0-1kHz',
                                    '1-2kHz',
                                    '2-3kHz',
                                    '3-4kHz',
                                    '4-5kHz',
                                    '5-6kHz',
                                    '6-7kHz',
                                    '7-8kHz',
                                    '8-9kHz',
                                    '9-10kHz',
                                    '10-11kHz',
                                    ])

    """ =======================================================================
                    Create a dataframe
    ========================================================================"""
    #### We create a dataframe from row that contains the date and the
    # full filename. This is done by creating a DataFrame from row (ie. TimeSeries)
    # then transposing the DataFrame.
    df_row = pd.DataFrame(row)
    df_row =df_row.T
    df_row.index.name = 'Date'
    df_row = df_row.reset_index()

    #### add Leq values into the df_spl dataframe
    df_spl = pd.concat([df_spl,pd.concat([df_row, df_leq], axis=1)], axis=0)

#### When the loop ends, set Date as index
df_spl = df_spl.set_index('Date')

#### remove the column file
df_spl = df_spl.drop(columns=['file'])
**************************************************************
S4A03895_20190522_000000.wav

**************************************************************
S4A03895_20190522_001500.wav

**************************************************************
S4A03895_20190522_003000.wav

**************************************************************
S4A03895_20190522_004500.wav

**************************************************************
S4A03895_20190522_010000.wav

**************************************************************
S4A03895_20190522_011500.wav

**************************************************************
S4A03895_20190522_013000.wav

**************************************************************
S4A03895_20190522_014500.wav

**************************************************************
S4A03895_20190522_020000.wav

**************************************************************
S4A03895_20190522_021500.wav

**************************************************************
S4A03895_20190522_023000.wav

**************************************************************
S4A03895_20190522_024500.wav

**************************************************************
S4A03895_20190522_030000.wav

**************************************************************
S4A03895_20190522_031500.wav

**************************************************************
S4A03895_20190522_033000.wav

**************************************************************
S4A03895_20190522_034500.wav

**************************************************************
S4A03895_20190522_040000.wav

**************************************************************
S4A03895_20190522_041500.wav

**************************************************************
S4A03895_20190522_043000.wav

**************************************************************
S4A03895_20190522_044500.wav

**************************************************************
S4A03895_20190522_050000.wav

**************************************************************
S4A03895_20190522_051500.wav

**************************************************************
S4A03895_20190522_053000.wav

**************************************************************
S4A03895_20190522_054500.wav

**************************************************************
S4A03895_20190522_060000.wav

**************************************************************
S4A03895_20190522_061500.wav

**************************************************************
S4A03895_20190522_063000.wav

**************************************************************
S4A03895_20190522_064500.wav

**************************************************************
S4A03895_20190522_070000.wav

**************************************************************
S4A03895_20190522_071500.wav

**************************************************************
S4A03895_20190522_073000.wav

**************************************************************
S4A03895_20190522_074500.wav

**************************************************************
S4A03895_20190522_080000.wav

**************************************************************
S4A03895_20190522_081500.wav

**************************************************************
S4A03895_20190522_083000.wav

**************************************************************
S4A03895_20190522_084500.wav

**************************************************************
S4A03895_20190522_090000.wav

**************************************************************
S4A03895_20190522_091500.wav

**************************************************************
S4A03895_20190522_093000.wav

**************************************************************
S4A03895_20190522_094500.wav

**************************************************************
S4A03895_20190522_100000.wav

**************************************************************
S4A03895_20190522_101500.wav

**************************************************************
S4A03895_20190522_103000.wav

**************************************************************
S4A03895_20190522_104500.wav

**************************************************************
S4A03895_20190522_110000.wav

**************************************************************
S4A03895_20190522_111500.wav

**************************************************************
S4A03895_20190522_113000.wav

**************************************************************
S4A03895_20190522_114500.wav

**************************************************************
S4A03895_20190522_120000.wav

**************************************************************
S4A03895_20190522_121500.wav

**************************************************************
S4A03895_20190522_123000.wav

**************************************************************
S4A03895_20190522_124500.wav

**************************************************************
S4A03895_20190522_130000.wav

**************************************************************
S4A03895_20190522_131500.wav

**************************************************************
S4A03895_20190522_133000.wav

**************************************************************
S4A03895_20190522_134500.wav

**************************************************************
S4A03895_20190522_140000.wav

**************************************************************
S4A03895_20190522_141500.wav

**************************************************************
S4A03895_20190522_143000.wav

**************************************************************
S4A03895_20190522_144500.wav

**************************************************************
S4A03895_20190522_150000.wav

**************************************************************
S4A03895_20190522_151500.wav

**************************************************************
S4A03895_20190522_153000.wav

**************************************************************
S4A03895_20190522_154500.wav

**************************************************************
S4A03895_20190522_160000.wav

**************************************************************
S4A03895_20190522_161500.wav

**************************************************************
S4A03895_20190522_163000.wav

**************************************************************
S4A03895_20190522_164500.wav

**************************************************************
S4A03895_20190522_170000.wav

**************************************************************
S4A03895_20190522_171500.wav

**************************************************************
S4A03895_20190522_173000.wav

**************************************************************
S4A03895_20190522_174500.wav

**************************************************************
S4A03895_20190522_180000.wav

**************************************************************
S4A03895_20190522_181500.wav

**************************************************************
S4A03895_20190522_183000.wav

**************************************************************
S4A03895_20190522_184500.wav

**************************************************************
S4A03895_20190522_190000.wav

**************************************************************
S4A03895_20190522_191500.wav

**************************************************************
S4A03895_20190522_193000.wav

**************************************************************
S4A03895_20190522_194500.wav

**************************************************************
S4A03895_20190522_200000.wav

**************************************************************
S4A03895_20190522_201500.wav

**************************************************************
S4A03895_20190522_203000.wav

**************************************************************
S4A03895_20190522_204500.wav

**************************************************************
S4A03895_20190522_210000.wav

**************************************************************
S4A03895_20190522_211500.wav

**************************************************************
S4A03895_20190522_213000.wav

**************************************************************
S4A03895_20190522_214500.wav

**************************************************************
S4A03895_20190522_220000.wav

**************************************************************
S4A03895_20190522_221500.wav

**************************************************************
S4A03895_20190522_223000.wav

**************************************************************
S4A03895_20190522_224500.wav

**************************************************************
S4A03895_20190522_230000.wav

**************************************************************
S4A03895_20190522_231500.wav

**************************************************************
S4A03895_20190522_233000.wav

**************************************************************
S4A03895_20190522_234500.wav

Display results

Display Leq (dB SPL) dynamics for each frequency band. One can observe that most of the acoustic energy is between 0-1kHz. Moreover the sound pressure level of the 0-1kHz frequency band is not constant but increases during the day, from 4am to 22pm with a maximum between at 10am This is mainly due to the airplanes flying over the forest during the day. One can also observe that the energy of the biophony is really lower than the energy of the low frequency band. The sound pressure level of the biophony is the highest between 5am to 9am, which corresponds to the dawn chorus

plt.style.use('ggplot')
df_spl_rev = df_spl.iloc[:,::-1]
util.plot_features_map(df_spl_rev, norm=False, cmap='RdPu')
plt.tight_layout()
plot sound pressure level

Display the comparison between the dynamics of the Leq (dB SPL) corresponding mainly to the anthropophony (frequency band 0-1kHz) and the biophony (frequency band 1-12kHz)

plt.figure(figsize=[7,4])
df_spl.iloc[:,0].apply(util.add_dB, axis=1).plot()
df_spl.iloc[:,1:].apply(util.add_dB, axis=1).plot()
plt.xlabel('Hours')
plt.ylabel('Sound Pressure Level (dB SPL)')
plt.legend(['anthropophony', 'biophony'])
plt.tight_layout()
plt.show()
plot sound pressure level

Total running time of the script: (0 minutes 1.133 seconds)

Gallery generated by Sphinx-Gallery