脉冲傅里叶变换Python绘图问题:实部与sinc曲线不一致原因排查
问题背景
我尝试用Python绘制脉冲信号的傅里叶变换,代码如下:
import numpy as np import matplotlib.pyplot as plt def pulse(time, L=1, A=1, C=0): return [A * int(C-L/2 <= t <= C+L/2) for t in time] # data time = np.arange(-5, 5, 0.01) freq = np.arange(-5, 5, 0.01) signal = pulse(time) fourier = [np.mean(signal * np.exp(-2j * np.pi * f * time)) for f in freq] # figure fig, axs = plt.subplots(nrows=3, figsize=(6, 6)) # original signal axs[0].grid(True) axs[0].set_ylabel('f(t)') axs[0].plot(time, signal) # real part fourier transform axs[1].grid(True) axs[1].set_ylabel('Re(F{f})') axs[1].plot(freq, np.real(fourier)) # Fourier{pulse(width)} = width * sinc(PI * f * width) axs[2].grid(True) axs[2].set_ylabel('sinc(f)') axs[2].plot(freq, np.sinc(np.pi*freq)) # show fig.canvas.set_window_title('Fourier Transform') plt.show()
运行后发现傅里叶变换实部和sinc曲线不完全一致,怀疑问题出在freq = np.arange(-5, 5, 0.01)和fourier = [np.mean(signal * np.exp(-2j * np.pi * f * time)) for f in freq]这两行,请问原因是什么?
问题分析与解决
嘿,你找对方向了,问题确实出在你怀疑的那两行,主要有两个核心原因:
1. 傅里叶变换的离散近似错误
你用np.mean()来近似计算傅里叶变换,但标准的连续傅里叶变换是积分形式:
$F(f) = \int_{-\infty}^{\infty} f(t) e^{-2j\pi f t} dt$
当用离散采样点近似这个积分时,应该用采样间隔乘以采样点的求和,而不是取平均。你的时间采样间隔是0.01,np.mean()相当于把求和结果除以了采样点总数,这会引入一个错误的缩放系数。
修正方法是把np.mean()换成np.sum()再乘以采样间隔dt:
dt = 0.01 fourier = [dt * np.sum(signal * np.exp(-2j * np.pi * f * time)) for f in freq]
2. Numpy的sinc函数定义理解偏差
Numpy中的np.sinc(x)定义是:$\text{sinc}(x) = \frac{\sin(\pi x)}{\pi x}$,而宽度为1、幅度为1的矩形脉冲的傅里叶变换理论值是$F(f) = \text{sinc}(f)$(对应$\frac{\sin(\pi f)}{\pi f}$)。但你现在绘制的是np.sinc(np.pi*freq),这相当于$\frac{\sin(\pi \cdot \pi f)}{\pi \cdot \pi f}$,和理论公式完全不符!
修正方法是直接使用np.sinc(freq)来绘制理论曲线:
axs[2].plot(freq, np.sinc(freq))
修正后的关键代码片段
把这两处修改后,关键代码部分应该是这样:
dt = 0.01 time = np.arange(-5, 5, dt) freq = np.arange(-5, 5, 0.01) signal = pulse(time) # 修正傅里叶变换计算 fourier = [dt * np.sum(signal * np.exp(-2j * np.pi * f * time)) for f in freq] # 修正sinc曲线绘制 axs[2].set_ylabel('sinc(f)') axs[2].plot(freq, np.sinc(freq))
这样调整后,傅里叶变换的实部曲线就会和理论的sinc曲线完全重合了。
内容的提问来源于stack exchange,提问作者Omar Aflak

