#python #scipy #time-series #fft
#python #scipy #временные ряды #бпф
Вопрос:
Я ищу разъяснение того, что я ошибаюсь в своем понимании или реализации построения спектрограммы.
Чтобы быть уверенным, что я все понял правильно, я начал с игрушечного примера, поэтому я сгенерировал очень простой сигнал (сумма трех периодических сигналов разной частоты и фазового сдвига, без шума) в качестве исходного:
import numpy as np
sampling_rate = 1.0 / 1000
duration = 2
t = np.arange(0, duration, sampling_rate)
# Signal 1
A_1 = 0.8 # amplitude of the cosine wave
f_1 = 100 # frequency of the cosine wave
phase_1 = 30 #desired phase shift of the cosine in degrees
phi_1 = phase_1*np.pi/180
s1 = A_1*np.cos(2*np.pi*f_1*t phi_1)
# Signal 2
A_2 = 0.3 # amplitude of the cosine wave
f_2 = 8 # frequency of the cosine wave
phase_2 = 45 #desired phase shift of the cosine in degrees
phi_2 = phase_2*np.pi/180
s2 = A_2*np.cos(2*np.pi*f_2*t phi_2)
# Signal 3
A_3 = 0.1 # amplitude of the cosine wave
f_3 = 60 # frequency of the cosine wave
phase_3 = -10 #desired phase shift of the cosine in degrees
phi_3 = phase_3*np.pi/180
s3 = A_3*np.cos(2*np.pi*f_3*t phi_3)
# Result
x = s1 s2 s3
Я ожидал, что спектрограмма из сигнала «x» будет представлять собой три горизонтальные линии, соответствующие трем частотам сгенерированного сигнала. Сигнал не меняется со временем, поэтому я ожидал результатов, аналогичных FFT, но в другом представлении.
Но после построения графика с помощью приведенного ниже кода:
from scipy import signal
import matplotlib.pyplot as plt
freqs, times, spectrogram = signal.spectrogram(x)
plt.figure(figsize=(8, 6))
plt.imshow(spectrogram, aspect='auto', cmap='hot_r', origin='lower')
plt.title('Spectrogram')
plt.ylabel('Frequency band')
plt.xlabel('Time window')
plt.tight_layout()
Я получаю что-то совершенно неожиданное:
Найденные частоты не имеют смысла.
Итак, мой вопрос: где я допустил ошибку? Мои ожидания были неверными? Моя реализация каким-то образом испорчена? Может быть, кто-нибудь может порекомендовать мне хороший источник знаний по этой теме?
Заранее большое вам спасибо за ваше время и помощь.
Ответ №1:
Я нахожу ответ, прежде чем задать этот вопрос, поэтому вместо удаления всего поста я поделюсь с вами своим результатом. Я надеюсь, что кто-то может извлечь из этого пользу.
График хороший, но оси плохо подписаны. Если вы напрягаете глаза, вы заметите, что на самом деле есть три бара (самый слабый — около 15). Видимость линии пропорциональна значению амплитуды компонентного сигнала, что имеет смысл из-за цветовых кодов для амплитуды. Итак, теперь довольно легко заметить, что ось y по какой-то причине делится на 4. Аналогичная проблема с осью x, что становится еще более понятным, когда вы понимаете, что мы нигде не предоставляем информацию о частоте дискретизации.
Итак, теперь мы можем исправить эту проблему и изменить цветовую палитру по мере необходимости:
freqs, times, spectrogram = signal.spectrogram(x,fs=1./sampling_rate)
plt.figure(figsize=(8, 6))
plt.pcolormesh(times, freqs, spectrogram, shading='gouraud')
plt.ylabel('Frequency [Hz]')
plt.ylim([0,110])
plt.xlabel('Time [sec]')
plt.tight_layout()
plt.show()
Что приводит нас к ожидаемому результату (амплитуда для s2, умноженная на два):
Я надеюсь, что это полезно.