使用 numpy fft 提取相位信息

extracting phase information using numpy fft

我正在尝试使用快速傅里叶变换来提取单个正弦函数的相移。我知道在纸上,如果我们将函数的变换表示为 T,那么我们有以下关系:

但是,我发现虽然我能够准确捕获余弦波的频率,但相位不准确,除非我以极高的速率进行采样。例如:

import numpy as np
import pylab as pl

num_t = 100000
t = np.linspace(0,1,num_t)
dt = 1.0/num_t
w = 2.0*np.pi*30.0
phase = np.pi/2.0

amp = np.fft.rfft(np.cos(w*t+phase))
freqs = np.fft.rfftfreq(t.shape[-1],dt)

print (np.arctan2(amp.imag,amp.real))[30]

pl.subplot(211)
pl.plot(freqs[:60],np.sqrt(amp.real**2+amp.imag**2)[:60])
pl.subplot(212)
pl.plot(freqs[:60],(np.arctan2(amp.imag,amp.real))[:60])
pl.show()

使用 num=100000 点我得到 1.57173880459 的相位。

使用 num=10000 点我得到 1.58022110476 的相位。

使用 num=1000 点我得到 1.6650441064 的相位。

怎么了?即使有1000分我每个周期有33分,这应该足以解决它。有没有办法增加计算频率点的数量?有没有办法用“低”点数做到这一点?

编辑:从进一步的实验来看,我似乎每个周期需要 ~1000 个点才能准确提取相位。为什么?!

编辑 2:进一步的实验表明,准确性与每个周期的点数有关,而不是与绝对数有关。增加每个周期的采样点数使相位更准确,但如果信号频率和采样点数增加相同的因子,则精度保持不变。

您的点数在区间内分布不均,您的末尾点数翻了一番:01 的点数相同。显然,您获得的分数越多,这一点就越不重要,但仍然会出现一些错误。你可以完全避免它,linspace 有一个标志。它还有一个标志 return 你 dt 直接和数组一起。

t, dt = np.linspace(0, 1, num_t, endpoint=False, retstep=True)

而不是

t = np.linspace(0,1,num_t)
dt = 1.0/num_t

然后就可以了:)

只有当输入信号在 FFT 长度内 正好 整数周期时,未旋转 FFT 的结果 bin 中的相位值才是正确的。您的测试信号不是,因此 FFT 测量的部分与测试正弦波端点之间信号不连续性的相位差部分相关。更高的采样率会产生与正弦曲线略有不同的最后终点,因此可能会产生更小的不连续性。

如果您想减少此 FFT 相位测量误差,请创建您的测试信号,以便您的测试相位参考测试矢量(不是第一个样本)的确切中心(样本 N/2),然后进行 fftshift 操作(旋转 N/2),这样在得到的长度为 N.

的 FFT 输入向量中的第一个点和最后一个点之间就没有信号不连续性

这段代码可能会有所帮助:

def reconstruct_ifft(data):
"""
In this function, we take in a signal, find its fft, retain the dominant modes and reconstruct the signal from that

Parameters
----------
data : Signal to do the fft, ifft

Returns 
-------
reconstructed_signal : the reconstructed signal

"""
N = data.size
yf = rfft(data)

amp_yf = np.abs(yf) #amplitude

yf = yf*(amp_yf>(THRESHOLD*np.amax(amp_yf)))

reconstructed_signal = irfft(yf)

return reconstructed_signal

0.01 是您想要保留的 fft 幅度阈值。使阈值更大(超过 1 没有任何意义),将给出 更少的模式并导致更高的均方根误差,但确保更高的频率选择性。 (请调整 python 代码的 TABS)