
PID 控制器是工业自动化和嵌入式控制中最常见的算法但很多初学者第一次看到公式里的积分项、微分项时心里多少会发怵这要不要先补一遍微积分才能调参其实完全不用。把 PID 公式离散化之后剩下的就是“累加”和“相减”这东西在 Excel 里用几列公式就能跑通。本文分享一套“不用微积分的 PID”实验方法不需要写一行代码只需要一个空白电子表格就能亲手搭出一个 PID 闭环控制系统完成参数整定实验甚至能直观看到比例、积分、微分各自对响应曲线的影响。学完之后你可以把同一套离散化逻辑平滑迁移到 STM32、Python、MATLAB 等真实项目中。1. 背景为什么 PID 可以用电子表格讲清楚1.1 PID 不是一个需要“高数”才能理解的算法PID 是 Proportional比例、Integral积分、Differential微分的缩写。中文里常写成“比例-积分-微分控制器”。它的作用很简单根据“目标值”和“当前测量值”之间的误差计算出一个控制量让测量值尽快、平稳地逼近目标值。在连续数学表达式中PID 的输出是[ u(t)K_p e(t) K_i \int e(t) dt K_d \frac{de(t)}{dt} ]一看到积分符号 (\int) 和导数符号 (\frac{d}{dt})很多人的第一反应是“完了要复习微积分”。但实际上在数字控制器和计算机控制系统里我们并不能直接处理连续积分和连续微分所有公式都要离散化。离散化之后积分变成“误差的累加”微分变成“误差的差值”。累加和差值小学算术就能搞定。所以我说“Calculus-free PID”并不是把 PID 简化成了另一个东西而是指在数字世界里PID 的底层实现本来就是简单的加减乘除。1.2 电子表格是理解 PID 的最佳“白板”电子表格Excel、WPS、Google Sheets 等天然适合做离散化计算每一行可以代表一个采样周期。每一列可以存放设定值、测量值、误差、比例项、积分项、微分项、输出值。用填充柄向下拖拽公式就能模拟一个连续运行的控制回路。插入折线图就能看到超调、振荡、稳态误差等经典现象。这种方式的优势是“透明”。Python 代码写一个回调函数你只能看到最终曲线但在电子表格中你能清楚地看到每一行误差如何变化、积分项如何累积、微分项如何对噪声敏感。这对于建立 PID 直觉非常有帮助。1.3 这篇文章适合谁刚开始学 PID但被微积分公式劝退的初学者。准备在 STM32、PLC、ROS 等平台上做 PID 控制想先理解算法本质的开发者。已经会调参但想找一个快速验证工具观察参数变化对响应影响的人。需要给学生或新人做控制算法培训需要一个可视化实验环境的人。读完本文你将掌握 PID 的离散化形式、电子表格模拟方法、参数整定实验以及从电子表格迁移到真实代码的完整思路。2. PID 控制的核心原理拆解2.1 三个基本项比例、积分、微分在离散系统中我们按固定的采样周期 (T) 定时读取测量值每次计算一次控制输出。假设当前时刻为第 (k) 次采样目标值为 (SV_k)测量值为 (PV_k)误差为[ e_k SV_k - PV_k ]那么三个分项分别这样算。2.1.1 比例项现在错多少比例项的输出是[ P_k K_p \times e_k ]它把当前误差放大 (K_p) 倍。误差大输出就大误差小输出就小。比例项是控制系统的主力但单独使用通常会出现“稳态误差”——系统稳定后测量值和目标值之间始终差了一截。比如你用比例控制一个风扇转速设定 3000 转当负载导致转速下降时比例项会提高输出电压但它需要存在误差才能维持输出所以最终转速通常会稳定在目标值附近但不会完全等于目标值。2.1.2 积分项过去错多少积分项在离散系统中是“误差的累加”[ I_k I_{k-1} K_i \times e_k \times T ]也可以写成[ I_k K_i \times T \times \sum_{j1}^{k} e_j ]关键点积分项会把历史误差一直记着。只要有残差存在积分项就会持续增大从而推动输出逐渐逼近目标值最终消除稳态误差。但积分项太强也会带来问题超调变大、系统出现低频振荡甚至积分饱和。2.1.3 微分项误差变化趋势微分项在离散系统中是“误差的差值除以采样周期”[ D_k K_d \times \frac{e_k - e_{k-1}}{T} ]它预测误差接下来是变大还是变小。如果误差正在快速减小微分项会产生一个反向“刹车”作用抑制超调。但微分项有一个著名的副作用对测量噪声非常敏感。因为噪声会让相邻两次采样误差产生抖动微分项会把这种抖动放大严重时系统会高频振荡。2.2 位置式 PID 与增量式 PID上述公式计算的是控制器输出 (u_k) 的绝对值称为“位置式 PID”[ u_k P_k I_k D_k ]实际嵌入式项目中还有一种常见写法是“增量式 PID”它只计算输出的增量[ \Delta u_k u_k - u_{k-1} ]增量式的优势是输出不会突变适合带积分执行机构的场合比如步进电机调速。但理解 PID 本质先看位置式更直观。电子表格模拟也更容易。2.3 采样周期 T 的重要性离散 PID 公式里的 (T) 不是摆设。(T) 越小控制越接近连续系统但计算负担和噪声敏感度也会增加(T) 越大控制越粗糙甚至可能失稳。在电子表格中(T) 就是一个单元格里的数值。改变它你会立刻看到曲线变化。这也是电子表格实验的价值所在——不用写代码改一个单元格就能体验采样周期的影响。3. 环境准备创建一个 PID 电子表格模拟器3.1 软件环境本文以最常见的 Excel 操作为例但同样适用于 WPS 表格、Google Sheets、LibreOffice Calc。公式基本都是通用的。版本不需要特别新只要是近十年内的办公表格软件都可以。重点是掌握“单元格引用”“填充柄下拉”“插入折线图”这三个基础操作。3.2 被控对象模型要模拟闭环控制我们需要一个“被控对象”。现实中它可能是电机、加热器、水箱液位等。本文使用一个最经典的一阶惯性系统数学描述是[ T_s \frac{dPV}{dt} PV K_s \times u ]其中(u)控制器输出例如控制电压(PV)被控量例如转速、温度、液位(K_s)系统增益(T_s)系统时间常数这个模型的好处是只需要两个参数 (K_s) 和 (T_s)就能模拟大多数常见的惯性对象。离散化之后下一时刻的测量值公式为[ PV_{new} PV_{old} \frac{T}{T_s} \times (K_s \times u_{old} - PV_{old}) ]这个公式非常容易放进电子表格。它不涉及真实硬件却保留了闭环系统的主要特征。3.3 表格整体设计我们准备让每一行代表一个采样时刻。列结构如下列含义示例公式A时间 (t)(0, 0.1, 0.2...)B设定值 (SV)阶跃到 100C测量值 (PV)初值为 0后续由模型算出D误差 (e)(B2-C2)E比例项 (P)(Kp*D2)F积分项 (I)上一行积分 (KieT)G微分项 (D)(Kd*(e - 前一时刻e)/T)H控制器输出 (u)(PID)并做限幅参数区放在右侧单元格例如 K 列K1(K_p)K2(K_i)K3(K_d)K4采样周期 (T)K5系统增益 (K_s)K6系统时间常数 (T_s)K7输出下限K8输出上限修改参数区里的数值整个响应曲线会跟着变化这就是“几乎在电子表格里实现 PID”的核心体验。4. 手把手搭建 PID 电子表格模拟器4.1 设置参数区打开一个空白工作表在 K1:K8 单元格输入以下初值单元格参数初值K1Kp1.0K2Ki0.2K3Kd0.05K4T0.1K5K_sys1.0K6T_sys1.0K7umin0K8umax100这些值会在后续实验中反复修改。4.2 输入表头在第 1 行输入表头A1B1C1D1E1F1G1H1时间设定值测量值误差比例项积分项微分项输出4.3 输入初始状态行第 2 行我们需要在第 2 行建立初始状态。此时系统刚刚上电测量值为 0控制器还没有开始累积积分微分项也为 0。在 A2 输入0B2 输入设定值这里模拟一个从 0 阶跃到 100 的过程100C2 输入初始测量值0D2 输入误差公式B2-C2E2 输入比例项公式$K$1*D2F2 输入积分项初值0G2 输入微分项初值0H2 输入输出值同时做限幅防止出现负数或超过执行器范围MAX($K$7,MIN($K$8,E2F2G2))注意这里使用了绝对引用$K$7、$K$8目的是让公式下拉时不会改变行号。4.4 输入第二行第 3 行并下拉第 3 行开始体现真正的闭环迭代。先输入 A3 时间A2$K$4B3 设定值继续保持 100 B2C3 测量值需要根据上一行的输出 (u_2) 和上一行的测量值 (PV_2)用一阶惯性模型更新C2 ($K$4/$K$6)*($K$5*H2 - C2)这里再解释一下这个公式的来由离散化后的对象模型 (PV_{new} PV_{old} \frac{T}{T_s}(K_s \times u - PV_{old}))。H2 是上一行输出C2 是上一行测量值。D3 误差公式B3-C3E3 比例项$K$1*D3F3 积分项使用上一行 F2 累加F2 $K$2*D3*$K$4G3 微分项使用当前行与上一行的误差差值$K$3*(D3-D2)/$K$4H3 输出限幅MAX($K$7,MIN($K$8,E3F3G3))选中 A3:H3使用填充柄向下拖拽。拖到第 102 行左右就是模拟 10 秒100 步 x 0.1s。4.5 绘制响应曲线选中 A 列、C 列、H 列也就是时间、测量值、输出值插入“带平滑线和数据标记的折线图”。如果在 Excel 中不方便一次选中不连续列可以先插入空白折线图然后右键“选择数据”分别添加系列名称PVX 轴选择 A 列数据Y 轴选择 C 列数据。系列名称SVX 轴选择 A 列数据Y 轴选择 B 列数据。系列名称uX 轴选择 A 列数据Y 轴选择 H 列数据。也可以直接选中 A、C、H 三列后插入折线图Excel 会自动生成。初始参数下你应该能看到测量值在 1 秒左右上升到接近 100然后出现一个较小的超调最终稳定在 100 附近。这就是一个完整的 PID 闭环响应。4.6 预期结果说明在 (K_p1.0, K_i0.2, K_d0.05, T0.1) 的初始参数下测量值会快速上升但因为积分项存在超调可能达到 10% 左右然后经过几次衰减振荡后收敛。输出 u 会从 100% 开始随后逐渐下降稳定在维持测量值 100 所需的输出值附近。如果你的曲线完全不动或者出现直线上升请先检查 C3 公式里是否引用了 H2F3 公式是否引用了 F2G3 公式是否引用了 D2。这是最容易出错的地方。5. 用电子表格完成 PID 参数整定实验有了这个“电子表格 PID 实验台”接下来可以亲手做三个经典实验。这比直接改代码更能建立直觉。5.1 实验一纯比例控制观察稳态误差将 (K_i) 和 (K_d) 都设为 0只保留 (K_p1.0)刷新后下拉观察曲线。你会发现测量值会快速上升然后稳定在某个值但永远达不到 100比如稳定在 95 左右。这个差值就是“稳态误差”。原因很简单比例控制需要误差存在才能产生输出误差为零时比例项输出为零系统无法维持。你可以试着把 (K_p) 提高到 3、5、10会发现稳态误差变小但超调和振荡会变大。这验证了一个结论单纯增加比例增益无法彻底消除稳态误差只会让系统越来越“急躁”。这个实验强烈建议在电子表格里做一次因为屏幕上每一行的误差数据都清晰可见你能亲眼看到稳态误差不是“调不好”而是结构性的存在。5.2 实验二加入积分项消除稳态误差恢复 (K_p1.0)设置 (K_i0.2)(K_d0)。此时测量值会更快地贴近 100最终误差趋近于零。同时你也会看到超调比纯比例控制更大甚至出现低频振荡。积分项的魅力在于它“记住”了过去的误差。哪怕当前误差很小只要不等于零积分项就会一点点累积推动输出继续变化直到误差彻底归零。但积分项也像一把双刃剑(K_i) 太大、(T) 太大甚至启动时的初始误差就会导致积分饱和输出长时间维持在最大值系统剧烈超调。你可以试着把 (K_i) 从 0.2 改到 0.5再改到 1.0观察超调如何一步步变大。5.3 实验三加入微分项抑制超调恢复 (K_p1.0, K_i0.2)设置 (K_d0.05)然后观察曲线。微分项会在误差快速变小时提前“刹车”所以超调通常会小于纯比例积分控制。继续增大 (K_d) 到 0.2、0.5你会发现超调被压制但曲线变得“毛糙”甚至出现高频抖动。这就是微分项在放大测量噪声。为了更直观地体验噪声对微分项的影响你可以在 C 列测量值公式里故意加一个小扰动例如改成C2 ($K$4/$K$6)*($K$5*H2 - C2) $K$9K9 单元格里填一个随机噪声值比如RAND()*0.5-0.25然后观察 G 列微分项的变化。你会看到即使测量值只抖动了一点微分项也可能会跳得很大。这个实验也解释了为什么真实项目里微分项通常需要配合低通滤波使用甚至很多系统干脆不用微分项。5.4 参数整定的经验口诀电子表格实验做完后可以记住一条通用调参顺序先把 (K_i)、(K_d) 设为 0只留 (K_p)从小到大增加直到系统出现等幅振荡。再把 (K_p) 适当回退到振荡点的 50% 左右。加入 (K_i)从小到大增加直到稳态误差被消除但注意观察超调。最后加入 (K_d)从小到大增加用来抵消超调但小心噪声放大。这只是一条经验不是万能公式。实际项目中结合 Ziegler-Nichols 等整定方法或者 MATLAB Response Optimizer 这类工具可以做更精细的调优。但电子表格实验能帮你建立“参数改变后曲线会怎么变”的直觉这种直觉在真实调试中远比死记公式更有价值。6. 从电子表格到真实代码Python 实现同一个 PID如果只在电子表格里跑你可能还会怀疑“这套逻辑能不能搬到真实程序里”。下面用 Python 实现完全相同的离散 PID 和一阶惯性系统可以直接运行。你可以对比输出结果和电子表格生成的曲线会发现它们几乎完全一致。这个对照过程是把电子表格思路迁移到代码的关键一步。6.1 完整示例代码import numpy as np import matplotlib.pyplot as plt # PID 参数 Kp 1.0 Ki 0.2 Kd 0.05 # 采样周期 T 0.1 # 被控对象参数 K_sys 1.0 T_sys 1.0 # 输出限幅 umin 0 umax 100 # 模拟时长 t_end 10 t np.arange(0, t_end, T) n len(t) # 设定值阶跃到 100 SV np.ones(n) * 100 # 初始化变量 PV np.zeros(n) u np.zeros(n) I 0.0 e_prev 0.0 for i in range(n): # 当前误差 e SV[i] - PV[i] # 比例项 P Kp * e # 积分项使用上一次累积值当前时刻输出中还没有加入本次误差 # 对应电子表格中 F 列第 2 行积分为 0第 3 行才开始累加 I I # 保持当前 I 用于输出 # 微分项第一次采样时微分项为 0避免初始冲击 if i 0: D 0.0 else: D Kd * (e - e_prev) / T # 控制器输出 u_raw P I D u[i] np.clip(u_raw, umin, umax) # 更新积分项供下一次使用 I I Ki * e * T # 根据一阶惯性模型计算下一时刻的测量值 if i n - 1: PV[i 1] PV[i] (T / T_sys) * (K_sys * u[i] - PV[i]) # 记录当前误差用于下一次微分项 e_prev e # 绘图 plt.figure(figsize(10, 5)) plt.plot(t, SV, --, labelSV) plt.plot(t, PV, labelPV) plt.plot(t, u, labelu) plt.xlabel(Time (s)) plt.ylabel(Value) plt.legend() plt.grid(True) plt.title(Discrete PID in Python) plt.show()需要注意代码中积分项更新位置刻意和电子表格保持一致当前行的输出使用的是上一行累积下来的 (I)输出计算完之后才把当前误差累加进去。这样不会出现“本周期输出提前包含本周期积分变化”的问题。运行这段代码后你会得到与电子表格几乎一致的曲线。但由于电子表格中微分项的计算方式、浮点精度、输出限幅位置可能存在细微差异数值不会逐位完全相同这属于正常现象。6.2 电子表格与代码的优势互补电子表格的优势是“便于观察和教学”每一列计算过程都摊开展示在眼前。代码的优势是“便于迭代和集成”可以快速写进你的 STM32 项目、ROS 节点或自动化控制系统。建议你同时掌握两者先用电子表格理解 PID 内部计算过程再用 Python 做批量参数扫描最后迁移到目标硬件。这种路径比直接啃公式硬快得多。7. 常见问题与排查思路在搭建电子表格 PID 模拟器和后续控制实验过程中容易遇到这些问题。下面整理成一张速查表。问题现象常见原因解决思路曲线不变化测量值一直是 0C 列模型公式没有正确引用上一行 H 列检查 C3 公式是否包含 H2并确认 H2 有非零输出输出瞬间到 100%无法回落积分项过大或初值误差导致积分饱和减小 Ki或者对 F 列积分项做限幅系统振荡越来越剧烈甚至发散比例项过大采样周期 T 过大减小 Kp减小 T查看曲线是否稳定输出曲线出现锯齿、高频抖动微分项放大噪声或测量值存在微小突变减小 Kd或对微分项增加一阶低通滤波稳态误差一直存在积分项为 0或 Ki 太小恢复 Ki 并缓慢增大观察稳态误差是否消失输出长期等于 0 或 100输出限幅设置太小/太大积分饱和检查 umin/umax加入抗积分饱和逻辑下拉公式后数值出现大量循环引用公式错误引用自身单元格重新检查公式中引用的行列避免 H 列引用 H 列图表中只显示一条直线只选择了输出列未选择时间列在选择数据时将 X 轴设置为 A 列时间如果曲线发散一个快速排查手段是把 (K_i)、(K_d) 全设为 0只保留很小的 (K_p)确认系统能稳定。然后再逐步增加 (K_p)、(K_i)、(K_d)。这本质上就是“控制变量法”在电子表格里操作非常方便。8. PID 工程实战建议与安全边界电子表格只是起点真实系统远比这个模拟复杂。把 PID 用在实际项目中以下建议值得认真对待。8.1 采样时间和执行器刷新频率要匹配采样周期 (T) 不是越短越好也不是越长越好。它需要与传感器响应速度、执行器刷新频率、控制器计算能力匹配。电子表格里随手可以改 (T)但到嵌入式环境定时器中断频率、通信周期都会限制最高采样率。8.2 输出限幅和积分限幅必须一起处理只对输出限幅不限制积分项很容易出现“积分饱和”。现象是当系统长时间无法达到目标时积分项累积到很大一旦测量值到达目标积分项还需要很长时间才能“吐出来”导致严重超调。常见处理方式是在积分项计算时做限幅或者仅在输出未饱和时积分。具体到电子表格可以把 F 列公式改为限幅形式MAX($K$7, MIN($K$8, F2 $K$2*D3*$K$4))这样积分项不会超过执行器能力范围对抗积分饱和有一定帮助。8.3 微分项必须考虑噪声抑制真实传感器都有噪声纯微分项会把噪声放大因此工程上常用“不完全微分”或“微分先行”。最灵活的做法是让微分项通过一个低通滤波器比如[ D_{filtered} \alpha \times D_{raw} (1-\alpha) \times D_{filtered_prev} ]其中 (\alpha) 是滤波系数。电子表格只能模拟理想情况真实项目中这一点不能省。8.4 手动自动切换和参数保存很多板卡和控制器支持手动/自动模式切换。在切换瞬间如果 PID 输出和手动输出不一致系统会产生冲击。通常需要在切换前把积分项重置为当前输出对应的值或者实行“无扰切换”bumpless transfer。此外参数整定结果不要只看一组曲线要保存多组参数样本记录目标对象、工况、采样周期、Kp/Ki/Kd 和响应指标。这样后续调优才能有据可查。8.5 生产环境安全边界如果 PID 控制用在真实设备上比如电机、加热器、压力阀一定要有安全保护机制输出限幅必须根据执行器安全范围设置。增加急停逻辑例如测量值超过安全阈值时强制输出为 0 或切到安全状态。修改参数应在测试环境或低功率工况下先验证确认无异常后再接入生产系统。涉及数据库、生产环境变更时要遵守最小权限原则并做好备份。PID 只是控制层的一部分不要忽视传感器故障、通信中断、执行器卡死等异常情况。这些内容看似与“电子表格模拟 PID”无关但实际上是从实验环境走向真实项目时最容易踩坑的地方。提前知道能省很多现场调试时间。9. 总结与下一步学习路线这篇文章围绕“Calculus-free PID almost in a spreadsheet”展开核心是让你不必纠结微积分而是用离散化视角和电子表格工具亲手搭出一个可视化的 PID 闭环系统。你实际操作时应该已经尝到了三个阶段的变化第一阶段纯比例控制看到稳态误差。第二阶段加入积分项看到超调和振荡。第三阶段加入微分项看到超调被压制也看到噪声放大。这种“亲眼看曲线变化”的体验比记住任何公式都更牢固。如果你能独立完成这三个实验并尝试修改 Kp、Ki、Kd、T 等参数那么 PID 对你来说就不是一个黑盒了。下一步可以继续延伸的方向包括把电子表格里的离散 PID 公式迁移到 STM32 或 Arduino做电机转速闭环。研究增量式 PID 与位置式 PID 的区别以及各自的适用场景。学习串级 PID 和双环 PID比如四轴飞行器中常见的内环角速度、外环角度控制。了解模糊 PID 等自适应控制方法它们能在参数变化较大的工况下自动调整 PID 参数。使用 MATLAB Response Optimizer 或 Simulink 做更精细的模型仿真与参数优化。无论你最后走向哪个方向电子表格里这几列数据就是你理解 PID 的“最原始版本”。把这一套计算逻辑吃透再去接触上层工具和真实硬件会顺畅得多。现在就可以打开一个空白电子表格把这 8 个参数和 3 行公式填进去下拉到 100 行再把图表画出来。只有亲手拖动一次填充柄你才能真正感受到“ PID 原来不过如此。”