news 2026/9/5 12:33:48

连续周期信号傅里叶级数详解:Python验证与工程实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
连续周期信号傅里叶级数详解:Python验证与工程实践

连续周期信号的傅里叶级数,是信号从时域进入频域的第一个门槛。很多教材会在这一章给出积分公式、正交条件和吉布斯现象,但读者真正动手时最容易卡住的,反而不是公式本身,而是系数定义不统一、时间轴采样方式不对、三角形式与复指数形式换算错位这几个工程细节。这篇文章以周期方波为样例,把连续周期信号傅里叶级数的概念、系数计算、信号合成、验证方法和排错路径完整走一遍,重点说明每一步背后的原因,以及如何在代码里确认结果是对的。

1. 连续周期信号为什么需要傅里叶级数,它到底分解出了什么

1.1 从“函数表示”到“频率成分”

连续周期信号,是指满足

[ x(t+T_0)=x(t) ]

的信号,其中 (T_0) 是最小正周期。常见的正弦波、方波、锯齿波、三角波,都是周期信号的典型例子。时域描述能告诉我们信号在某个时刻的取值,却很难告诉我们这个信号由哪些“基础分量”叠加而成。实际工程里,滤波、去噪、调制解调、故障特征提取,几乎都依赖频率信息。傅里叶级数的作用,就是把一个连续周期信号拆分成的直流分量、基波分量和各次谐波分量。

这里要区分一个概念:傅里叶级数不是“把一个信号变短”,也不是“压缩数据”,而是把信号从“时间坐标系”切换到“频率坐标系”。同一个信号,在时域是一条曲线,在频域是一组谱线。连续周期信号的频谱是离散谱,只在基波频率的整数倍处有值,这是它和非周期信号最直观的区别。

1.2 周期、基波与谐波:三角展开的完整定义

设周期信号 (x(t)) 的周期为 (T_0),则基波频率为

[ f_0=\frac{1}{T_0} ]

角频率为

[ \omega_0=2\pi f_0=\frac{2\pi}{T_0} ]

三角形式的傅里叶级数可以写成

[ x(t)=\frac{a_0}{2}+\sum_{n=1}^{\infty}\left[a_n\cos(n\omega_0t)+b_n\sin(n\omega_0t)\right] ]

其中系数为

[ a_0=\frac{2}{T_0}\int_{T_0}x(t)dt ]

[ a_n=\frac{2}{T_0}\int_{T_0}x(t)\cos(n\omega_0t)dt ]

[ b_n=\frac{2}{T_0}\int_{T_0}x(t)\sin(n\omega_0t)dt ]

这里的积分区间可以取 ([0,T_0]),也可以取 ([-T_0/2,T_0/2])。由于被积函数是周期信号,只要积分区间长度正好是一个周期,起点取在哪里不影响积分结果。

工程里最容易混淆的是 (a_0) 的定义。有些教材把 (a_0) 定义为信号在一个周期内的平均值,也就是直流分量本身;上面的定义里,直流分量是 (a_0/2)。这两种定义差一个系数。如果看书时没有注意公式上下文,写代码时就可能出现结果偏大两倍或者偏小两倍。

1.3 复指数形式、离散谱与吉布斯现象

三角形式直观,但涉及两个系数序列。做理论推导和数值计算时,复指数形式更紧凑:

[ x(t)=\sum_{n=-\infty}^{\infty}c_ne^{jn\omega_0t} ]

[ c_n=\frac{1}{T_0}\int_{T_0}x(t)e^{-jn\omega_0t}dt ]

三角系数和复指数系数之间可以互相换算:

