Using matplotlib to create a spectrogram of a wavfile - python

import scipy.io.wavfile as wav
import matplotlib.pyplot as plt
import scipy
sample_rate, X = wav.read("/Users/sinaastani/Downloads/partynextdoor.wav")
X = scipy.mean(X, axis=1)
plt.specgram(X, Fs=sample_rate, xextent=(0,30))
I get an error whenever I run the code above:
/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/matplotlib/axes/_axes.py:7017: RuntimeWarning: divide by zero encountered in log10
Z = 10. * np.log10(spec)
This occurs with several wav files that I have tried. I'm simply trying to replicate an example from "Building Machine Learning Systems with Python - Second Edition".
The wavfile.read function returns a numpy array. It looks like at the beginning and end of this array, there are a bunch of 0 values so when it tries to calculate log(0) it is undefined. What is the appropriate to deal with this? Should I simply get rid of 0 values from the array?

Use the parameter NFFT of plt.specgram(). Because this parameter defaults to 256, it causes the error. You can increase this number by multiplying it to 2 to the extent by which the error disappears. Try 512 - 1024 - 2048 , ... and the problem is solved!:)

Related

WAV FFT: Slice indices must be integers

I am trying to perform some analysis on a .wav file, I have taken the code from the following question (Python Scipy FFT wav files) and it seems to give exactly what I need however when running the code I run into the following error:
TypeError: slice indices must be integers or None or have an index method
This occurs on line 9 of my code. I don't undertand why this occurs, because I thought that the abs function would make it an integer.
import matplotlib.pyplot as plt
from scipy.fftpack import fft
from scipy.io import wavfile # get the api
fs, data = wavfile.read('New Recording 2.wav') # load the data
a = data.T[0] # this is a two channel soundtrack, I get the first track
b=[(ele/2**8.)*2-1 for ele in a] # this is 8-bit track, b is now normalized on [-1,1)
c = fft(b) # calculate fourier transform (complex numbers list)
d = len(c)/2 # you only need half of the fft list (real signal symmetry)
plt.plot(abs(c[:(d-1)]),'r')
plt.show()
plt.savefig("Test.png", bbox_inches = "tight")
abs() doesn't make your number into an integer. It just turns negative numbers into positive numbers. When len(c) is an odd number your variable d is a float that ends in x.5.
What you want is probably round(d) instead of abs(d)

Runtime warning while trying to write equation for line

Equation
This link goes to the picture of the equation i am trying to graph in matplotlib
from matplotlib import pyplot as plt
import numpy as np
x_values = np.arange(1, 10, step=0.1)
y_values = (np.arcsin(np.sqrt(abs(np.sin(x_values) ** (abs(np.cos(x_values)) + abs(np.sin(x_values)) + (2.718281828459045** np.sin(x_values)))))) - x_values)/x_values
The code above throws the following error message:
ipykernel_launcher.py:4: RuntimeWarning: invalid value encountered in power
after removing the cwd from sys.path.
I didn't get to the plotting because this code alone threw an error message
How can i fix this?
numpy does not allow fractional powers of negative numbers, since it expects a complex result and you did not define a complex type. You can inspect your power array like this:
pow = abs(np.cos(x_values)) + abs(np.sin(x_values)) + (2.718281828459045** np.sin(x_values))
a = np.sin(x_values)
and use a workaround like this:
a_pow = np.sign(a) * (np.abs(a)) ** (pow)
y_values = (np.arcsin(np.sqrt(abs(a_pow))) - x_values)/x_values
But make sure in advance that you are not expecting complex numbers as results!
If you do though, change your array dtype to np.complex.

Is it possible to resolve filter rounding errors between MATLAB and Python?

