fft.fft() 的幅度和相位(角度)输出与设置的值不对应
Output of fft.fft() for magnitude and phase (angle) not corresponding the the values set up
我设置了一定幅度、频率和相位的正弦波,并尝试恢复幅度和相位:
import numpy as np
import matplotlib.pyplot as plt
N = 1000 # Sample points
T = 1 / 800 # Spacing
t = np.linspace(0.0, N*T, N) # Time
frequency = np.fft.fftfreq(t.size, d=T) # Normalized Fourier frequencies in spectrum.
f0 = 25 # Frequency of the sampled wave
phi = np.pi/6 # Phase
A = 50 # Amplitude
s = A * np.sin(2 * np.pi * f0 * t - phi) # Signal
S = np.fft.fft(s) # Unnormalized FFT
fig, [ax1,ax2] = plt.subplots(nrows=2, ncols=1, figsize=(10, 5))
ax1.plot(t,s,'.-', label='time signal')
ax2.plot(freq[0:N//2], 2/N * np.abs(S[0:N//2]), '.', label='amplitude spectrum')
plt.show()
index, = np.where(np.isclose(frequency, f0, atol=1/(T*N))) # Getting the normalized frequency close to f0 in Hz)
magnitude = np.abs(S[index[0]]) # Magnitude
phase = np.angle(S[index[0]]) # Phase
print(magnitude)
print(phase)
phi
#21785.02149316858
#-1.2093259641890741
#0.5235987755982988
现在幅度应该是 50,而不是 21785,相位 pi/6=0.524,而不是 -1.2。
我是不是误解了输出,或者上面 link 中提到的 post 的答案?
- 您需要通过以下两个更改之一将 fft 标准化为 1/N(我使用了第二个):
S = np.fft.fft(s)
--> S = 1/N*np.fft.fft(s)
magnitude = np.abs(S[index[0]])
--> magnitude = 1/N*np.abs(S[index[0]])
- 不要使用
index, = np.where(np.isclose(frequency, f0, atol=1/(T*N)))
,fft 不准确,最大幅度可能
不是 f0
,而是使用 np.argmax(np.abs(S))
您的信号峰值非常接近 f0
- np.angle 搞砸了(我认为它是 pi,pi/2 arctan 偏移量之一
事情)只需用
np.arctan(np.real(x)/np.imag(x))
手动完成
- 使用更多点(我使
N
更高)并使 T
更小以获得更高的准确性
- 由于 DFT(离散傅立叶变换)是双面的,并且在负频率和正频率中都有峰值信号,因此正侧的峰值只会是实际幅度的一半。对于 fft,除了
f=0
之外,您需要将每个频率乘以 2 才能解决这个问题。我在 magnitude = np.abs(S[index])*2/N
中乘以 2
N = 10000
T = 1/5000
...
index = np.argmax(np.abs(S))
magnitude = np.abs(S[index])*2/N
freq_max = frequency[index]
phase = np.arctan(np.imag(S[index])/np.real(S[index]))
print(f"magnitude: {magnitude}, freq_max: {freq_max}, phase: {phase}") print(phi)
输出:magnitude: 49.996693276663564, freq_max: 25.0, phase: 0.5079341239733628
我设置了一定幅度、频率和相位的正弦波,并尝试恢复幅度和相位:
import numpy as np
import matplotlib.pyplot as plt
N = 1000 # Sample points
T = 1 / 800 # Spacing
t = np.linspace(0.0, N*T, N) # Time
frequency = np.fft.fftfreq(t.size, d=T) # Normalized Fourier frequencies in spectrum.
f0 = 25 # Frequency of the sampled wave
phi = np.pi/6 # Phase
A = 50 # Amplitude
s = A * np.sin(2 * np.pi * f0 * t - phi) # Signal
S = np.fft.fft(s) # Unnormalized FFT
fig, [ax1,ax2] = plt.subplots(nrows=2, ncols=1, figsize=(10, 5))
ax1.plot(t,s,'.-', label='time signal')
ax2.plot(freq[0:N//2], 2/N * np.abs(S[0:N//2]), '.', label='amplitude spectrum')
plt.show()
index, = np.where(np.isclose(frequency, f0, atol=1/(T*N))) # Getting the normalized frequency close to f0 in Hz)
magnitude = np.abs(S[index[0]]) # Magnitude
phase = np.angle(S[index[0]]) # Phase
print(magnitude)
print(phase)
phi
#21785.02149316858
#-1.2093259641890741
#0.5235987755982988
现在幅度应该是 50,而不是 21785,相位 pi/6=0.524,而不是 -1.2。
我是不是误解了输出,或者上面 link 中提到的 post 的答案?
- 您需要通过以下两个更改之一将 fft 标准化为 1/N(我使用了第二个):
S = np.fft.fft(s)
-->S = 1/N*np.fft.fft(s)
magnitude = np.abs(S[index[0]])
-->magnitude = 1/N*np.abs(S[index[0]])
- 不要使用
index, = np.where(np.isclose(frequency, f0, atol=1/(T*N)))
,fft 不准确,最大幅度可能 不是f0
,而是使用np.argmax(np.abs(S))
您的信号峰值非常接近f0
- np.angle 搞砸了(我认为它是 pi,pi/2 arctan 偏移量之一
事情)只需用
np.arctan(np.real(x)/np.imag(x))
手动完成
- 使用更多点(我使
N
更高)并使T
更小以获得更高的准确性 - 由于 DFT(离散傅立叶变换)是双面的,并且在负频率和正频率中都有峰值信号,因此正侧的峰值只会是实际幅度的一半。对于 fft,除了
f=0
之外,您需要将每个频率乘以 2 才能解决这个问题。我在magnitude = np.abs(S[index])*2/N
中乘以 2
N = 10000
T = 1/5000
...
index = np.argmax(np.abs(S))
magnitude = np.abs(S[index])*2/N
freq_max = frequency[index]
phase = np.arctan(np.imag(S[index])/np.real(S[index]))
print(f"magnitude: {magnitude}, freq_max: {freq_max}, phase: {phase}") print(phi)
输出:magnitude: 49.996693276663564, freq_max: 25.0, phase: 0.5079341239733628