Octave:Incorrect FFT相位谱
Octave:Incorrect FFT phase spectrum
我用 Octave 编写的一个小程序没有产生所需的相位谱。不过幅度图很完美。
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)
returns 5.998(6 度)而不是 60 度。我究竟做错了什么?我的期望不正确吗?
在您的示例中,如果您生成频率轴:(抱歉,我这里没有 Octave,所以 Python 必须这样做——我 确定 在 Octave 中也是一样的):
faxis = (np.arange(0, t.size) / t.size) * fs
你会看到 faxis[200]
(Python 是 0 索引,相当于 Octave 的 201 索引)是 199.80019980019981。你认为你要求的是 200 Hz 的相位,但你不是,你要求的是 199.8 Hz 的相位。
(发生这种情况是因为您的 t
向量包含 1.0——一个额外的样本会稍微减小光谱间距!我 不 认为 link @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 formula 说 sin(x) = (exp(i * x) - exp(-i * x)) / 2i
。分母中的 i
意味着 FFT 恢复的相位不会是 60°,即使输入正弦波具有 60° 的相位。相反,FFT bin 的相位将为 60 - 90
度,因为 -90° = angle(1/i) = angle(-i)
。所以这实际上是正确的答案!要恢复正弦波的相位,您需要将 FFT bin 的相位增加 90°。
总而言之,您需要解决两件事:
- 确保您查看的是正确的频点。对于
N
点 FFT(没有 fftshift
),bin 为 [0 : N - 1] / N * fs
。上面,我们只是使用了一个 N=2000 点的 FFT 来确保代表 200 Hz。
- 请理解,尽管您有一个正弦波,但就 FFT 而言,它会得到两个复指数,分别为 +200 和 -200 Hz,振幅为 1/(2i) 和 -1/( 2i).分母中的虚数值将您期望的相位分别移动 -90° 和 +90°。
- 如果你正好用了
cos
,一个余弦波,对于sig
,你就不会运行进入这个数学障碍了,所以付出以后注意sin和cos的区别!
改为t=0:1/fs:1-1/fs;
然后
sig_fft_phase(201)
ans = -30.000
我用 Octave 编写的一个小程序没有产生所需的相位谱。不过幅度图很完美。
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)
returns 5.998(6 度)而不是 60 度。我究竟做错了什么?我的期望不正确吗?
在您的示例中,如果您生成频率轴:(抱歉,我这里没有 Octave,所以 Python 必须这样做——我 确定 在 Octave 中也是一样的):
faxis = (np.arange(0, t.size) / t.size) * fs
你会看到 faxis[200]
(Python 是 0 索引,相当于 Octave 的 201 索引)是 199.80019980019981。你认为你要求的是 200 Hz 的相位,但你不是,你要求的是 199.8 Hz 的相位。
(发生这种情况是因为您的 t
向量包含 1.0——一个额外的样本会稍微减小光谱间距!我 不 认为 link @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 formula 说 sin(x) = (exp(i * x) - exp(-i * x)) / 2i
。分母中的 i
意味着 FFT 恢复的相位不会是 60°,即使输入正弦波具有 60° 的相位。相反,FFT bin 的相位将为 60 - 90
度,因为 -90° = angle(1/i) = angle(-i)
。所以这实际上是正确的答案!要恢复正弦波的相位,您需要将 FFT bin 的相位增加 90°。
总而言之,您需要解决两件事:
- 确保您查看的是正确的频点。对于
N
点 FFT(没有fftshift
),bin 为[0 : N - 1] / N * fs
。上面,我们只是使用了一个 N=2000 点的 FFT 来确保代表 200 Hz。 - 请理解,尽管您有一个正弦波,但就 FFT 而言,它会得到两个复指数,分别为 +200 和 -200 Hz,振幅为 1/(2i) 和 -1/( 2i).分母中的虚数值将您期望的相位分别移动 -90° 和 +90°。
- 如果你正好用了
cos
,一个余弦波,对于sig
,你就不会运行进入这个数学障碍了,所以付出以后注意sin和cos的区别!
- 如果你正好用了
改为t=0:1/fs:1-1/fs;
然后
sig_fft_phase(201)
ans = -30.000