The Signal class

The Signal class is a container based on the np.array storing besides the samples as function of time also a sample frequency. The class has many usefull methods making the life of an acoustician a bit easier. Furthermore, because its based on the np.array, all operations you would normally perform on a np.array can be done on a Signal as well.


In [1]:
from acoustics import Signal
import numpy as np
%matplotlib inline
from IPython.display import Audio
import seaborn as sns # seaborn for prettier graphs

Creating an instance

A Signal takes two arguments, the first an array of samples, and the second a sample frequency.


In [2]:
s = Signal(np.random.randn(44100), fs=11025)

Alternatively, one of the alternative constructors can be used


In [3]:
s = Signal.from_wav('../data/recording.wav')

Attributes

An instance of Signal stores besides the instantaneous values also the sample frequency


In [4]:
s.fs


Out[4]:
44100

The Signal class can handle multiple signals. Currently we have only one channel.


In [5]:
s.channels


Out[5]:
1

The amount of samples in the signal can be retrieved in several ways. We can use the standard ways, len(s), or s.shape but also the method s.samples


In [6]:
s.samples


Out[6]:
863860

Play signal with IPython

The recording is of an aircraft flyover as you can hear.


In [7]:
Audio(data=s, rate=s.fs)


Out[7]:

Spectral analysis

Let's continue for now with analysing the recording.

We can start with looking at the spectrum. A narrowband power spectrum can be calculated using s.power_spectrum()


In [8]:
s.power_spectrum()


Out[8]:
(array([  0.00000000e+00,   5.10499386e-02,   1.02099877e-01, ...,
          2.20498469e+04,   2.20498979e+04,   2.20499490e+04]),
 array([  4.47483544e-10,   9.42024541e-12,   8.67856146e-12, ...,
          5.43481045e-13,   7.52065129e-13,   4.11959645e-13]))

returning frequencies and powers. It's also possible to straightaway plot the power spectrum


In [9]:
fig = s.plot_power_spectrum()


There are other types of spectra available, like for example the phase spectrum. Another popular figure is the spectrogram


In [10]:
fig = s.spectrogram()


Sound pressure level

The methods shown so far are quite common operations, not specific to acoustics alone. But, the Signal class has some more acoustics-specific methods as well. For example, we can calculate the sound pressure level as function of time using s.levels() or instead plot the values


In [11]:
fig = s.plot_levels()


Fractional octaves

The label is the channel number, using zero-based numbering as is common in Python. We can also calculate and plot 1/1-octaves with respectively s.octaves() and s.plot_octaves().


In [12]:
fig = s.plot_octaves()


Calculating or plotting 1/3-octaves is also possible.


In [13]:
fig = s.plot_third_octaves()


Frequency weighting

The acoustics package features frequency weighting in several ways. When having a signal like shown in this example, frequency weighting can be applied directly using the weigh method.


In [14]:
s.weigh('A')


Out[14]:
Signal([-0.00050427 -0.00163906 -0.00253622 ..., -0.00421069 -0.00422739 -0.004272  ])

This can be seen better when plotting in octaves.


In [15]:
fig = s.weigh('A').plot_octaves()


Descriptors

The signal class also features several descriptors, like e.g. $L_{eq}$. Let's calculate as an example the A-weighted equivalent level over the event, i.e. $L_{A,eq}$.


In [16]:
s.weigh('A').leq()


Out[16]:
array(67.6309947210684)

This value is a bit below the unweighted $L_{Z,eq}$.


In [17]:
s.leq()


Out[17]:
array(72.74051070692379)

We can verify the calculation by using a different method. Let's calculate 1/3-octave values first, and then add the weighting. The A-weighting is


In [18]:
from acoustics.standards.iec_61672_1_2013 import WEIGHTING_VALUES
WEIGHTING_VALUES['A']


Out[18]:
array([-70.4, -63.4, -56.7, -50.5, -44.7, -39.4, -34.6, -30.2, -26.2,
       -22.5, -19.1, -16.1, -13.4, -10.9,  -8.6,  -6.6,  -4.8,  -3.2,
        -1.9,  -0.8,   0. ,   0.6,   1. ,   1.2,   1.3,   1.2,   1. ,
         0.5,  -0.1,  -1.1,  -2.5,  -4.3,  -6.6,  -9.3])

and the A-weighted $L_{A,eq}$ determined using this method is


In [19]:
from acoustics.decibel import dbsum
dbsum( s.third_octaves()[1] + WEIGHTING_VALUES['A'] )


Out[19]:
67.65246258801092

Multichannel signal

The Signal container can store more then one channel


In [20]:
s2 = Signal([s,s,s], s.fs)

as we can see


In [21]:
s2.channels


Out[21]:
3

Most methods still work when considering multichannel signals.


In [22]:
fig = s2.weigh('A').plot_third_octaves()


Exporting to wav

Finally, a signal can be written to WAV format easily as well using s.to_wav(filename). You might want to normalize your signal first though, so e.g. s.normalize().to_wav(filename).