You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python中FFT处理正弦信号时正负频分量问题求解

解决实信号FFT正负频率分量问题

问题原因

实值信号的FFT结果天生具有共轭对称性:正频率分量和对应的负频率分量幅值相等、相位相反。你看到的“20000Hz附近的分量”其实是-50Hz的频率被折叠到了采样频率Fs(这里Fs=20000Hz)的后半段,本质就是负频率分量。单独只保留正频率分量做IFFT,得到的会是复信号,自然还原不了原来的实正弦波。

两种解决方法

方法1:用实信号专用的rfft/irfft(推荐)

scipy.fftpack提供了rfft()和irfft(),专门针对实信号优化:rfft()只返回正频率部分(包括0Hz),点数为N//2 +1,避免了冗余的负频率分量;irfft()可以直接从正频率结果还原出实信号,不需要额外处理。

修改你的代码如下:

from scipy.fftpack import rfft, irfft
import matplotlib.pyplot as plt
import numpy as np

tt = np.arange(0, 0.02, 50e-6)
xx = np.sin(2*np.pi*50*tt)

# 用rfft计算实信号的FFT
XX_r = rfft(xx)
N = len(tt)
Fs = 1 / 50e-6
# 构造正频率轴:0到Fs/2
ff_r = np.linspace(0, Fs/2, len(XX_r))

plt.figure(figsize=(12, 6))
plt.subplot(121)
plt.plot(ff_r, np.abs(XX_r))
plt.xlabel('Freq (Hz)')
plt.ylabel('FFT Amplitude')
plt.title('RFFT结果(仅正频率)')

plt.subplot(122)
# 用irfft直接还原实信号
xx_recon = irfft(XX_r)
plt.plot(tt, xx_recon, 'r-')
plt.xlabel('Time (s)')
plt.ylabel('Amplitude')
plt.title('IRFFT还原信号')
plt.tight_layout()
plt.show()

这样你只会看到50Hz的单分量,且还原的信号和原信号完全一致。

方法2:手动处理普通FFT的对称分量

如果一定要用普通fft(),需要手动构造共轭对称的FFT结果,才能还原实信号:

  1. 找到目标正频率的索引
  2. 保留该分量,并在对应的负频率位置设置其共轭值
  3. 0Hz和Nyquist频率(Fs/2)无需处理(因为它们没有配对的负频率)
  4. 其他位置置0,再做IFFT后取实部

示例代码:

from scipy.fftpack import fft, ifft
import matplotlib.pyplot as plt
import numpy as np

tt = np.arange(0, 0.02, 50e-6)
xx = np.sin(2*np.pi*50*tt)
N = len(tt)
Fs = 1 / 50e-6

XX = fft(xx)
ff = np.fft.fftfreq(N, 50e-6)  # 用fftfreq生成正确的正负频率轴,更直观

# 找到50Hz对应的正频率索引
target_freq = 50
idx = np.argmin(np.abs(ff - target_freq))
# 对应的负频率索引
neg_idx = N - idx

# 构造新的FFT结果,只保留目标频率及其共轭分量
XX_filtered = np.zeros_like(XX, dtype=np.complex128)
XX_filtered[idx] = XX[idx]
XX_filtered[neg_idx] = np.conj(XX[idx])  # 设置共轭值,保证实信号特性

# 还原信号
xx_recon = ifft(XX_filtered).real  # 取实部消除数值误差

plt.figure(figsize=(12, 6))
plt.subplot(121)
plt.plot(ff, np.abs(XX_filtered))
plt.xlabel('Freq (Hz)')
plt.ylabel('FFT Amplitude')
plt.title('处理后的FFT结果')

plt.subplot(122)
plt.plot(tt, xx_recon, 'r-')
plt.xlabel('Time (s)')
plt.ylabel('Amplitude')
plt.title('还原信号')
plt.tight_layout()
plt.show()

这里用np.fft.fftfreq()生成了包含正负频率的轴,能更清晰看到-50Hz和50Hz的分量,处理后只保留这两个对称分量,IFFT就能还原出原正弦波。

关于幅值和相位的提取

如果要提取主谐波的幅值和相位:

  • 用rfft()的话,幅值是np.abs(XX_r[idx]) * 2 / N(因为rfft的正频率分量幅值是普通FFT的2倍,除以N是归一化)
  • 相位是np.angle(XX_r[idx]),注意正弦信号的相位和余弦的差异(原信号是sin,对应cos的相位减π/2)

用普通FFT的话,正频率分量的幅值是np.abs(XX[idx]) / N,相位是np.angle(XX[idx]),负频率是其共轭。

内容的提问来源于stack exchange,提问作者Poria Divshali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 22:05:44