我试图使用快速傅立叶变换来提取单个正弦函数的相移.我知道在纸上,如果我们将函数转换为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()
Run Code Online (Sandbox Code Playgroud)
使用num = 100000点我得到一个1.57173880459的阶段.
使用num = 10000点我得到一个1.58022110476的阶段.
使用num = 1000点我得到1.6650441064的阶段.
出了什么问题?即使有1000分,我每周期有33分,这应该足以解决它.有没有办法增加计算频率点的数量?有没有办法用"低"点数做到这一点?
编辑:从进一步的实验看来,我需要每周期~1000点才能准确地提取相.为什么?!
编辑2:进一步的实验表明,准确性与每个周期的点数有关,而不是绝对数.增加每个周期的采样点数可以使相位更准确,但如果信号频率和采样点数都增加相同因子,则精度保持不变.
您的点在间隔内的分布不均匀,最后的点加倍:0
与 相同1
。显然,你获得的分数越多,这一点就越不重要,但仍然会产生一些错误。你可以完全避免它,它linspace
有一个标志。它还具有一个标志,可dt
直接与数组一起返回您。
做
t, dt = np.linspace(0, 1, num_t, endpoint=False, retstep=True)
Run Code Online (Sandbox Code Playgroud)
代替
t = np.linspace(0,1,num_t)
dt = 1.0/num_t
Run Code Online (Sandbox Code Playgroud)
然后就可以了:)