拓冰建站拓冰建站
首页 / 资讯中心 / 正文

增量式PID原理与MATLAB仿真:参数整定、抗饱和与C移植

简介这是一份面向自动化、控制工程与嵌入式方向学习者的增量式PID控制算法MATLAB仿真文档聚焦被控对象传递函数的离散化建模、控制器实现与参数整定适合课程设计、毕业设计和仿真实验入门。资源包内仅含一个docx文件大小约162KB正文以原理推导、程序清单、波形结果和调试记录组织便于直接阅读与复现。文档从比例、积分、微分控制原理切入说明增量式算法输出控制量增量而非绝对量并演示Z变换、差分方程、状态变量计算及MATLAB代码实现涵盖单位阶跃与正弦输入、毫秒级采样、控制器输出限幅、系统输出和误差曲线绘制。文中还记录比例、积分、微分三个增益由临界稳定逐步调节的过程可帮助读者理解参数变化对超调、振荡和稳态误差的影响并对照仿真波形排查效果不理想的原因。已有2088人学习下载适合需要快速掌握增量式PID仿真流程与调参思路的读者参考。1. 从执行器抖动说起增量式PID到底解决什么问题做过温度控制的人多半遇到过这种现场加热丝在稳态附近来回抽动电机调速时转速在一两百转内高频晃。把位置式 PID 换成增量式 PID同一组参数下曲线反而干净很多。原因不玄学——位置式 PID 每拍算的是绝对输出量 u(k)积分项对历史误差累加累加器一旦被扰动带偏或者手动/自动切换瞬间误差突变u(k) 会直接跟着跳执行器只能照单全收。增量式 PID 算的是增量 Δu(k)执行环节自己保留上一次的位置控制器只告诉它「再加一点」。输出天然具备保持特性切换或复位时没有冲击单拍算错也只影响一步。代价是必须有一个能累加的执行环节阀门、变频器、PWM 占空比寄存器都满足。后面的内容围绕 MATLAB 展开先把差分方程推清楚再搭一个最小仿真闭环然后把参数整定、仿真发散、积分饱和这些坑逐个拆开。适合做嵌入式温控、电机调速、PLC 模拟量输出的工程师也适合想把算法先在 MATLAB 上验证再往 C 里搬的人。2. 增量式PID的差分方程推导与位置式PID的取舍2.1 位置式PID的离散化差分方程长什么样连续形式的位置式 PID 是大家熟的那一条u(t) Kp * [ e(t) (1/Ti) * ∫e(t)dt Td * de(t)/dt ]做数字控制必须离散化。常见做法是积分用矩形法累加、微分用后向差分采样周期记作 Tu(k) Kp*e(k) Kp*(T/Ti)*Σe(j) Kp*(Td/T)*[e(k)-e(k-1)]把两个组合系数拎出来记 Ki KpT/Ti、Kd KpTd/T就是写代码时最熟的那版u(k) Kp*e(k) Ki*Σ(j0..k)e(j) Kd*[e(k)-e(k-1)]这条式子有三个后遗症。第一Σe(j) 是一个只增不减的累加器必须用一个变量常驻保存溢出和饱和都出在这里。第二输出是绝对量执行器拿到的就是 u(k) 本身限幅做在输出口上。第三Ki 和 Kd 都含 T采样周期一改之前调好的参数全部失效。这三条正是后面所有坑的源头。2.2 两步相减推出增量式PID的三系数形式把 2.1 的式子写成 k-1 拍u(k-1) Kp*e(k-1) Ki*Σ(j0..k-1)e(j) Kd*[e(k-1)-e(k-2)]两式相减求和项被消掉只剩 e(k) 这一项Δu(k) u(k) - u(k-1) Kp*[e(k)-e(k-1)] Ki*e(k) Kd*[e(k)-2e(k-1)e(k-2)]把 e(k)、e(k-1)、e(k-2) 的系数合并Δu(k) A*e(k) - B*e(k-1) C*e(k-2) A Kp Ki Kd B Kp 2*Kd C Kd这就是工程上常说的「三系数增量式 PID」。它的状态只有两个e(k-1) 和 e(k-2)。没有积分累加器所以不存在累加器溢出系数 A、B、C 一旦算好每拍只做三次乘法和两次加减Cortex-M0 级别也扛得住。注意没有累加器不等于天然抗积分饱和。u(k) u(k-1) Δu(k) 本身就是一次累加u 顶到限幅之后 Δu 还在算恢复时照样会冲过头。抗饱和得单独做见 4.4。位置式和增量式的差别可以整理成一张表选型时对着看对比项位置式 PID增量式 PID输出含义绝对量 u(k)增量 Δu(k)需要保存的状态e(k-1)、积分累加器e(k-1)、e(k-2)手动/自动切换需做无扰切换处理天然平滑积分饱和风险高必须有抗饱和累加仍会饱和需限幅适合的执行器伺服位置给定、绝对量输出阀门、变频器、PWM采样周期改动Ki、Kd 全部要重算同样要重算但系数可整体缩放2.3 三种等价写法的MATLAB实现与取舍第一种是直接用 Kp、Ki、Kd 写好处是整定结果能和位置式共用function [du, st] pid_inc_gain(Kp, Ki, Kd, ek, st) % 增量式PID由 Kp/Ki/Kd 直接计算本拍增量 % st.e1 存 e(k-1)st.e2 存 e(k-2) du Kp*(ek - st.e1) Ki*ek Kd*(ek - 2*st.e1 st.e2); st.e2 st.e1; % 历史误差整体后移一拍 st.e1 ek; end第二种是三系数形式适合参数定死、要往单片机上搬的场景function [du, st] pid_inc_abc(A, B, C, ek, st) % 增量式PID三系数形式每拍三次乘法 du A*ek - B*st.e1 C*st.e2; st.e2 st.e1; st.e1 ek; end两种写法数学上完全等价区别在于pid_inc_gain 改一个 Kp 不需要重算别的调试期用它pid_inc_abc 把系数在初始化时算好运行期不再碰乘法以外的逻辑量产代码用它。实测中还有一个细节A、B、C 用定点数存的时候要留意 A 的绝对值最大通常取 Q12 或 Q15 格式先把 Kp、Ki、Kd 放大再截断别到运行期才转。第三种写法是把 Ki 并进 Kp也就是所谓的 PI 增量式只保留 A、B 两个系数。微分项在温度这种大惯性对象上贡献有限噪声又大很多现场干脆不用 D。要不要砍掉 D看 4.3 里微分项的排查结果。3. 在MATLAB里跑通增量式PID仿真的最小闭环3.1 被控对象建模与采样周期T的选取仿真发散有一多半不是 PID 的问题是对象模型和采样周期没配对。温度、加热这类过程常用一阶惯性加纯滞后G(s) K0 / (T0*s 1) * exp(-tau*s)K0 是对象增益T0 是时间常数tau 是纯滞后。用零阶保持离散化得到可以直接迭代的差分方程a exp(-T/T0) b K0*(1 - a) d round(tau/T) y(k) a*y(k-1) b*u(k-1-d)d 是滞后拍数取整之后会引入误差所以 T 不能取得太大。采样周期的经验是 T 取 T0 的 1/10 到 1/20同时保证纯滞后至少覆盖 3 到 5 个采样拍。算下来 d 小于 2 的时候仿真里的振荡往往是离散化误差不是控制器真的不稳。一组可以直接抄的参数参数取值说明K02对象静态增益T020 s时间常数tau5 s纯滞后T0.5 s采样周期T0/40d10tau/T滞后拍数t_end100 s仿真时长3.2 增量式PID控制器的MATLAB函数控制器就写成 2.3 里的 pid_inc_gain单独一个文件方便后面做位置式对比时两边共用。状态用结构体传递避免用 globalfunction [du, st] pid_inc_gain(Kp, Ki, Kd, ek, st) % 增量式PID状态结构体 st 含 e1、e2 du Kp*(ek - st.e1) Ki*ek Kd*(ek - 2*st.e1 st.e2); st.e2 st.e1; st.e1 ek; end参数顺序不要随意调。ek 是当前误差必须是本拍采样得到的值st 是上一次调用留下的状态第一次调用前要显式初始化为 struct(e1,0,e2,0)否则 MATLAB 会报字段不存在。3.3 主仿真脚本阶跃响应从0到稳态下面是完整脚本把对象、控制器、限幅串成一个闭环。注意误差取的是 r - y(k-1)因为数字控制器先采样上一拍输出、再计算、再输出这个顺序和实际程序一致。%% 增量式PID MATLAB仿真最小闭环 clear; clc; close all; T 0.5; t_end 100; N round(t_end/T); K0 2; T0 20; tau 5; d round(tau/T); a exp(-T/T0); b K0*(1-a); Kp 0.8; Ki 0.05; Kd 0.5; % 待整定参数 r 1; % 阶跃给定 u_max 5; u_min 0; % 执行器上下限 y zeros(1,N); u zeros(1,N); e zeros(1,N); st struct(e1,0,e2,0); u_prev 0; for k 2:N e(k) r - y(k-1); % 当前误差 [dk, st] pid_inc_gain(Kp, Ki, Kd, e(k), st); u_old u_prev; u_prev u_prev dk; % 增量累加成绝对输出 u_prev min(max(u_prev, u_min), u_max);% 限幅 dk u_prev - u_old; % 实际生效的增量 u(k) u_prev; idx k - 1 - d; % 纯滞后回看 if idx 1 ul u(idx); else ul 0; end y(k) a*y(k-1) b*ul; % 对象差分方程 end figure; subplot(2,1,1); plot((0:N-1)*T, y, LineWidth,1.2); grid on; ylabel(y); subplot(2,1,2); plot((0:N-1)*T, u, LineWidth,1.2); grid on; ylabel(u); xlabel(t/s);逻辑上有三处容易写错滞后索引 idx 是从 k-1-d 往前回看写反会变成超前限幅要放在累加之后、赋值给 u(k) 之前dk 被限幅改写之后下一拍用作判断的 u_prev 已经是最新的饱和值反算才成立。3.4 仿真曲线怎么读超调、上升时间、稳态误差跑完之后不要只看形状把三个指标算出来。手写循环没有现成的 stepinfo 可用可以自己提ymax max(y); overshoot (ymax - r)/r*100; % 超调量 % i10 find(y 0.1*r, 1); i90 find(y 0.9*r, 1); tr (i90 - i10)*T; % 上升时间 s ess r - mean(y(end-100:end)); % 稳态误差 fprintf(超调 %.1f%%, 上升时间 %.2f s, 稳态误差 %.4f\n, overshoot, tr, ess);目标形态是超调 10% 到 20%、上升时间在 1 到 2 倍 T0 之间、稳态误差趋近 0。三样里只要有一项不对劲就去 4.3 的排查表里对号入座不要先去动参数。4. 增量式PID参数整定与仿真发散排查4.1 Kp、Ki、Kd与PB、TI、TD的换算关系西门子 S7-200 SMART、三菱 FX 系列以及不少温控仪表用的是另一套参数PB 是比例带%TI 是积分时间sTD 是微分时间s。从现场抄下来的参数要进 MATLAB必须先换算Kp 100 / PB Ki Kp * T / TI Kd Kp * TD / T反过去也一样PB 100 / Kp TI Kp * T / Ki TD Kd * T / Kp举个实际的PB20%、TI40 s、TD5 s采样周期 T0.5 s算出来 Kp5、Ki50.5/400.0625、Kd55/0.550。注意 TD 只有 5 秒换算完 Kd 却有 50这就是为什么增量式 PID 里 Kd 经常比 Kp 大一个量级——它乘的是二阶差分不放大根本不起作用。现场参数数值换算结果数值PB20%Kp5TI40 sKi0.0625TD5 sKd50T0.5 s——提示不同品牌的 TI、TD 单位可能是秒也可能是分钟某些仪表还有 TI0 表示取消积分的约定。抄参数前先翻一眼手册单位错了整定方向会完全反掉。4.2 用pidTuner先调位置式再换算增量式增益MATLAB 的 pidTuner新版叫 PID Tuner App只能对线性模型调参拿到的是位置式增益但 Kp、Ki、Kd 的定义和增量式完全一致可以直接代入G tf(K0, [T0 1], InputDelay, tau); Gd c2d(G, T, zoh); % 采样周期必须和仿真脚本一致 pidTuner(Gd, PID); % 交互式拖动满意后导出 Kp/Ki/Kd导出数值之后把 3.3 脚本里的 Kp、Ki、Kd 替换掉即可。这里有两个硬约束c2d 用的 T 必须等于仿真脚本的 T否则 Ki、Kd 全错pidTuner 默认按「平衡响应」给参数实际工程里如果超调偏大可以手动把 Kd 减一半再跑很多时候 pid 最优曲线并不等于现场最舒服的曲线执行器动作幅度也是约束。4.3 仿真发散的六类原因与逐条定位曲线发散的原因和现象基本是一对一的对表排查比盲调参数快得多现象最可能原因排查动作指数上扬不振荡Kp 过大超过稳定边界把 Ki、Kd 置 0只留 P 单独试一拍正一拍负的高频振荡采样周期 T 相对 T0 太大或滞后拍数 d 太小T 减半重跑d 至少 3周期几秒到几十秒的缓慢振荡Ki 偏大Ki 降到原来的 1/2 或 1/3曲线上有密集毛刺并逐渐发散Kd 偏大微分在放大测量噪声微分改为对 y 求差分或串一阶低通u 顶到限幅、y 不动之后大幅超调积分饱和加限幅并做反算抗饱和曲线朝反方向跑到底反馈极性接反检查 e r - y 的符号第一类最容易被误判成对象不稳。判断方法很直接Kp 单独作用时如果输出单调发散那确实是 Kp 过大如果输出是振荡发散通常是 T 和 d 的组合问题。4.4 积分饱和、输出限幅与抗噪声的微分改法第三条排查里提到反算抗饱和具体写法是在累加限幅之后把被削掉的部分从增量里扣回去u_old u_prev; u_prev u_prev dk; if u_prev u_max u_prev u_max; elseif u_prev u_min u_prev u_min; end dk u_prev - u_old; % 实际生效的增量回写给状态判断这一行 dk u_prev - u_old 是关键。不加它控制器内部以为输出到了 8实际执行器停在 5等误差反号之后要先把内部这笔「虚账」还完才肯掉头超调就是从这里来的。微分冲击是另一个常见问题。给定值阶跃跳变时de/dt 理论上是冲激实际代码里就是采样点上的一个尖峰。把微分作用改到 y 上可以绕开function [du, st] pid_inc_dy(Kp, Ki, Kd, ek, yk, st) % 微分作用在输出 y 上避免给定跳变时产生微分冲击 dy yk - st.y1; du Kp*(ek - st.e1) Ki*ek - Kd*dy; st.e1 ek; st.y1 yk; end这样改的代价是微分不再响应给定的前馈变化跟踪型应用里上升时间会略变长。跟踪精度要求高的场合可以保留 e 的微分但给 Kd 串一个一阶低通Kd_lp Kd * alphaalpha 取 0.1 到 0.3实测能把毛刺压掉又不太伤相位。5. 增量式PID的进阶玩法与结果验证5.1 增量式与位置式在同一对象上的对比实验同一对象、同一组 Kp/Ki/Kd两个控制器并排跑差异一眼能看出来。把两种实现都包成函数签名保持一致[u_inc, y_inc] sim_inc(Kp, Ki, Kd, T, N, a, b, d, u_max, u_min, r); [u_pos, y_pos] sim_pos(Kp, Ki, Kd, T, N, a, b, d, u_max, u_min, r); plot((0:N-1)*T, y_pos, --, (0:N-1)*T, y_inc, -, LineWidth, 1.2); legend(位置式,增量式); grid on; xlabel(t/s); ylabel(y);位置式那版要显式维护积分累加器并在每次更新后判断限幅状态。跑出来通常能看到给定阶跃阶段两条曲线几乎重合差异出现在给定突变、手动切换、输出饱和恢复这三个时刻。增量式在这三处的输出更连贯位置式则容易出现一次明显的跳变。5.2 级联PID外环位置式、内环增量式温度-流量、位置-速度这类双环结构里常见做法是外环用位置式、内环用增量式。外环的输出含义是「给内环的设定值」本身就是绝对量用位置式更直观内环直接驱动变频器或 PWM 占空比用增量式省状态、切换平滑。% 外环位置式输出作为内环给定 [r_inner, st_out] pid_pos(Kp1, Ki1, Kd1, r - y_out, st_out); % 内环增量式输出到执行器 [du_in, st_in] pid_inc_gain(Kp2, Ki2, Kd2, r_inner - y_in, st_in);两环的采样周期一般差 5 到 10 倍内环快、外环慢。写仿真时要按各自周期分别积分不能共用一个循环节拍否则内环的积分项会算错。5.3 从仿真到C代码的验证清单仿真跑通之后往单片机或 PLC 搬之前逐条对一遍检查项仿真里怎么验移植后怎么验系数溢出A/B/C 用定点数截断重跑打印中间值看是否回绕采样周期一致T 与定时器中断周期对齐用示波器量中断间隔状态初始化struct 显式赋 0上电首拍手动清 e1、e2限幅位置累加后、赋值前限幅分支加断点手动/自动切换手动段强制 u_prev 跟随切换瞬间看 u 有无跳变抗饱和反算dk 扣回后重跑饱和场景长时间顶限幅后撤给定验证最有效的一招是把同一组输入数据分别喂给 MATLAB 和 C 代码逐拍比对 du 的数值。定点实现下允许最后一两位差异如果从某一拍开始整体偏移多半是状态更新顺序写反了——MATLAB 里先算 du 再挪历史C 代码里写成先挪历史再算 du误差就会一路累积下去。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门