
一句话介绍: 这套 MATLAB 程序针对一阶纯滞后对象建立广义预测控制仿真,使用预测时域 N=8、控制时域 Nu=6 和平滑参考轨迹,在仿真中途加入 −0.2 输入扰动,再通过不同控制加权 λ 对比输出跟踪与控制动作,适合观察 GPC 对时滞、扰动以及控制量惩罚的处理机制。
普通反馈控制主要根据“现在误差有多大”决定当前控制动作。
但当前对象带有明显纯滞后:
对象时间常数 T=2 s,纯滞后 L=3 s,采样周期 Ts=0.2 s
也就是说,一个控制动作发出去以后,并不会立刻在输出端表现出来。
在这种情况下,如果只盯着当前误差进行控制,就很容易遇到几个问题:
当前输出还没有响应,但新的控制动作已经继续叠加;
控制过于激进时容易产生明显超调和较大的控制峰值;
控制过于保守时,扰动后的恢复速度又可能变慢;
还需要同时考虑未来若干步的跟踪效果,而不是只优化下一时刻。
GPC 的思路正好相反:
当前输出与历史控制量 → 预测未来输出 → 构造未来参考轨迹 → 优化一段未来控制增量 → 只执行第一个控制动作 → 下一采样时刻重新预测
这套程序又在仿真中途人为加入输入扰动,因此除了给定值跟踪,还能够观察:
不同控制加权 λ 下,控制器为了抑制扰动需要付出多大的控制动作。
1. 当前工程真正由哪些程序组成?
整个项目规模不大,主线比较清晰。
文件 | 作用 |
|---|---|
contrast.m | 整个对比实验的主入口,调用三组 GPC 并绘制输出和控制量对比 |
GPC_basic.m | 第一组 GPC 仿真 |
GPC_basic1.m、GPC_basic2.m | 另外两组不同控制加权参数的 GPC 仿真 |
tf2AB.p、diophantine.p、getGij.p、getG.p、rankn.p | 模型离散化、丢番图方程及预测矩阵构造等辅助计算 |
output.emf、control.emf | 工程中保存的输出响应与控制动作对比结果 |
分别运行三个 GPC 控制函数,最后把三组结果放在相同坐标下比较。
工程中的核心辅助算法采用 MATLAB .p 文件封装,因此它们的函数接口和数据流可以从主程序确认,但内部源码无法像 .m 文件一样逐行检查。
2. 当前 GPC 控制的是什么对象?
三个 GPC 函数使用完全相同的被控对象参数:
参数 | 当前值 | 含义 |
|---|---|---|
K | 1 | 对象增益 |
T | 2 s | 一阶惯性时间常数 |
L | 3 s | 纯滞后时间 |
Ts | 0.2 s | 采样周期 |
对应的连续对象可以概括成:
G(s) = K·e^(−L·s) / (T·s + 1)
代入当前参数就是:
G(s) = e^(−3s) / (2s + 1)
在 Ts=0.2 s 的采样周期下,3 s 滞后相当于 15 个采样间隔的量级。
程序并没有直接手工写出离散差分模型,而是调用:
tf2AB(K,[T 1],L,Ts)
得到离散模型的 A、B 多项式以及离散延迟参数。
后面的对象输出按照这些离散参数递推计算。
3. 控制器使用的模型和真实对象一致吗?
当前程序没有设置模型失配。
真实对象使用:K=1,T=2,L=3
控制器内部模型同样使用:Km=1,Tm=2,Lm=3
因此当前实验研究的重点不是:
模型参数估错以后 GPC 是否还能工作
而是:
在模型匹配条件下,不同控制加权以及外部输入扰动会怎样改变控制效果。
这也是阅读结果时需要先明确的一点。
当前工程验证的是:
时滞 + 扰动 + 控制权重变化
而不是模型不确定性实验。
4. GPC 在程序里怎样建立“未来预测”?
GPC 真正区别于普通单步反馈的地方,是它一次考虑未来多个采样时刻。
当前程序设置:预测时域 N=8
也就是控制器每一次更新时,都要考虑未来 8 步的输出变化。
按照 Ts=0.2 s 计算,对应未来约:8 × 0.2 = 1.6 s的预测区间。
程序首先调用:diophantine(m_A,N,m_d)得到后续预测需要的 E、F。
然后通过:getGij(m_B,E)构造 G,再调用:getG(G,Nu)
得到控制计算中实际使用的 Gpk、Gku 等矩阵。
从主函数的数据关系看,预测量最终由三部分共同决定:
当前及历史输出 + 已经发生的历史控制增量 + 未来准备施加的控制增量
所以 GPC 并不是简单问:“现在差了多少?”
而是在问:“按照当前状态继续发展,再施加这一串控制动作,未来几个采样点会变成什么样?”
这正是预测控制处理时滞对象的核心价值。
5. 当前程序真正求解的控制律是什么?
当前控制时域设置为:Nu=6
因此控制器每一步会计算未来 6 个控制增量,但实际只使用其中第一个。
源码中的核心计算为:
ΔU = (GkuᵀGku + λI)⁻¹Gkuᵀ(Yr − Gpk·ΔUk − F·Yk)
这里可以把它理解成两个目标之间的平衡。
第一部分希望:预测输出尽量接近未来参考轨迹 Yr
第二部分通过:λI抑制控制增量过大。
计算出未来控制序列后,程序执行:
Δu(k) = ΔU 的第一个元素
再更新:
u(k) = u(k−1) + Δu(k)
剩下的未来控制动作并不会直接一次性全部发送出去。
下一采样时刻程序会重新获取输出,再进行一次新的预测和优化。
因此整个过程属于典型的:
滚动预测 → 滚动优化 → 只执行第一步 → 再滚动
6. 为什么给定值不是直接从 0 瞬间跳到 1?
程序首先建立:w=ones(W_length,1)
所以最终目标值是:w=1
但 GPC 实际使用的未来参考轨迹并不是直接把这个阶跃值原样送进去,而是进行了滤波:
r=filter((1-alpha),[1 -alpha],w)
当前:α=0.1
对于这里的单位阶跃输入,它可以理解为让参考轨迹逐步靠近 1,而不是在初始时刻完全突变。
这样处理的作用很直观:
阶跃给定 → 平滑参考轨迹 → GPC 跟踪平滑后的未来目标
参考轨迹越平缓,控制器就越没有必要在开始阶段给出特别剧烈的动作。
不过当前 α 很小,因此参考轨迹本身仍然上升得比较快。
7. 程序怎样测试 GPC 的抗扰动能力?
当前仿真不是只做一次没有干扰的跟踪实验。
程序初始化:dist = 0
然后在:k > tend/2
以后改成:dist = -0.2
当前:tend=250、Ts=0.2 s
总仿真时间约为:250 × 0.2 = 50 s
因此扰动大约从仿真中点,也就是:25 s 左右开始作用。
这个 −0.2 扰动直接进入对象输入计算项。
所以完整实验可以分成两个阶段:
前半段:单位给定值跟踪
后半段:保持给定值不变,同时加入 −0.2 输入扰动
如果控制器能够发挥作用,那么扰动出现以后输出会先发生偏离,然后通过新的控制动作重新被拉回给定值附近。
这正是工程中 output.emf 和 control.emf 所展示的主要现象。
8. 为什么控制加权 λ 是这个项目最关键的比较参数?
λ 直接出现在:
GkuᵀGku + λI
这一项中。
它控制的是:控制器愿意用多大的控制动作,去换取更快的预测误差下降。
当 λ 较小时,控制增量受到的惩罚较弱。
控制器更愿意:
快速增加控制量 → 尽快纠正预测误差
通常表现为控制动作更积极,同时也更容易出现较大的控制峰值和更明显的瞬态变化。
当 λ 增大时,对控制变化的惩罚增强。
控制器会更倾向于:
减少控制增量 → 用更温和的动作完成跟踪
因此 λ 并不是单纯的“越大越好”或“越小越好”。
真正需要权衡的是:
跟踪速度 ↔ 控制动作幅度
对于真实执行器,这个权衡尤其重要,因为控制信号还可能受到:
执行器幅值限制;控制变化率限制;能耗;阀门或电机动态能力;等实际条件约束。
当前程序没有显式加入这些饱和约束,但 λ 可以直观展示“更激进”和“更平缓”的控制差异。
9. 当前保存结果能够说明什么?
工程自带的 output.emf 显示,三组 GPC 输出都会从初始状态向单位给定值靠近。
开始阶段存在不同程度的瞬态超调和振荡,随后都稳定在:y≈1附近。
到约 25 s 加入负输入扰动以后,输出会明显向下偏离给定值。
随后控制器重新增加控制作用,输出再次返回 1 附近,并伴随一段新的瞬态过程。
对应的 control.emf 可以看到:
启动阶段和扰动出现以后,控制量都发生了明显调整。
其中保存结果所标注的较小 λ 对应更大的初始控制动作,而随着控制惩罚增强,控制动作整体趋于平缓。
所以这两张结果实际上是在同时观察两个维度:
输出曲线:跟踪得怎么样
控制曲线:为了得到这种跟踪效果,付出了多大的控制动作
这比只看输出是否最终到达给定值更有意义。
当前工程没有进一步自动计算超调量、调节时间、IAE、ISE 或控制能量等定量指标,因此现有比较主要是基于响应曲线和控制曲线完成。
10. 为什么复现实验时必须先核对 λ?
这一点对当前工程非常重要。
contrast.m 中的图例以及工程保存的两张 EMF 结果标注的是:
λ=0.1、λ=0.5、λ=1.0
但当前压缩包中的三个实际控制函数分别写成:
函数 | 当前源码中的 λ |
|---|---|
GPC_basic.m | 0.1 |
GPC_basic1.m | 2 |
GPC_basic2.m | 3 |
因此:
当前源码参数与 contrast.m 图例、保存的 EMF 图中参数标注并不一致。
这意味着不能把工程保存图直接当成“当前 0.1、2、3 源码重新运行后的精确结果”。
如果按照当前源码直接重新运行,三组实际比较值应该理解成:0.1、2、3
相应地,应把 contrast.m 图例同步改成这三个数值。
如果希望按照现有 EMF 图中的标注重新做:0.1、0.5、1.0
对比,则应先把 GPC_basic1.m、GPC_basic2.m 中的 lambda 分别修改为 0.5 和 1.0,再运行 contrast.m。
还有一个容易忽略的参数:deta = 1
三个 GPC 文件都定义了它,并注释为“误差加权矩阵”,但当前实际控制律计算 dU 时并没有使用 deta。
因此按现有代码:单独修改 deta 不会改变控制结果。
如果后续实验希望真正比较不同误差加权,就需要先把该权重正式引入目标函数及对应矩阵控制律,而不是只修改这一行数值。
11. 哪些参数最值得修改?
当前程序里真正适合做参数实验的,主要是下面几项。
参数 | 当前值 | 为什么值得改 | 调整后的主要影响 |
|---|---|---|---|
lambda | 0.1 / 2 / 3 | 直接控制未来控制增量的惩罚强度 | 小值通常更激进,大值通常更平缓;做对比时应同步修改图例 |
N | 8 | 决定一次向未来看多少步 | 增大可考虑更长未来响应,但矩阵规模和预测范围也随之增加 |
Nu | 6 | 决定一次优化多少个未来控制增量 | 增大控制自由度,同时增加求解规模 |
alpha | 0.1 | 决定参考轨迹平滑程度 | 增大后参考轨迹更缓,通常可减弱初始控制冲击 |
如果进行公平的 λ 对比,最重要的是:
除 λ 外,其余对象参数、N、Nu、α、扰动大小和仿真时间全部保持一致。
deta 虽然出现在参数区,但当前没有进入控制律,因此不能把它作为已经实现的有效调节参数。
12. 它适合用在哪里?
这套程序非常适合用于理解:
预测时域、控制时域、未来控制增量和滚动优化之间是什么关系。
因为整个 GPC 主循环都集中在三个较短的 MATLAB 函数里,数据流比大型控制工程更容易跟踪。
程序已经准备了三套结构完全相同、只需要改变 λ 的控制函数,因此很适合研究:
λ 改变以后,输出瞬态和控制量峰值怎样变化。
如果进一步增加自动指标计算,还可以继续比较超调量、调节时间、控制能量等。
当前对象具有明确的:
一阶惯性 + 3 s 纯滞后
特征,同时又加入中途输入扰动,因此比没有时滞、没有扰动的简单阶跃仿真更能体现预测控制的特点。
如果后续准备研究:
不同 N / Nu、不同 λ、不同参考轨迹、模型失配、扰动强度或约束预测控制
可以把这套程序作为一个较小的基础算例继续扩展。
不过它目前仍属于 MATLAB 离线控制算法仿真程序,并没有现场 I/O、执行器约束、在线通信或实时控制接口,因此不应直接等同于工业实时控制系统。
13. 怎么运行?
将压缩包中的 .m、.p 文件保持在同一 MATLAB 工作目录下。
主入口直接运行:contrast
然后依次调用:
GPC_basic(tend) → GPC_basic1(tend) → GPC_basic2(tend)
最后绘制输出跟踪曲线和控制动作曲线。
正式做参数对比前,建议先处理当前最关键的复现问题:
统一 λ 的实际数值与图例。
按当前源码运行时,实际参数为:0.1 / 2 / 3
如果需要按照工程保存图的标注比较:0.1 / 0.5 / 1.0
则先修改 GPC_basic1.m 和 GPC_basic2.m。
如果只想观察一组控制效果,也可以单独调用:
GPC_basic(tend)
其中 tend 是仿真采样步数。
更换对象时,需要同步修改三个 GPC 文件中的:K、T、L
以及对应模型参数:Km、Tm、Lm
核心模型转换、丢番图方程和预测矩阵构造依赖工程自带的 .p 文件,因此运行时不能只复 制三个 .m 主函数而遗漏这些辅助文件。
由于这些核心辅助函数是 P-code,当前资料无法逐行确认其内部是否还调用特定 MATLAB Toolbox;如果在新 MATLAB 环境中出现 .p 文件兼容或依赖错误,应以实际 MATLAB 报错为准进行环境匹配。
14. 一句话看懂这个项目
这是一个针对一阶纯滞后对象的 广义预测控制仿真程序:对象参数为 K=1、T=2 s、L=3 s,采样周期 0.2 s,控制器以 N=8 的预测时域和 Nu=6 的控制时域建立未来输出预测,通过 ΔU=(GkuᵀGku+λI)⁻¹Gkuᵀ(Yr−Gpk·ΔUk−F·Yk) 计算未来控制增量,每次只执行第一步并滚动更新;仿真总计 250 步,在约 25 s 后加入 −0.2 输入扰动,用输出响应和控制动作观察 GPC 的跟踪及抗扰表现,尤其适合教学、课程设计和 λ 参数敏感性实验。需要注意,当前三个源码实际使用 λ=0.1/2/3,而contrast.m图例及保存的 EMF 结果标注为 0.1/0.5/1.0,同时源码定义的deta=1尚未进入实际控制律,因此正式复现实验前应先统一参数与图例。