使用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()
编辑:这是一些简单的代码。似乎仍然无法达到阶段。
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])
根本没有相位。
答案 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()