I would like to keep here the knowledge I gained when I wrestled with matplotlib specgram in my research. Mainly on the following topics:
――Why is the upper limit of the frequency of the graph half of the frequency sample? --What happens if the frequency sample and data length do not match? ――Why is the length of the returned frequency data 129?
I think the following qiita article will be very helpful for basic variables. matplotlib specgram
First, let's try with dummy data. The following visualizes a sine wave with a frequency of 3000. The length of the sine wave data is 20000, and it is said that this data was observed in 1 second.
import matplotlib.pyplot as plt
import numpy as np
# freq_The unit of sample is Hz
freq_sample = 20000
#Data length and freq_It is important to understand the relationship of samples
x = np.linspace(0, 2*np.pi, freq_sample)
sin_signal = np.sin(3000*x)
fs = freq_sample
amplitude = 1
data = amplitude * sin_signal
list_data = data.tolist()
Pxx, freqs, bins, im = plt.specgram(list_data, Fs=fs, cmap = 'jet', mode='magnitude')
x1, x2, y1, y2 = plt.axis()
plt.axis((x1, x2, y1, y2))
plt.xlabel("time [s]")
plt.ylabel("frequency [Hz]")
plt.colorbar(im).set_label('Intensity [dB]')
plt.title(f"STFT Analysis of Waveform")
plt.show()
Obviously, it turns red at frequency 3000.
In the code, frequency_sample
is set to 20000Hz, but in the graph, the upper limit of the y-axis is 10000Hz. It seems that in specgram
, 0 is the lower limit and half of the sample frequency is the upper limit. It seems that the upper limit of this frequency is called the Nyquist frequency.
If you set freq_sample to 40000 as a trial, the upper limit is certainly halved to 20000.
freq_sample = 40000
x = np.linspace(0, 2*np.pi, freq_sample)
sin_signal = np.sin(3000*x)
The following stackoverflow was helpful.
What if the frequency sample remains 20000 and the data length is 5000?
freq_sample = 20000
x = np.linspace(0, 2*np.pi, 5000)
sin_signal = np.sin(3000*x)
The place at 8000Hz has turned red. The sin function hasn't changed, but the frequency has increased because the sample has changed. Furthermore, paying attention to the x-axis of the time unit, it has been reduced from 1 second to 0.25 seconds.
What if the length of the data is reversed to 60000?
freq_sample = 20000
x = np.linspace(0, 2*np.pi, 60000)
sin_signal = np.sin(3000*x)
This time around 1000Hz. In addition, the time axis extends to 3.0 seconds.
Pxx, freqs, bins, im = plt.specgram(lstrip, Fs=fs, cmap = 'jet', mode='magnitude')
print("freqs:")
print(freqs.shape)
print("Pxx")
print(Pxx.shape)
>> output:
freqs:
(129,)
Pxx
(129, 311)
This is because the number of samples when performing discrete Fourier transform is fixed and is 256
, and the number of overlaps is 128
, so it seems that it will be 256 // 2 + 1 = 129
.
129 is a half-hearted number, and it's a little annoying that you can't change it ...
The following stackoverflow was helpful.
Python - How to save spectrogram output in a text file?
I think that the unit is very important in making a graph, so it is necessary to carefully consider the relationship between the frequency sample and the length of the data.
Recommended Posts