Scipy FFT-如何获得相位角

时间:2019-01-31 06:39:26

标签: python scipy fft

使用python中的scipy fft模块无法获得简单正弦曲线的相位。我密切关注了this教程,并将matlab代码转换为python。但是,无论我在输入中使用哪个阶段,该图始终显示3。我缺少什么?

import numpy as np
import matplotlib.pyplot as plt
import scipy.fftpack
import cmath
A=10
fc = 10
phase=60
fs=32#Sampling frequency with oversampling factor of 32

t = np.arange(0,2,1/fs)

#Convert the phase shift to radians from degrees.
phi = phase*np.pi/180

x=A*np.cos(2*np.pi*fc*t+phi)

N=256
X = scipy.fftpack.fftshift(scipy.fftpack.fft(x,N))/N

df=fs/N #Frequency resolution.
sampleindex = np.arange(-N/2,N/2,1) #Ordered index for FFT plot.
f = sampleindex*df #x-axis index continued to ordered frequencies

raw_phases = np.angle(X)

X2=np.copy(X)#Store the FFT results in another array.
#Detect very small numbers and ignore them.
tau = max(abs(X))/10
X2[abs(X)<tau]=0

phase=[cmath.phase(i) for i in X2]
plt.plot(f,phase)
plt.show()

enter image description here

编辑:这是一些简单的代码。似乎仍然无法达到阶段。

y = 28*np.sin(2*np.pi/7*x)
yf = scipy.fftpack.fft(y)
xf = np.linspace(0.0, 1.0/(2.0*T), N/2)
phase = np.angle(yf)
yf = np.abs(yf[:N//2])
phase = phase[:N//2]
xf = xf[1:]
yf = yf[1:]
phase = phase[1:]
yf = yf-np.mean(yf)
#The frequencies seem to always be scaled by 0.1433, not sure why.
c = 2*np.pi/7/0.143301
freqs = xf[yf>np.std(yf)]*c
phases = phase[yf>np.std(yf)]

我得到的频率聚集在2 * np.pi / 7附近。但是我得到的阶段是:

array([-0.217795  , -0.22007488, -0.22226087,  2.91723935,  2.91524011,
    2.91333367])

根本没有相位。

2 个答案:

答案 0 :(得分:1)

FFT测量循环相位,同时参考输入数据窗口的开始和结束。如果您输入的正弦波在FFT孔径中不是正整数周期,则窗口开始和结束之间的相位之间将存在不连续性,因此FFT相位测量将不是您期望的。

相反,我建议您在数据窗口中间(N / 2)而不是开始处的所需相位处开始(或参考)输入正弦波。然后在FFT之前执行循环fftshift。最终的FFT相位测量结果将表示相对于原始数据窗口中间的相位,在该中间没有间断;和atan2()代表的是连续输入波形的偶数和奇数分量之间的比率,这是通常所期望的。

答案 1 :(得分:1)

这是说明如何获得角度的最简单的代码。

请注意,我创建的信号y使得其中包含整数个周期(如我建议的in a comment和@ hotpaw2建议的in their answer)。

这是OP代码的问题。

我使用linspace选项通过endpoint=False创建了时间轴。这很重要,如果t包含数字10,那么我们将不再有精确的整数个句号。当与离散傅里叶变换工作,它有助于想到的,当你重复的信号会发生什么。只需获取y,然后连接其自身的副本:np.hstack((y,y))。这个新信号仍然是单个正弦波的采样,还是我们创建了更复杂的信号?在两个副本相遇的那一点会发生什么?

import numpy as np
import matplotlib.pyplot as plt
import scipy.fftpack

phase = np.pi / 4
t = np.linspace(0, 10, num=200, endpoint=False)
y = np.cos(2 * np.pi * t + phase)
Y = scipy.fftpack.fftshift(scipy.fftpack.fft(y))
f = scipy.fftpack.fftshift(scipy.fftpack.fftfreq(len(t)))

p = np.angle(Y)
p[np.abs(Y) < 1] = 0
plt.plot(f, p)
plt.show()

plot of the phase of the Frequency spectrum of a pure sine wave