系数与三角系数关系
(c_0)(a_0/2),即直流分量
(c_n, n>0)((a_n-jb_n)/2)
(c_n, n<0)((a_{

复指数形式会同时出现正频率和负频率,这是数学表达上的对称性,不是真实存在“负频率”的物理信号。画单边频谱时,需要把正频率对应的复幅度乘以 2,才能得到对应正弦或余弦分量的实际幅度。

还要理解吉布斯现象。连续周期信号在跳变点处的傅里叶级数不是均匀收敛的,即使展开项数增加到很大,间断点附近也会出现固定比例的过冲,大约为跳变幅度的 9%。项数越大,过冲越靠近间断点,但过冲峰值不会消失。这不是计算错误,而是傅里叶级数本身在间断点邻域的收敛特性。

2. 用 Python 搭建最小验证环境,先跑出一个周期方波

2.1 实验思路与依赖环境

验证傅里叶级数,只用纸面推导不够,因为系数积分、信号合成、能量校验都必须落到具体数值上。用 Python 做这个实验,需要三个库:NumPy 负责数值计算,Matplotlib 负责绘图,SciPy 在需要 FFT 交叉验证时使用。

pip install numpy matplotlib scipy

如果使用虚拟环境,推荐先创建独立目录:

python -m venv fs_demo source fs_demo/bin/activate pip install numpy matplotlib scipy

Windows 下激活命令是fs_demo\Scripts\activate。本文示例基于 Python 3.10 以上版本,NumPy 1.21 以上、Matplotlib 3.5 以上均可运行。傅里叶级数实验对版本不敏感,关键是采样点设置要正确。

实验的主线可以拆成四个验证目标:

  • 手写系数积分的结果是否接近解析解。
  • 用有限项合成信号后,波形是否逼近原信号。
  • 时域功率和频域功率是否满足帕塞瓦尔定理。
  • 间断点附近是否出现吉布斯现象。

这四个目标全部通过,才能说明对这一部分的理解没有系统性偏差。

2.2 生成周期方波信号

为了后续能和解析系数对照,选用占空比为 50% 的周期方波。设周期 (T=2) 秒,基波频率 (f_0=0.5) Hz,角频率 (\omega_0=\pi) rad/s。方波在一个周期前半段为 1,后半段为 -1。

import numpy as np import matplotlib.pyplot as plt # 周期 T = 2.0 # 一个周期内的采样点数 M = 4096 # 时间轴:从 0 到 T,但不包含 T t = np.linspace(0.0, T, M, endpoint=False) def square_wave(t, T): """占空比 50% 的周期方波,取值范围 -1 到 1。""" phase = t % T return np.where(phase < T / 2.0, 1.0, -1.0) x = square_wave(t, T)

这段代码里最关键的是endpoint=False。傅里叶级数积分要求区间长度正好是一个周期。如果写成np.linspace(0, T, M),最后一个点会重复采样时刻 (T),而周期边界上 (x(T)=x(0)),相当于多计算了一次端点。虽然采样点数量很大时影响很小,但从一开始就养成“周期采样不含终点”的习惯,后续和 FFT 对照也会更顺畅。

绘图时不要只画一个周期,建议画两个周期观察周期性:

t_plot = np.linspace(0.0, 2 * T, 2 * M, endpoint=False) fig, ax = plt.subplots(figsize=(8, 3)) ax.plot(t_plot, square_wave(t_plot, T), linewidth=1) ax.set_xlabel("time / s") ax.set_ylabel("x(t)") ax.set_xlim(0, 2 * T) ax.set_title("Periodic Square Wave") plt.show()

运行后应看到幅度在 -1 和 1 之间切换的方波,一个完整周期内高低电平各占一半。

2.3 采样时间与积分近似的对应关系

把傅里叶系数积分改成数值计算时,本质上是用离散采样点近似连续积分。因为这里处理的信号是连续周期信号,数值积分只要求足够密即可。M 取 4096 是相对保守的选择,既能保证积分精度,速度也非常快。

需要注意时间轴的单位和角频率单位。代码里周期 T 的单位是秒,所以omega0 = 2.0 * np.pi / T的单位是 rad/s。如果直接写成omega0 = 2.0 * np.pi,角频率就错了,前几个谐波会对应错误频率位置。另一个常见误解是认为采样点越多,傅里叶级数就能展开到越多项。实际上,一个周期内采样 M 个点后,可表示的最高谐波次数受奈奎斯特频率约束。M=4096 对展开几十个谐波绰绰有余,但展开到 2000 项以上时,数值结果会退化。

学习阶段的检查点是:先看时域图是否正确,再打印一次周期内的平均值。占空比 50% 的对称方波平均值为 0,所以后续理论上的 (a_0) 应当接近 0。

3. 手写傅里叶级数系数计算与信号合成

3.1 系数积分的矩阵化写法

用循环逐个计算 (a_n) 和 (b_n),思路直观,但代码较长。这里采用 NumPy 的广播机制,把一个周期内所有采样点上的正弦、余弦基函数一次性构造出来,再和信号做逐元素相乘后求和。

def fs_coeffs(signal, t, T, n_max): """ 计算三角形式傅里叶系数。 参数 ---- signal : 一个完整周期内的采样值 t : 对应时间轴 T : 信号周期 n_max : 最高谐波次数 返回 a0, a, b a0 对应三角公式中的 a0,合成时直流分量为 a0/2 """ dt = t[1] - t[0] omega0 = 2.0 * np.pi / T n = np.arange(1, n_max + 1) # cos_base.shape = (n_max, M) cos_base = np.cos(np.outer(n, omega0 * t)) sin_base = np.sin(np.outer(n, omega0 * t)) # 对每个基函数做一整个周期的积分 a = (2.0 / T) * np.sum(signal * cos_base, axis=1) * dt b = (2.0 / T) * np.sum(signal * sin_base, axis=1) * dt # a0 = (2/T) * integral(signal dt) a0 = 2.0 * np.mean(signal) return a0, a, b

对于占空比 50% 的对称方波,理论上只有奇数阶正弦项,即

[ b_n = \begin{cases} \dfrac{4}{n\pi}, & n\text{为奇数}\ 0, & n\text{为偶数} \end{cases} ]

而所有 (a_n) 都应该接近 0。拿解析解检查数值结果是判断代码是否正确的最快方式。

a0, a, b = fs_coeffs(x, t, T, 50) print("a0 =", a0) for i in range(5): n = i + 1 exact = 4.0 / (n * np.pi) if n %
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/5 12:33:31

STM32口罩识别门禁系统:源码原理图与联调实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/5 12:32:21

MES生产执行系统优化指南:如何提升制造效率?

一、引言&#xff1a;MES优化的核心价值在工业4.0和智能制造的大背景下&#xff0c;MES&#xff08;Manufacturing Execution System&#xff0c;制造执行系统&#xff09;作为连接企业计划层与车间控制层的关键枢纽&#xff0c;其运行效率直接影响着产品质量、交付周期和生产成…

作者头像 李华
网站建设 2026/9/5 12:29:31

STM32G431RBT6工程脚手架:硬件原理图+25例实战源码

简介&#xff1a;本资源是面向STM32初学者与嵌入式开发工程师的完整学习套件&#xff0c;聚焦STM32G431RBT6单片机硬件设计与软件开发实践&#xff0c;解决入门难、参考设计缺失、例程分散等典型痛点。压缩包含2000个文件&#xff0c;主体为1155个C源码与600个头文件&#xff0…

作者头像 李华
网站建设 2026/9/5 12:27:38

双向DC-DC变换器仿真建模:从Buck-Boost拓扑到双闭环控制实战

简介&#xff1a;本资源是一个面向电力电子工程师、高校师生及嵌入式电源系统学习者的DC-DC变换器仿真实践包&#xff0c;聚焦Buck-Boost拓扑与双向能量流动特性&#xff0c;适用于电动汽车车载充电、储能系统充放电管理、可再生能源接口等实际应用场景。压缩包共2个文件&#…

作者头像 李华
网站建设 2026/9/5 12:25:54

工业级无人机红外热成像数据集(2898张JPG)

简介&#xff1a;本资源是面向计算机视觉、遥感感知与红外目标检测研究者的高质量无人机高空红外热成像数据集&#xff0c;专为训练/验证热红外目标检测模型&#xff08;如YOLO系列、Faster R-CNN&#xff09;及多模态融合算法提供真实场景支撑。数据集包含2898张JPG格式红外热…

作者头像 李华