在您的示例中,如果您生成频率轴:(抱歉,我这里没有Octave,所以只能使用Python - 我
确信在Octave中是相同的):
faxis = (np.arange(0, t.size) / t.size) * fs
你会发现
faxis [200]
(Python的索引从0开始,相当于Octave的201索引)为
199.80019980019981。你以为你在请求200Hz处的相位,但实际上不是,你在请求199.8 Hz 的相位。
(这是因为你的向量包括1.0-那一个额外的样本略微减少了频谱间距!我认为@Sardar_Usama在他们的评论中发布的链接不正确-它与正弦波没有结束在完整周期无关,因为这种方法应该可以使用不完整的周期解决。)
解决方案:将长度为1001的sig
向量填充为2000个样本。然后,使用新的faxis
频率向量,faxis[400]
(Octave的第401个索引)对应于确切的200Hz:
In [54]: sig_fft = fft.fft(sig, 2000);
In [55]: faxis = np.arange(0, sig_fft.size) / sig_fft.size * fs
In [56]: faxis[400]
Out[56]: 200.0
In [57]: np.angle(sig_fft[400]) * 180 / np.pi
Out[57]: -29.950454729683386
但是,糟糕的是,发生了什么?这里显示的角度是-30°?
好吧,回想一下
欧拉公式表明
sin(x) = (exp(i * x) - exp(-i * x)) / 2i
。分母中的
i
意味着FFT恢复的相位不会是60°,即使输入正弦波的相位为60°。相反,FFT频率的相位将是
60 - 90
度,因为-90°=
angle(1/i) = angle(-i)
。所以这实际上是正确的答案!要恢复正弦波的相位,您需要在FFT频率的相位上加上90°。
因此,总结起来,您需要解决两个问题:
- 确保你正在查看正确的频率区间。对于一个
N
-点FFT(没有 fftshift
),区间为 [0 : N - 1] / N * fs
。上面,我们只是使用了一个N=2000点的FFT来确保200 Hz被表示。
- 请注意,尽管你有一个正弦波,但就FFT而言,它会得到两个复指数,在+200和-200 Hz处,并且振幅分别为1 /(2i)和-1 /(2i)。分母中的虚数值将使你期望的相位分别向左偏移90°和向右偏移90°。
- 如果你刚好使用了余弦波cos作为sig,你就不会遇到这个数学障碍,所以以后要注意sin和cos之间的区别!