[PYTHON] Unravel the mystery of matplotlib specgram

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, visualize with dummy data

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.

sample-qiita.png

Why the upper limit of the frequency of the graph is half of the frequency sample

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)

Figure_1.png

The following stackoverflow was helpful.

How to change pyplot.specgram x and y axis scaling?

What happens if the frequency sample and data lengths do not match

Frequency sample> Data length: Higher frequency and shorter time

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.

Figure_1.png

Frequency sample <Data length: lower frequency, longer time

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)

Figure_1.png

This time around 1000Hz. In addition, the time axis extends to 3.0 seconds.

Why is the length of frequency data returned 129?

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?

Conclusion

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

Unravel the mystery of matplotlib specgram
Change the style of matplotlib
About the size of matplotlib points
Align the size of the colorbar with matplotlib
About the X-axis notation of Matplotlib bar graphs
Increase the font size of the graph with matplotlib
One liner that lists the colors of matplotlib
Put the second axis in 2dhistgram of matplotlib
The basis of graph theory with matplotlib animation
Code for checking the operation of Python Matplotlib
Visualize the behavior of the sorting algorithm with matplotlib
The beginning of cif2cell
Add information to the bottom of the figure with Matplotlib
The meaning of self
Omit the decimal point of the graph scale in matplotlib
the zen of Python
[Introduction to Python] Basic usage of the library matplotlib
Installation of matplotlib (Python 3.3.2)
Adjust the ratio of multiple figures with the matplotlib gridspec
Revenge of the Types: Revenge of types
Python Note: The mystery of assigning a variable to a variable
[Memo] The mystery of cumulative assignment statements in Python functions
Follow the mystery of orthographic-pedant that suddenly appeared on GitHub !!
Reformat the timeline of the pandas time series plot with matplotlib
Let's visualize the number of people infected with coronavirus with matplotlib
I wrote the basic operation of matplotlib with Jupyter Lab
Output the result of gradient descent method as matplotlib animation
Align the version of chromedriver_binary
Scraping the result of "Schedule-kun"
10. Counting the number of lines
The story of building Zabbix 4.4
[Apache] The story of prefork
Japanese display of matplotlib, seaborn
The road to download Matplotlib
Compare the fonts of jupyter-themes
behavior of matplotlib: histogram normed
About the ease of Python
Get the number of digits
Explain the code of Tensorflow_in_ROS
Reuse the results of clustering
GoPiGo3 of the old man
Calculate the number of changes
Change the theme of Jupyter
The popularity of programming languages
Visualize the orbit of Hayabusa2
About the components of Luigi
Connected components of the graph
Filter the output of tracemalloc
About the features of Python
Simulation of the contents of the wallet
The Power of Pandas: Python
Color extraction with Python + OpenCV solved the mystery of the green background
Change the Y-axis scale of Matplotlib to exponential notation (10 Nth power notation)
Find out the mystery change of Pokédex description by Levenshtein distance