Search code examples
pythonunit-testingmatplotlibsignal-processingacoustics

Matplotlib Magnitude_spectrum Units in Python for Comparing Guitar Strings


I'm using matplotlib's magnitude_spectrum to compare the tonal characteristics of guitar strings. Magnitude_spectrum shows the y axis as having units of "Magnitude (energy)". I use two different 'processes' to compare the FFT. Process 2 (for lack of a better description) is much easier to interpret- code & graphs below

My questions are:

  • In terms of units, what does "Magnitude (energy)" mean and how does it relate to dB?
  • Using #Process 2 (see code & graphs below), what type of units am I looking at, dB?
  • If #Process 2 is not dB, then what is the best way to scale it to dB?

My code below (simplified) shows an example of what I'm talking about/looking at.

import numpy as np
from scipy.io.wavfile import read
from pylab import plot
from pylab import plot, psd, magnitude_spectrum
import matplotlib.pyplot as plt

#Hello Signal!!!
(fs, x) = read('C:\Desktop\Spectral Work\EB_AB_1_2.wav') 

#Remove silence out of beginning of signal with threshold of 1000 
def indices(a, func):
#This allows to use the lambda function for equivalent of find() in matlab
return [i for (i, val) in enumerate(a) if func(val)]

#Make the signal smaller so it uses less resources
x_tiny = x[0:100000]
#threshold is 1000, 0 is calling the first index greater than 1000
thresh = indices(x_tiny, lambda y: y > 1000)[1]
# backs signal up 20 bins, so to not ignore the initial pluck sound...
thresh_start = thresh-20
#starts at threshstart ends at end of signal (-1 is just a referencing     thing)
analysis_signal = x[thresh_start-1:] 

#Split signal so it is 1 second long
one_sec = 1*fs
onesec = x[thresh_start-1:one_sec+thresh_start-1]

#process 1
(spectrum, freqs, _) = magnitude_spectrum(onesec, Fs=fs) 
#process 2
spectrum1 = spectrum/len(spectrum)

I don't know how to bulk process on multiple .wav files so I run this code separately on a whole bunch of different .wav files and i put them into excel to compare. But for the sake of not looking at ugly graphs, I graphed it in Python. Here's what #process1 and #process2 look like when graphed:

Process 1

#Process 1

Process 2

#Process 2


Solution

  • Magnetude is just the absolute value of the frequency spectrum. As you have labelled in Process 1 "Energy" is a good way to think about it.

    Both Process 1 and Process 2 are in the same units. The only difference is that the values in Process 2 has been divided by the total length of the array (a scalar, hence no change of units). Normally this happens as part of the FFT, but sometimes it does not (e.g. numpy.FFT doesn't include the divide by length).

    The easiest way to scale it to dB is:

    (spectrum, freqs, _) = magnitude_spectrum(onesec, Fs=fs, scale='dB')

    If you wanted to do this yourself then you would need to do something like: spectrum2 = 20*numpy.log10(spectrum)

    **It is worth noting that I'm not sure if you should be applying the /len(spectrum) or not. I would suggest using the scale='dB' !!