Почему функция matplotlib magnitude_spectrum показывает неправильные значения? - PullRequest
1 голос
/ 09 апреля 2020

Я создал аудиосэмпл длительностью 1 секунда, состоящий из двух синусоидальных волн, а затем использовал функцию спектра по амплитуде matplotlibs для построения спектра, и результаты оказались неверными. Две волны имеют одинаковую амплитуду на протяжении одной секунды аудиосэмпла, и, тем не менее, величины сильно различаются. Мне это показалось странным, поэтому я также использовал функции numpys для построения ДПФ, и величины точно такие же, как я думаю, и должны быть. Полученные графики показаны на рисунке ниже. Кто-нибудь знает, почему это может быть? Я сделал что-то не так в своем коде? Любая помощь будет очень ценной.

Минимальный рабочий пример:

import matplotlib.pyplot as plt
import numpy as np

sr = 20000
freq1 = 200
freq2 = 100
duration = 1

x = np.linspace(0, duration, sr * duration)
y = np.concatenate([0.5*np.sin(freq1 * 2 * np.pi * x[:10000]) + 0.5*np.sin(freq2 * 2 * np.pi * x[:10000]), np.sin(freq1 * 2 * np.pi * x[10000:15000]), np.sin(freq2 * 2 * np.pi * x[15000:20000])])

fig, ax = plt.subplots(3, 1, figsize=(12, 10))

ax[0].plot(x, y)
ax[0].axis(xmin=0, xmax=1)
ax[0].set_xlabel('Time [s]')
ax[0].set_ylabel('Amplitude [-]')

ax[1].magnitude_spectrum(y, Fs=sr, color='C1')
ax[1].axis(xmin=0, xmax=500)
ax[1].set_xlabel('Frequency [Hz]')
ax[1].set_ylabel('Magnitude [-]')

ax[2].plot(np.fft.rfftfreq(sr, d=1/sr), np.abs(np.fft.rfft(y, norm='ortho'))/100)
ax[2].axis(xmin=0, xmax=500)
ax[2].set_xlabel('Frequency [Hz]')
ax[2].set_ylabel('Magnitude [-]')

plt.tight_layout()
plt.show()

Image showing the signal and the two magnitude spectra, orange one is from matplotlib and blue one from numpy.

1 Ответ

2 голосов
/ 09 апреля 2020

Я думаю, что это связано с окном, используемым в matplotlib. По умолчанию используется окно Ханнинга, поэтому измените тип окна на window_none. Кроме того, способ масштабирования в обоих случаях различен. Сделав следующие изменения, вы увидите, что они оба совпадают.

from matplotlib import mlab
ax[1].magnitude_spectrum(y, Fs=sr, color='C1', window=mlab.window_none)

ax[2].plot(np.fft.rfftfreq(sr, d=1/sr), np.abs(np.fft.rfft(y))/sr)

приводит к enter image description here

...