使用 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:进一步的实验表明,准确性与每个周期的点数有关,而不是与绝对数有关。增加每个周期的采样点数使相位更准确,但如果信号频率和采样点数增加相同的因子,则精度保持不变。
您的点数在区间内分布不均,您的末尾点数翻了一番:0
与 1
的点数相同。显然,您获得的分数越多,这一点就越不重要,但仍然会出现一些错误。你可以完全避免它,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)
我正在尝试使用快速傅里叶变换来提取单个正弦函数的相移。我知道在纸上,如果我们将函数的变换表示为 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:进一步的实验表明,准确性与每个周期的点数有关,而不是与绝对数有关。增加每个周期的采样点数使相位更准确,但如果信号频率和采样点数增加相同的因子,则精度保持不变。
您的点数在区间内分布不均,您的末尾点数翻了一番:0
与 1
的点数相同。显然,您获得的分数越多,这一点就越不重要,但仍然会出现一些错误。你可以完全避免它,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)