Перед ответом просто небольшая заметка:
Удалите строку p[np.abs(Y) < 1] = 0
. Большая часть вашего спектра имеет величину ниже 1, поэтому с этой линией ваш спектр выглядит в основном как плоская линия в нуле.
Теперь к ответу:
phase_spectrum
делает три вещи, отличные от вас:
- Применяется разворачивание фазы.
- Если вы хотите применить развертывание фазы в вашем коде, просто выполните
np.unwrap(np.angle(Y))
. - Если вы хотите, чтобы matplotlib отображал спектр без развертывания, используйте
angle_spectrum
вместо этого.
- Применяет оконную функцию к данным перед вычислением спектра.
- Я знаю, что вы передали
window=None
, но по какой-то причине matplotlib решил, что window=None
означает "используйте окно Hanning, пожалуйста" (см. документы ). - Если вы не хотите, чтобы matplotlib применял окно, одно из решений - передать
window=lambda x: x
. - В документах фактически предлагается передать
window=matplotlib.mlab.window_none
, но source для него всего лишь def window_none(x): return x
.
- Он рассчитывает одностороннюю версию вашего спектра. docs говорят, что это значение по умолчанию, когда ввод действительный, а не сложный
- Чтобы получить обычную двустороннюю версию, передайте
sides='twosided'
на phase_spectrum
вызов.
Теперь о получении фазы с частотой f
:
Для этого вы должны использовать фазу без развертывания .
Вы правы, что можете t непосредственно извлекать фазу однотонального сигнала, если у вас нет целого числа циклов. Это связано с тем, что частота сингла не попадает точно в верхнюю часть частотного бина в БПФ. Вы можете получить приближение с фазой ближайшего бина, хотя. Вы можете также выполнить интерполяцию спектра sin c, чтобы получить его значение на нужной частоте.
Если вы заботитесь только о фазе single частота f
, тогда вы не должны использовать БПФ вообще. БПФ вычисляет фазу и амплитуду на всех частотах. Если вам нужна только одна частота, просто наберите Y_at_f = y @ np.exp(2j * np.pi * f * t)
и получите эту фазу на np.angle(Y_at_f)
.