八度:FFT相位谱不正确

时间:2016-10-01 16:39:41

标签: signal-processing fft octave phase

我用八度音程写的一个小程序没有产生所需的相位谱。虽然幅度图很完美。

 f = 200;
 fs = 1000;
 phase = pi/3; 
 t = 0: 1/fs: 1;
 sig = sin((2*pi*f*t) + phase);
 sig_fft = fft(sig);

 sig_fft_phase = angle(sig_fft) * 180/pi;

 sig_fft_phase(201)

sig_fft_phase(201)返回5.998(6度)而不是60度。我究竟做错了什么?我的期望不正确吗?

2 个答案:

答案 0 :(得分:4)

在你的例子中,如果你生成频率轴:(抱歉,我这里没有Octave,所以Python必须这样做 - 我确定它在Octave中是相同的):

faxis = (np.arange(0, t.size) / t.size) * fs

您会看到faxis[200](Python为0索引,相当于Octave的201索引) 199.80019980019981 。你认为你要的是200赫兹的相位,但你不是,你要的是相位为199.8赫兹。

(这是因为你的t向量包含1.0 - 一个额外的样本会略微减少光谱间距!我认为他们评论中张贴的链接@Sardar_Usama是正确的 - 它与正弦曲线不会在一个完整的循环中结束的事实无关,因为这种方法在不完整的循环中工作。)

解决方案:将1001长的sig向量填充到2000个样本。然后,使用新的faxis频率向量,faxis[400](Octave的第401个索引)恰好对应于200 Hz:

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°?

好吧,回想一下Euler’s formulasin(x) = (exp(i * x) - exp(-i * x)) / 2i。分母中的i表示即使输入正弦波具有60°的相位,FFT恢复的相位也不会是60°。相反,FFT bin的相位将为60 - 90度,因为-90°= angle(1/i) = angle(-i)。所以这实际上是正确的答案!要恢复正弦波的相位,您需要在FFT箱的相位上增加90°。

总而言之,你需要解决两件事:

  1. 确保您正在查看正确的频率仓。对于N点FFT(并且没有fftshift),这些区间为[0 : N - 1] / N * fs。上面,我们只使用N = 2000点FFT来确保表示200 Hz。
  2. 明白,虽然你有一个正弦波,但就FFT而言,它有两个复指数,分别为+200和-200Hz,振幅为1 /(2i)和-1 /(2i) 。分母中的虚拟值将您期望的相位分别移动-90°和+ 90°。
    • 如果你碰巧使用cos,余弦波,sig,你就不会遇到这个数学障碍,所以要注意罪和cos之间的区别在将来!

答案 1 :(得分:0)

更改为t=0:1/fs:1-1/fs;然后

 sig_fft_phase(201)
 ans = -30.000