Scipy FFT - 如何获得相位角
Scipy FFT - how to get phase angle
我在使用 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])
虽然根本不应该有相位。
FFT 测量循环相位,参考输入数据的最开始和最结束 window。如果您的输入正弦波在 FFT 孔径中不完全是整数周期,那么 window 开始和结束的相位之间将存在不连续性,因此 FFT 相位测量将不是您可能的结果期待。
相反,我建议在数据 window(在 N/2)的所需相位开始(或参考)输入正弦波,而不是开始。然后在FFT之前做一个循环fftshift。由此产生的 FFT 相位测量将代表相对于原始数据 window 中间的相位,其中没有不连续性;和 atan2() 将代表连续输入波形的偶数和奇数分量之间的比率,这是更常见的预期。
这是展示如何获取角度的最简单的代码。
请注意,我创建了信号 y
,其中包含整数个周期(正如我所建议的 , and @hotpaw2 suggested )。
这是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()
我在使用 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])
虽然根本不应该有相位。
FFT 测量循环相位,参考输入数据的最开始和最结束 window。如果您的输入正弦波在 FFT 孔径中不完全是整数周期,那么 window 开始和结束的相位之间将存在不连续性,因此 FFT 相位测量将不是您可能的结果期待。
相反,我建议在数据 window(在 N/2)的所需相位开始(或参考)输入正弦波,而不是开始。然后在FFT之前做一个循环fftshift。由此产生的 FFT 相位测量将代表相对于原始数据 window 中间的相位,其中没有不连续性;和 atan2() 将代表连续输入波形的偶数和奇数分量之间的比率,这是更常见的预期。
这是展示如何获取角度的最简单的代码。
请注意,我创建了信号 y
,其中包含整数个周期(正如我所建议的
这是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()