I have recorded some audio and would like to obtain a spectrum from it. As the audio is a real valued signal, I figure that I could perform a FFT with some window and obtain a spectrum for that period. There is the scipy.signal.spectrogram
function which can just do this in one go. This is the code that I have thrown together:
import numpy as np
import matplotlib.pyplot as pl
import scipy.io.wavfile
import scipy.fftpack
from scipy import signal
rate, data = scipy.io.wavfile.read('audio.wav')
N = rate // 10
f, t, Sxx = signal.spectrogram(data, rate, window=signal.blackman(N), nfft=N, mode='magnitude')
pl.pcolormesh(t, f, 10 * np.log10(Sxx), shading='auto', cmap='jet')
The sampling rate is 44100 Hz. I thought that using a window of 100 ms should give me a lower frequency of 10 Hz, which is fine for my purpose.
Looking at the resulting spectrum plots I see that the upper half of the frequency seems to be different from the lower part.
From the documentation I would have expected that I just get the real amplitude as return_onesided
defaults to True
. In general I would expect to have amplitudes and phases, or real and imaginary part. But with the spectrum I just want the amplitudes. Are they just the lower part?
And if so, why is the maximum frequency just around 11 kHz whereas the sampling frequency is 44 kHz and from the Nyquist–Shannon sampling theorem I'd expect to be able to resolve like 22 kHz?
Update: Other recording
Using my laptop with Audacity instead of my phone with SmartRecorder to record some audio, I have no strange upper half in the spectrum.
Update: Jet colormap
I was asked why I have been using Jet instead of Viridis. When using the latter for the spectrum plot, one cannot see so much of the structure.
I know that Jet isn't so great, but I just want to have more contrast.
jet
colormap? :) They got rid of that because it's misleading. The defaultviridis
is better $\endgroup$ – endolith Jan 30 at 21:39turbo
colormap would be better, then? $\endgroup$ – endolith Jan 31 at 19:43