I'm trying to replicate some Matlab code into Python and at the moment im developing a unit test to check for equivalence. In the code below I get errors in the order of E-11 which indicates to me that it could possibly be a rounding error.
Matlab Code:
width = 200;
x = 1:100000;
b = ones(width,1)/width;
y = filter(b, 1, x);
save('mat_data')
Python Code:
import numpy as np
from scipy.io import loadmat
from scipy import signal
def plot_fig(x, y=None):
import matplotlib.pyplot as plt
if y is None:
y = x
x = np.arange(0, len(y))
plt.figure()
plt.plot(x, y)
plt.show()
def mat_data(param):
data = loadmat('mat_data.mat')
return np.squeeze(data[param])
y = signal.lfilter(mat_data('b'), 1, mat_data('x'), axis=0)
plot_fig(mat_data('y') - y)
I have used the loadmat function to ensure equivalence between the numerical arrays I use as function inputs. The resulting plot is:
difference plot
I see that the error is small, so could be rounding errors, but it does also seem to accumulate which worries me.
At the moment the application I'm working on is critical to ensure the binary equivalence between the two codes (matlab and python) so I would greatly appreciate any help in resolving this disparity.
Thanks in advance,
A.
You could try double precision floats rather than single precision in python.
I think that would reduce accumulating rounding error significantly.

Play square wave SciPy and PyAudio

I'm trying to play square waves generated using SciPy with PyAudio but I get the error
TypeError: len() of unsized object
which is kind of strange because the square wave object should have a size, right?
RATE = 48000
p = pyaudio.PyAudio()
stream = p.open(format = pyaudio.paInt16,
channels = 2,
rate = RATE,
output = True)
# ... inside a loop
wav = signal.square(2*math.pi*FREQ*t)
wav = wav.astype(np.int16)
stream.write(wav) # crash here
The crash happens on the first iteration of the loop, so I suppose the loop is not a problem.
I get the same error. However, you are omitting some information, so I will assume these are your imports:
import pyaudio
import math
import numpy as np
from scipy import signal
And that
FREQ = 440
It looks like the variable you are iterating is t and it's a scalar. You might have good reasons to do this, but I don't think it is how scipy.signal is meant to work. If you use a vector t instead:
t = np.linspace(0, 2)
Then signal.square(...) and stream.write(wav.astype(np.int16)) work without problems.

What's the correct usage of matplotlib.mlab.normpdf()?

I intend for part of a program I'm writing to automatically generate Gaussian distributions of various statistics over multiple raw text sources, however I'm having some issues generating the graphs as per the guide at:
python pylab plot normal distribution
The general gist of the plot code is as follows.
import numpy as np
import matplotlib.mlab as mlab
import matplotlib.pyplot as pyplot
meanAverage = 222.89219487179491 # typical value calculated beforehand
standardDeviation = 3.8857889432054091 # typical value calculated beforehand
x = np.linspace(-3,3,100)
pyplot.plot(x,mlab.normpdf(x,meanAverage,standardDeviation))
pyplot.show()
All it does is produce a rather flat looking and useless y = 0 line!
Can anyone see what the problem is here?
Cheers.
If you read documentation of matplotlib.mlab.normpdf, this function is deprycated and you should use scipy.stats.norm.pdf instead.
Deprecated since version 2.2: scipy.stats.norm.pdf
And because your distribution mean is about 222, you should use np.linspace(200, 220, 100).
So your code will look like:
import numpy as np
from scipy.stats import norm
import matplotlib.pyplot as pyplot
meanAverage = 222.89219487179491 # typical value calculated beforehand
standardDeviation = 3.8857889432054091 # typical value calculated beforehand
x = np.linspace(200, 220, 100)
pyplot.plot(x, norm.pdf(x, meanAverage, standardDeviation))
pyplot.show()
It looks like you made a few small but significant errors. You either are choosing your x vector wrong or you swapped your stddev and mean. Since your mean is at 222, you probably want your x vector in this area, maybe something like 150 to 300. This way you get all the good stuff, right now you are looking at -3 to 3 which is at the tail of the distribution. Hope that helps.
I see that, for the *args which are sending meanAverage, standardDeviation, the correct thing to be sent is:
mu : a numdims array of means of a
sigma : a numdims array of atandard deviation of a
Does this help?

Categories