
很多学过《信号与系统》的人都有一种共同的体验上课好像能听懂一到做题就发懵期末复习越看越乱。傅里叶变换、频谱分析、调制解调翻开教材是三个独立章节各有各的公式各有各的题型但很少有人告诉你它们其实是一条主线上的不同环节。这条主线就是“变换域思维”。傅里叶变换给了你一个从频域观察信号的视角频谱分析是你在这个视角下读信号的方式而调制解调则是把这个视角用到真实通信系统中的经典案例。它们不是三个考点而是一套完整的技术逻辑。这篇文章会用“主线串联 Python 验证”的方式把信号与系统里最容易让人混乱的几块内容讲清楚。你不需要先精通数学推导只要跟着文章把概念骨架搭起来再用 Python 跑一遍仿真很多公式瞬间就活了。如果你是正在准备期末考试、考研复习或者工作后需要回炉信号处理基础这篇文章值得收藏后慢慢看完。1. 这篇文章真正要解决的问题先说一个观察很多同学学信号与系统卡住不是因为不努力而是因为努力的方向错了。教材的编排通常是先讲连续时间信号与系统再讲傅里叶变换然后讲拉普拉斯变换、Z 变换、系统函数。每章都很严谨但问题是当你学到第三章的时候可能已经忘了第一章的卷积和系统分析有什么关系。章节之间缺少一个“为什么先学这个、再学那个”的导航图于是学习变成了一堆孤立公式的背诵。还有一个现实问题这门课的数学门槛不低。傅里叶变换是积分变换卷积是积分运算系统响应要解微分方程。如果数学基础一般很容易陷入“每个符号都认识连起来不知道在说什么”的状态。更麻烦的是概念高度抽象时域波形、频域谱线、系统频率响应这些东西光靠纸笔很难建立直觉。本文要解决的就是这三件事把傅里叶变换、频谱分析、调制解调串成一条完整主线让你知道它们之间到底是什么关系。用 Python 仿真把抽象概念变成能看到的波形和频谱建立直觉之后再回来看公式。从“速成”角度给出复习路径先抓主线、再补细节、最后用实验验证而不是一上来死磕推导。这门课不是背出来的是“看”出来和“跑”出来的。下面我们从头开始。2. 从时域到频域傅里叶变换到底做了什么2.1 时域看信号你熟悉的“波形视角”我们最开始接触信号都是从示波器开始的。横轴是时间纵轴是电压或幅度看到的是一条随时间变化的曲线比如一个正弦波、一个脉冲、一段语音。这个视角叫时域视角它直观地告诉你在某个时刻信号的值是多少。时域视角的问题在于它把所有频率成分混在一起。一个由 5Hz 和 40Hz 正弦波叠加而成的信号在时域里就是一条看起来有点复杂的波形曲线你很难一眼看出它“包含哪两种频率”。这就像一杯混合果汁你只看到颜色看不出配方。2.2 频域看信号频谱仪的“配方视角”频域视角换了一个维度横轴是频率纵轴是幅度。它回答的问题是这个信号由哪些频率成分组成每个频率成分的强度是多少。同一个混合信号在频域里会变成两条清晰的谱线一条在 5Hz一条在 40Hz一目了然。把信号从时域变到频域的数学工具就是傅里叶变换。用人话说傅里叶变换做的事情是“把信号拆解成一系列不同频率的正弦波之和”。任何一个满足条件的周期信号都可以被分解为基波和一系列谐波非周期信号则可以理解为无穷多个频率连续分布的正弦波的叠加。2.3 傅里叶变换的公式与“人话解释”连续时间傅里叶变换的公式长这样$$X(j\omega) \int_{-\infty}^{\infty} x(t) e^{-j\omega t} dt$$如果你现在被这个公式吓到了先别跑。它的含义其实很朴素把信号 $x(t)$ 分别与不同频率的复指数信号 $e^{-j\omega t}$ 做“相似度比较”看它的能量在哪个频率上更集中。$X(j\omega)$ 就是信号在频率 $\omega$ 处的“含量”。把所有频率的“含量”画出来就得到频谱。对比维度时域频域横轴时间频率观察内容信号随时间如何变化信号包含哪些频率成分常见工具示波器频谱分析仪典型问题波形是否失真、延迟多久带宽多大、有哪些干扰频率这个表是这门课最重要的思维切换工具。后面讲到的频谱分析、调制解调本质上都是在“时域—频域”之间来回切换。3. 频谱与频谱分析读懂一张频谱图3.1 频谱图怎么读频谱图是傅里叶变换最直观的产物。横轴是频率纵轴是幅度。一个单一频率的正弦波在频谱图上只有一根谱线一个方波在频谱图上会出现基波和一系列衰减的奇次谐波一段语音在频谱图上是一块连续的宽带谱。很多初学者第一次看到频谱图最大的困惑是“这个图到底能干嘛”。最简单的理解方式频谱图告诉你的不是信号“长什么样”而是信号“由什么构成”。就像一道菜的卖相是时域配料表是频域。读频谱图时有几个关键点谱线位置决定频率成分。谱线高度决定该频率成分的强弱。谱线宽度和形状往往反映了信号的稳定性。连续谱范围决定了信号占用的带宽。3.2 频谱分析的应用场景理解了频谱图你就会发现它几乎无处不在。在设备故障诊断中轴承磨损、齿轮断齿会产生特征频率通过频谱分析可以在设备还没有完全损坏之前发现异常。在音频处理中均衡器就是对频谱的频段进行增益调整降噪算法则是在频谱域把噪声频段衰减掉。在通信系统设计中调制信号占多大带宽、滤波器该设计成什么截止频率都需要先做频谱分析。频谱分析是傅里叶变换最直接、最成熟的应用之一。它的核心逻辑可以概括为先把时域信号变换到频域在频域里观察、处理再根据需要变换回时域。3.3 采样率与奈奎斯特定理在做数字频谱分析之前必须提一个前置条件采样。计算机只能处理离散点所以模拟信号要先经过采样变成离散序列才能用 FFT 分析。而采样率的选择有一个底线就是奈奎斯特定理采样率必须大于信号最高频率的两倍否则高频成分会“混叠”到低频区域频谱图就是错的。这篇文章后面的 Python 示例里采样率设为 500Hz信号最高频率只有 50Hz 左右远大于两倍关系所以结果可以放心观察。实际项目中这个关系永远是排查频谱图是否可信的第一道检查线。4. 调制与解调为什么信息要“搬个家”4.1 为什么不直接把信号发出去如果有一段语音信号频率大概在 300Hz 到 3400Hz能不能直接通过天线发射出去理论上可以但工程上问题很大。首先是天线尺寸问题。天线的有效长度通常需要和波长可比拟而 1kHz 信号的波长是 300 公里不可能造出那么大的天线。把信号搬到高频载波上之后波长缩短到米级甚至厘米级天线才变得可制造。其次是多路复用问题。多个人同时打电话如果都用基带信号直接发射接收端根本无法区分谁是谁。把不同用户的信号调制到不同的载波频率上大家挤在同一条信道上互不干扰接收端只要调到对应频率就能解出自己的信号。最后还有信道匹配和抗干扰因素。某些信道对特定频段衰减较小把信号搬到合适频段能获得更好的传输质量。这就是“调制”存在的根本原因让信息在频域上搬个家适应信道和系统需求。4.2 AM 调制的数学表达幅度调制AM是最直观的一种调制方式。设调制信号为 $m(t)$载波为 $c(t) \cos(2\pi f_c t)$AM 已调信号可以写成$$s(t) [1 m_a m(t)] \cdot \cos(2\pi f_c t)$$其中 $m_a$ 是调幅指数控制调制深度。当 $m_a$ 小于 1 时包络形状和 $m(t)$ 保持一致接收机可以用最简单的包络检波恢复信号当 $m_a$ 大于 1 时包络会过调解调就会失真。从频域视角看AM 调制的作用是把基带信号的频谱从低频“搬”到载波频率 $f_c$ 附近形成上边带和下边带两条谐波。这个“频谱搬移”的效果正是傅里叶变换的频移性质在通信系统里的直接体现。4.3 解调的两种常见方式解调是调制的逆过程目标是恢复原始信号。包络检波是最直观的方法先用二极管之类的非线性器件对已调信号取绝对值相当于全波整流再用低通滤波器滤掉高频载波分量剩下的就是原信号的包络。它的优点是简单、不需要载波同步缺点是只能用于幅度调制且容易受噪声影响。相干解调则是让接收端产生一个和发射端同频同相的本地载波把已调信号乘以本地载波再用低通滤波器取出低频分量。这种方法性能更好但代价是必须有载波同步电路。4.4 傅里叶变换在调制中的角色调制和解调整个过程用傅里叶变换来看会格外清晰。时域里 $s(t) m(t) \cdot \cos(2\pi f_c t)$而频域里“时域相乘”对应“频域卷积”。载波 $\cos(2\pi f_c t)$ 的傅里叶变换是在 $\pm f_c$ 处的两个冲激所以 $m(t)$ 的频谱被复制到 $\pm f_c$ 附近。这一下就理解了为什么调制是“频谱搬移”。同理解调时再次乘以本地载波频谱又一次搬移把原始低频分量搬回基带再用低通滤波器清除高频部分。整个通信链路本质上就是傅里叶变换性质的一次次应用。5. 环境准备用 Python 做信号实验理论说完了下面进入动手环节。我们要用 Python 把傅里叶变换、频谱分析、AM 调制解调全部跑一遍。建议使用 Python 3 的现代稳定版本配合 NumPy、SciPy、Matplotlib 三个库。NumPy 负责数值计算和 FFTSciPy 负责滤波Matplotlib 负责画图。安装命令pip install numpy matplotlib scipy如果网络环境使用镜像源更顺畅可以换用清华或阿里云镜像这是常规操作不再展开。安装完成后打开 Python 交互环境运行下面的导入语句验证环境import numpy as np import matplotlib.pyplot as plt from scipy.signal import butter, filtfilt print(numpy version:, np.__version__)能正确输出版本号环境就没有问题了。下面开始第一个实验。6. 傅里叶变换与频谱分析的 Python 实现6.1 生成信号并做 FFT我们用 Python 生成一段仿真信号包含 5Hz 和 40Hz 两个正弦波然后用 FFT 看它的频谱。import numpy as np import matplotlib.pyplot as plt fs 500 # 采样率 500Hz t np.arange(0, 1, 1/fs) # 时长 1 秒 # 构造一个由 5Hz 和 40Hz 组成的信号 x np.sin(2 * np.pi * 5 * t) 0.5 * np.sin(2 * np.pi * 40 * t) N len(x) # 采样点数 X np.fft.fft(x) # 离散傅里叶变换 freqs np.fft.fftfreq(N, 1/fs) # 频率轴 # 只取正频率部分并换成单边谱幅度 half N // 2 mag np.abs(X[:half]) * 2 / N freq_axis freqs[:half] # 画图 plt.figure(figsize(10, 4)) plt.subplot(1, 2, 1) plt.plot(t, x) plt.title(时域波形) plt.xlabel(时间/s) plt.ylabel(幅度) plt.subplot(1, 2, 2) plt.stem(freq_axis, mag) plt.title(幅度谱FFT) plt.xlabel(频率/Hz) plt.ylabel(幅度) plt.tight_layout() plt.show()这段代码做了几件关键的事np.fft.fft(x)计算离散傅里叶变换结果是复数数组。np.fft.fftfreq(N, 1/fs)生成与 FFT 结果对应的频率坐标。np.abs(X[:half]) * 2 / N把复数幅度转成单边谱幅度。因为 FFT 结果关于 N/2 对称所以取前一半并乘以 2再除以 N 做归一化。运行后时域里是一条混合波形频域里你能清晰地看到两根谱线分别位于 5Hz 和 40Hz幅度分别是 1 和 0.5正好对应构造信号时设置的参数。这就验证了 FFT 频谱分析的正确性。6.2 频谱泄漏一个特别容易踩的坑如果你把信号频率改成 5.3Hz重新做 FFT会发现谱峰变得很宽幅度也变小了。这个现象叫频谱泄漏。原因是 FFT 默认把信号当作周期性延拓来处理当信号频率不是频率分辨率 $\Delta f fs / N$ 的整数倍时截断边界不连续能量就会泄漏到相邻多个频点上。解决办法有两个一是增加采样点数 N提高频率分辨率让频率更接近整数倍二是给信号加窗函数比如汉宁窗牺牲一点主瓣宽度来压低泄漏。f 5.3 x2 np.sin(2 * np.pi * f * t) # 加汉宁窗 win np.hanning(N) x2_win x2 * win # 对比加窗前后的频谱 X2 np.fft.fft(x2) X2_win np.fft.fft(x2_win) mag2 np.abs(X2[:half]) * 2 / N mag2_win np.abs(X2_win[:half]) * 2 / N fig, axes plt.subplots(1, 2, figsize(10, 3), shareyTrue) axes[0].stem(freq_axis, mag2, basefmt ) axes[0].set_title(未加窗频谱泄漏明显) axes[1].stem(freq_axis, mag2_win, basefmt ) axes[1].set_title(加汉宁窗泄漏降低) plt.tight_layout() plt.show()这个实验做完你就同时掌握了两件事怎么用 FFT 做频谱分析以及面对非整数频率时如何用窗函数改善结果。这两点在真实项目和课程作业里都非常常见。7. AM 调制与解调的 Python 完整示例7.1 生成 AM 信号现在把傅里叶变换的知识用起来完整走一遍 AM 调制、观察频谱、包络检波解调的流程。先设置参数并生成信号fs 500 t np.arange(0, 1, 1/fs) fm 5 # 调制信号频率 5Hz fc 50 # 载波频率 50Hz ma 0.5 # 调幅指数 # 调制信号 m np.cos(2 * np.pi * fm * t) # 载波 c np.cos(2 * np.pi * fc * t) # AM 已调信号 s (1 ma * m) * c这段代码对应前面讲的 AM 公式。调制信号是 5Hz 余弦波载波是 50Hz调幅指数 0.5包络不会过调。7.2 观察调制后的频谱定义一个画频谱的小函数方便复用def plot_spectrum(signal, fs, title): N len(signal) X np.fft.fft(signal) freqs np.fft.fftfreq(N, 1/fs) half N // 2 plt.plot(freqs[:half], np.abs(X[:half]) * 2 / N) plt.title(title) plt.xlabel(频率/Hz) plt.ylabel(幅度) plt.grid(True) plt.figure(figsize(8, 3)) plot_spectrum(s, fs, AM 已调信号频谱) plt.tight_layout() plt.show()运行后频谱图上最明显的是三组谱线50Hz 处是载波分量。45Hz 和 55Hz 分别是下边带和上边带分量。基带 5Hz 的信号原本在低频处经过调制后被搬移到了载波附近。这就是频谱搬移的直观体现。你会清楚地看到调制并没有改变信息本身只是改变了它在频域里的位置。7.3 包络检波恢复信号下面用包络检波恢复原始信号。思路是先取绝对值再做低通滤波from scipy.signal import butter, filtfilt # 1. 全波整流取绝对值 env np.abs(s) # 2. 低通滤波滤掉高频载波 b, a butter(4, 10 / (fs/2), btypelow) # 截止频率 10Hz low filtfilt(b, a, env) # 3. 去掉直流偏置归一化便于和原始信号对比 m_est low - np.mean(low) m_est m_est / np.max(np.abs(m_est)) # 画图对比 plt.figure(figsize(12, 6)) plt.subplot(3, 1, 1) plt.plot(t, m) plt.title(原始调制信号 m(t)) plt.grid(True) plt.subplot(3, 1, 2) plt.plot(t, s) plt.title(AM 已调信号 s(t)) plt.grid(True) plt.subplot(3, 1, 3) plt.plot(t, m / np.max(np.abs(m)), label原始信号) plt.plot(t, m_est, --, label包络检波恢复信号) plt.title(包络检波结果对比) plt.legend() plt.grid(True) plt.tight_layout() plt.show()关键逻辑解释np.abs(s)等价于全波整流输出一个带有基带包络和大量高频分量的信号。butter设计一个 4 阶巴特沃斯低通滤波器截止频率 10Hz。因为调制信号只有 5Hz10Hz 的截止频率足够保留它同时滤掉 50Hz 载波及整流产生的高次谐波。filtfilt是零相位滤波避免波形产生相位偏移非常适合观察波形形状。低通滤波后信号里含有 AM 波形带来的直流分量所以要先减均值由于整流和滤波会改变增益这里做了一次归一化让恢复信号和原始信号在同一个尺度上比较。运行后第三条子图里两条曲线会几乎重合。这说明包络检波成功恢复了原始调制信号。你可以把调幅指数改成 0.8、1.0 甚至 1.5 再运行一次观察包络失真什么时候出现。这个实验比做十道计算题更能帮助你理解过调制的危害。7.4 换成相干解调会怎样包络检波虽然简单但它在噪声环境下性能有限。相干解调的思路是让已调信号乘以同频同相本地载波再低通滤波。coherent s * c # 乘以本地载波 b, a butter(4, 10 / (fs/2), btypelow) m_coherent filtfilt(b, a, coherent) # 去掉直流偏置 m_coherent m_coherent - np.mean(m_coherent) # 归一化后对比 m_coherent m_coherent / np.max(np.abs(m_coherent)) plt.figure(figsize(8, 3)) plt.plot(t, m / np.max(np.abs(m)), label原始信号) plt.plot(t, m_coherent, --, label相干解调恢复信号) plt.legend() plt.grid(True) plt.show()它的原理是$s(t) \cdot \cos(2\pi f_c t)$ 展开后会包含低频项和高频项低通滤波器只留下低频项完成解调。代价是接收端需要载波同步如果本地载波的频率或相位不一致恢复信号会明显畸变。8. 常见问题与排查思路在信号仿真与频谱分析中很多问题反复出现这里整理成一张排查表遇到问题直接对照处理。问题现象可能原因排查方式解决方案频谱图中峰值位置不对频率轴计算错误检查fftfreq参数是否写成了fs而不是1/fs使用np.fft.fftfreq(N, 1/fs)单根正弦的谱峰扩散到多个频点信号频率不是频率分辨率整数倍发生频谱泄漏计算 $\Delta f fs / N$检查信号频率与 $\Delta f$ 的比值增加采样点数 N或对信号加窗函数出现低频区域本不该有的频率成分采样率不足发生混叠检查最高频率是否超过fs/2提高采样率或先加抗混叠滤波器再采样解调后波形失真包络出现负值调幅指数大于 1发生了过调制绘制(1 ma * m)的包络观察是否小于 0将调幅指数调整为 0.5 或 0.8低通滤波后波形有高频毛刺低通截止频率设置过高打印滤波前后的频谱对比降低截止频率确保载波频率被滤除包络检波恢复的波形幅度对不上整流和滤波改变了信号增益对比恢复信号与原始信号的幅度范围先归一化再按理论增益恢复到原始幅度FFT 结果幅度和时域幅度不一致忘记做归一化或单边谱处理检查幅度是否除以 N双边谱是否乘 2单边谱使用np.abs(X[:half]) * 2 / N这张表不只适用于本文的示例也适用于你自己处理真实信号时的各种问题。建议截图或收藏遇到问题先查表。9. 信号与系统的“速成”复习路径如果现在距离考试只剩两三周我强烈建议你不要再按教材顺序从第一章慢慢看了而是按下面的路径复习。9.1 抓住唯一的骨架主线信号与系统的核心主线是“激励—系统—响应”而串联时域和频域的最重要关系是卷积定理$$y(t) x(t) * h(t) \quad \xrightarrow{\text{傅里叶变换}} \quad Y(j\omega) X(j\omega) H(j\omega)$$这句话的意思是时域里的卷积运算在频域里变成了简单的乘法。$H(j\omega)$ 是系统的频率响应它表示系统对每个频率分量是放大还是衰减、是滞后还是超前。很多同学做滤波题、求系统响应题都会绕远路根源就是没有理解这个等价关系。拿到一个系统先问自己在时域做卷积方便还是在频域做乘法方便。这是信号与系统题目里最重要的“策略问题”。9.2 先建立直觉再补数学推导速成最大的误区是花大量时间抄写公式推导结果遇到应用题还是不会。更有效的顺序是先用 Python 或仿真工具观察现象比如用 FFT 看频谱、用滤波看波形变化。知道现象之后再回来看推导你会更容易接受每一步数学操作的含义。最后用纸笔独立做题把公式变成自己的工具。傅里叶变换的对称性、时移性质、频移性质、卷积定理这几个性质建议反复用仿真验证。一旦你看过 AM 调制之后的频谱长什么样频移性质就永远不会忘。9.3 用 Python 做三组经典小实验光看不练没有用推荐三组能够在半小时内完成的小实验用 FFT 分析方波的频谱观察基波和奇次谐波的衰减规律。改变采样率对同一个信号做 FFT观察混叠如何发生。设计一个低通滤波器观察不同截止频率下的时域响应和频域响应。这三组实验覆盖了傅里叶变换、采样定理、系统频率响应这三大核心考点完成后你对整门课的理解会比刷十套真题更扎实。面试时如果聊到信号处理基础这些动手经验也是一个非常加分的亮点。10. 总结写到最后总结一下这篇文章真正想传达的东西。信号与系统这门课难点从来不在公式本身而在“时域”和“频域”这两个视角之间的频繁切换。傅里叶变换就是那副切换视角的眼镜频谱分析是戴着眼镜读取信息调制解调则是利用频域特性完成真实通信任务。速成不是不学原理而是先把主线搭起来再用实验验证最后回头补细节。如果你把这篇文章里的 Python 示例全部运行一遍已经比许多只背公式的同学领先一大截。下一步建议很具体先拿一个真实声音信号录制几秒用 FFT 分析它的频谱再尝试设计一个滤波器把其中某个频段滤掉。这一套流程跑通之后你就不再是“学过信号与系统”而是真的“会用它”了。