How to create a spectrogram of a 1D signal in python?

I am not sure how to do this, and I was given an example, spectrogram, for example , but this is in 2D.

I have a code here that generates a mixture of frequencies and I can select them in fft, how can I see them in the spectrogram? I understand that the frequencies in my example do not change with time; Does this mean that I will see a straight line in the spectrogram?

my code and output image:

# create a wave with 1Mhz and 0.5Mhz frequencies dt = 2e-9 t = np.arange(0, 10e-6, dt) y = np.cos(2 * pi * 1e6 * t) + (np.cos(2 * pi * 2e6 *t) * np.cos(2 * pi * 2e6 * t)) y *= np.hanning(len(y)) yy = np.concatenate((y, ([0] * 10 * len(y)))) # FFT of this Fs = 1 / dt # sampling rate, Fs = 500MHz = 1/2ns n = len(yy) # length of the signal k = np.arange(n) T = n / Fs frq = k / T # two sides frequency range frq = frq[range(n / 2)] # one side frequency range Y = fft(yy) / n # fft computing and normalization Y = Y[range(n / 2)] / max(Y[range(n / 2)]) # plotting the data subplot(3, 1, 1) plot(t * 1e3, y, 'r') xlabel('Time (micro seconds)') ylabel('Amplitude') grid() # plotting the spectrum subplot(3, 1, 2) plot(frq[0:600], abs(Y[0:600]), 'k') xlabel('Freq (Hz)') ylabel('|Y(freq)|') grid() # plotting the specgram subplot(3, 1, 3) Pxx, freqs, bins, im = specgram(y, NFFT=512, Fs=Fs, noverlap=10) show() 

output file

+6
source share
3 answers

What you have is technically correct, but you just need to look at the signal with an interesting spectrogram. To do this, you need a frequency over time. (And for this, you need a lot of oscillation, since it takes a few oscillations to set the frequency, and then you need many of them to be able to change the frequency over time in an interesting way.)

Below I have changed the code as little as possible to get a frequency that does something interesting ( fscale just increases the frequency over time). I am sending all the code to make it work, but I only change three of the four top lines.

enter image description here

 # create a wave with 1Mhz and 0.5Mhz frequencies dt = 40e-9 t = np.arange(0, 1000e-6, dt) fscale = t/max(t) y = np.cos(2 * pi * 1e6 * t*fscale) + (np.cos(2 * pi * 2e6 *t*fscale) * np.cos(2 * pi * 2e6 * t*fscale)) y *= np.hanning(len(y)) yy = np.concatenate((y, ([0] * 10 * len(y)))) # FFT of this Fs = 1 / dt # sampling rate, Fs = 500MHz = 1/2ns n = len(yy) # length of the signal k = np.arange(n) T = n / Fs frq = k / T # two sides frequency range frq = frq[range(n / 2)] # one side frequency range Y = fft(yy) / n # fft computing and normalization Y = Y[range(n / 2)] / max(Y[range(n / 2)]) # plotting the data subplot(3, 1, 1) plot(t * 1e3, y, 'r') xlabel('Time (micro seconds)') ylabel('Amplitude') grid() # plotting the spectrum subplot(3, 1, 2) plot(frq[0:600], abs(Y[0:600]), 'k') xlabel('Freq (Hz)') ylabel('|Y(freq)|') grid() # plotting the specgram subplot(3, 1, 3) Pxx, freqs, bins, im = specgram(y, NFFT=512, Fs=Fs, noverlap=10) show() 

Also, note that only the spectrogram is useful. If you see a good waveform or spectra, then spectrograms probably will not be interesting: 1) if the waveform is clear, you probably do not have enough data and time during which the frequency is determined and changed enough to be interesting; 2) if the full spectra are clear, you probably do not have a sufficient change in frequency for the spectrogram, since the spectrum is basically just the average of what you see over time in the spectrogram.

If you really want to see the spectrogram of your original signal, you just need to increase the y axis to see the expected peaks (note that the y axis of the spectrograms is 2.5e8, it should be larger than in your spectrum): enter image description here

+8
source

To get what you need:

1) a sample 1d of a signal at a high frequency (at least 5 times the frequency of its highest frequency component)

2) use blocks of samples (power 2, for example, 1024.16384, etc.) to calculate the FFT

3) for each spectrum graph, a vertical line of pixels whose color represents the amplitude of each frequency.

4) Repeat steps 2 and 3 for each block of samples.

In your case, the plot has a whole rainbow of colors, which should not be present only with pairs of very different frequencies. Your spectral graph has fairly wide bands around the peaks, but this may be due to the low sampling rate and smooth plotting.

+2
source

I'm just starting out with Python 3.6. Thanks for the Spectrogram sample sample!

However, with Python 3.6, I tried a little to make this spectrogram code sample workable (function calls and float division I edited the code, so it now works on python 3.6 for my python novice friends.

Enjoy

 ''' Original Script for Python 2.7 https://stackoverflow.com/questions/19052324/how-do-i-generate-a-spectrogram-of-a-1d-signal-in-python Modified in August 2017 for Python 3.6 Python 2.7 two integers / Division generate Integer Python 3.6 two integers / Division generate Float Python 3.6 two integers // Division generate integer ''' import numpy as np from scipy import fftpack import matplotlib.pyplot as plt dt = 40e-9 t = np.arange(0, 1000e-6, dt) fscale = t/max(t) y = np.cos(2 * np.pi * 1e6 * t*fscale) + (np.cos(2 * np.pi * 2e6 *t*fscale) * np.cos(2 * np.pi * 2e6 * t*fscale)) y *= np.hanning(len(y)) yy = np.concatenate((y, ([0] * 10 * len(y)))) # FFT of this Fs = 1 / dt # sampling rate, Fs = 500MHz = 1/2ns n = len(yy) # length of the signal k = np.arange(n) T = n / Fs frq = k / T # two sides frequency range frq = frq[range(n // 2)] # one side frequency range Y = fftpack.fft(yy) / n # fft computing and normalization Y = Y[range(n // 2)] / max(Y[range(n // 2)]) # plotting the data plt.subplot(3, 1, 1) plt.plot(t * 1e3, y, 'r') plt.xlabel('Time (micro seconds)') plt.ylabel('Amplitude') plt.grid() # plotting the spectrum plt.subplot(3, 1, 2) plt.plot(frq[0:600], abs(Y[0:600]), 'k') plt.xlabel('Freq (Hz)') plt.ylabel('|Y(freq)|') plt.grid() # plotting the specgram plt.subplot(3, 1, 3) Pxx, freqs, bins, im = plt.specgram(y, NFFT=512, Fs=Fs, noverlap=10) plt.show() 
0
source

Source: https://habr.com/ru/post/954782/