ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

水箱液位级联控制:从PID失稳到Matlab仿真的完整解决方案

水箱液位级联控制:从PID失稳到Matlab仿真的完整解决方案 上个月帮一位做水处理平台的朋友看他们实验室的小型水箱装置液位一直控不好。进水压力稍微波动一下液位就开始上下晃PID 参数调了一下午也没解决。我第一反应是参数问题后来仔细一推才发现问题出在控制回路的结构上——对液位这种大惯性、带积分特性的对象光靠一个主回路的 PID反应永远慢半拍。后来我把系统改成级联控制用 Matlab 把动态模型和仿真代码完整搭起来效果立竿见影。这篇就把整套思路和代码完整分享一下适合正在做过程控制课程设计、毕业设计或者刚接触级联控制的工程师。看了你会理解水箱液位为什么难控也能拿到一套可以直接跑的 Matlab 仿真代码甚至可以照着改成你自己的模型参数。1. 从一次失败的 PID 调参说起单回路为什么压不住液位先说清楚一个问题单回路 PID 不是不能用而是面对“扰动发生在执行机构附近”的场景结构上就吃亏。1.1 液位对象的“迟钝”和“漂移”来自哪里水箱液位对象有两个很扎心的特点第一容量大。一个 0.5 平方米截面积的水箱进水和出水流量只要差一点液位变化非常缓慢。这意味着主回路 PID 看到的“误差变化率”很小控制器要花很长时间才能反应过来。第二本质是积分对象。主水箱的液位是进出流量之差的积分结果。即使进水流量出现一个阶跃扰动液位也会持续累积偏差而不是自动回到设定值。积分对象对扰动的“容忍度”很低必须靠控制器主动动作才能拉回来。这两个特点叠加在一起产生了一个经典困境扰动从执行机构附近进入系统后主变量液位要等很久才能感知到控制器再动作又需要时间等液位真正被拉回来动态偏差早就超标了。1.2 单回路在流量扰动下的实时表现你可以想象这样一个场景调节阀开度不变但阀前压力突然升高导致实际进水量突然增大。单回路系统里控制器唯一能感知的信息是主水箱液位。而液位是个大惯性积分环节在扰动发生后很长一段时间内液位才缓慢上升偏差才逐渐变大。这时候控制器才开始关小阀门但已经晚了。液位会经历一个明显的上升过程等到控制器把阀门关到位液位已经在高位徘徊了很久。如果扰动是反复波动的液位也会跟着反复振荡系统永远处于“追着扰动跑”的状态。这就像洗澡时热水管道压力不稳。你只能靠皮肤感受水温去拧热水阀等皮肤接到信号再动手已经慢了一拍。水温忽冷忽热你怎么调都难受。1.3 单回路与级联控制的本质差别级联控制的核心思想是给主回路配一个“侦察兵”——副回路。副回路负责监测并快速抑制靠近执行机构的扰动主回路只负责慢悠悠地管好液位。这样扰动在影响主变量之前就已经被副回路消化掉一大部分。对比维度单回路控制级联控制扰动感知位置主变量液位副变量副水箱液位/流量扰动到主变量的路径直接冲击主变量先变化扰动先影响副变量副回路先动作控制器响应速度慢受主对象大惯性限制快副回路只面对小惯性对象主变量动态偏差大明显减小整定难度参数一调就影响全局先内后外思路清晰我把系统改成两个水箱串联的结构调节阀后面接一个副水箱副水箱再向主水箱供水。副水箱液位作为副变量由快速副回路控制主水箱液位作为主变量由慢速主回路输出副水箱的设定值。这样扰动在副水箱里就被拦截了主水箱液位基本不用大动作。2. 先把动态模型建出来从物料平衡到传递函数做控制仿真最忌讳拿着别人的代码瞎改参数。你得知道模型每一步从哪来、每个参数代表什么物理量。下面我把建模过程完整走一遍。2.1 系统结构和物料平衡方程系统组成调节阀 → 副水箱 → 主水箱 → 用户用水。副水箱的物料平衡[ A_2 \frac{dh_2}{dt} q_{in} - q_{12} ]其中 (A_2) 是副水箱截面积(h_2) 是副水箱液位(q_{in}) 是调节阀进入副水箱的流量(q_{12}) 是从副水箱流向主水箱的流量。主水箱的物料平衡[ A_1 \frac{dh_1}{dt} q_{12} - q_d ](A_1) 是主水箱截面积(h_1) 是主水箱液位(q_d) 是用户用水量。水流从副水箱到主水箱可以近似为孔口出流流量与液位的平方根成正比[ q_{12} C_{12} \sqrt{h_2} ]调节阀的流量特性简化为线性关系[ q_{in} K_v \cdot u ](u) 是阀门开度%(K_v) 是阀门增益。这是最常见的简化方式实际阀门会有死区和非线性后文我会专门说明。2.2 在工作点附近做小偏差线性化直接拿上面的非线性方程做频域分析和传函推导比较麻烦工程上通常在工作点附近做小偏差线性化。选择稳态工作点副水箱液位 (h_{2,0} 0.6) m主水箱液位 (h_{1,0} 1.0) m稳态流量 (q_{12,0} q_{d,0} 0.05) m³/min阀门开度 (u_0 50)%把孔口出流公式在 (h_{2,0}) 处做一阶泰勒展开[ q_{12} \approx q_{12,0} \frac{C_{12}}{2\sqrt{h_{2,0}}} (h_2 - h_{2,0}) ]令 (k_{q2} \frac{C_{12}}{2\sqrt{h_{2,0}}})这个系数代表副水箱液位变化对流出流量的影响程度。代入具体数值[ k_{q2} \frac{0.06455}{2 \times \sqrt{0.6}} \approx 0.0417 \text{ m}^2/\text{min} ]线性化后的增量方程[ A_2 \frac{d\Delta h_2}{dt} K_v \Delta u \Delta d - k_{q2} \Delta h_2 ][ A_1 \frac{d\Delta h_1}{dt} k_{q2} \Delta h_2 - \Delta q_d ]2.3 传递函数与状态空间形式对增量方程做拉普拉斯变换得到副水箱对象的传递函数[ G_2(s) \frac{H_2(s)}{U(s)} \frac{K_v / k_{q2}}{T_2 s 1} ]其中 (T_2 A_2 / k_{q2})。代入参数[ G_2(s) \frac{0.024}{1.92s 1} ]副对象是一个典型的一阶惯性环节时间常数不到 2 分钟相对主回路快得多。主水箱对象[ G_1(s) \frac{H_1(s)}{H_2(s)} \frac{k_{q2}}{A_1 s} \frac{0.0834}{s} ]主对象是纯积分特性这也是液位控制最需要注意的地方。系统参数整理如下参数数值物理含义(A_1)0.5 m²主水箱截面积(A_2)0.08 m²副水箱截面积(C_{12})0.06455孔口流量系数(K_v)0.001 m³/(min·%)调节阀增益(h_{1,0})1.0 m主水箱稳态液位(h_{2,0})0.6 m副水箱稳态液位(u_0)50%稳态阀门开度状态空间形式更直观我后面给的 Matlab 代码就是基于这个形式写的[ \begin{cases} \dot{h}1 \frac{C{12} \sqrt{h_2} - q_d}{A_1} \[6pt] \dot{h}2 \frac{K_v u d - C{12} \sqrt{h_2}}{A_2} \end{cases} ]从模型能看到两个关键点副回路面对的是小惯性对象可以做得很快主回路面对的是积分对象必须靠控制器稳定住。3. 级联控制系统设计内环快、外环稳模型建好了接下来就是控制方案设计。这里有几个原则需要提前想清楚。3.1 主副变量的选取原则级联控制里副变量的选择直接决定抗扰动效果。副变量必须满足两个条件一是能快速反映扰动二是与主变量有明确的物理联系。在我的系统里副变量选副水箱液位 (h_2)。进水流量扰动 (d) 直接作用于副水箱的物料平衡方程副回路能立刻看到扰动引起的变化并反向调节阀门而主水箱液位几乎不受影响。这比直接选进水流量做副变量更实用副水箱液位传感器便宜可靠而且它本身就包含了流量和液位两个信息省去一个流量计。主副回路的带宽关系也要注意。副回路闭环带宽至少要达到主回路的 3 到 5 倍否则两环会互相牵制系统出现“你追我赶”的低频振荡。简单说内环必须比外环反应快得多。3.2 控制器类型怎么定P、PI、PID 的搭配思路液位控制回路里微分项基本是个负担。液位信号本身就带有测量噪声微分会把噪声放大导致阀门频繁动作。回路推荐控制器原因副回路P 或 PI副对象是一阶惯性P 就够用加 I 可消除稳态偏差主回路PI主对象是积分特性必须靠 I 来消除稳态误差D 基本不需要不建议PID 两端都用微分放大噪声内环和外环参数互相纠缠整定困难副回路用 P 控制就够了。因为副回路的任务是“快速消除扰动”允许副水箱液位在一定范围内变化。真正要严格控制的只有主水箱液位那是主回路 PI 的职责。3.3 主副回路的信号牵制与单位换算级联控制里最容易搞乱的就是信号连接。主控制器的输出不是阀门开度而是副控制器的设定值。也就是说主控制器输出的是“副水箱液位应该保持在多少米”副控制器输出的是“阀门开度应该是百分之几”。单位换算一定要理清楚主控制器输入主水箱液位偏差m主控制器输出副水箱液位设定值m副控制器输入副水箱液位偏差m副控制器输出阀门开度%不少人第一次搭级联控制直接把主控制器输出接到阀门上那其实还是单回路只是多绕了一圈没有发挥级联的作用。还要注意副控制器输出的限幅。阀门开度只能在 0 到 100% 之间如果控制器输出超出这个范围积分项会继续累积产生积分饱和。在仿真代码里我就直接做了输出限幅后文会详细说。4. Matlab 代码搭建用 ode45 把非线性和级联同时仿真很多人做 Matlab 仿真第一反应是 Simulink但我觉得先用 m 脚本把非线性模型和控制器跑通思路更清晰调参也更灵活。我用 ode45 直接对非线性微分方程组做数值积分控制器用代码实现这样能同时验证模型和控制逻辑不依赖 Control System Toolbox。4.1 模型和控制器代码建议把脚本和局部函数放在同一个.m文件里需要 MATLAB R2016b 以上版本支持脚本局部函数。%% 水箱液位级联控制——非线性动态系统数值仿真 % 系统模型 % 副水箱A2*dh2/dt Kv*u d - C12*sqrt(h2) % 主水箱A1*dh1/dt C12*sqrt(h2) - Qd % 控制器 % 副回路P控制u u_ss Kc2*(SP2 - h2) % 主回路PI控制SP2 h2_0 Kc1*(SP1 - h1) (Kc1/Ti1)*integral(SP1-h1) clear; clc; %% 系统参数 A1 0.5; % 主水箱截面积m2 A2 0.08; % 副水箱截面积m2 C12 0.06455; % 孔口流量系数m^2.5/min Kv 0.001; % 调节阀增益m3/(min*%) Qd0 0.05; % 用户用水量m3/min h1_0 1.0; % 主水箱初始液位m h2_0 0.6; % 副水箱初始液位m SP1 1.0; % 主水箱液位设定值m %% 级联控制器参数 Kc2 200; % 副控制器比例增益%/m Kc1 2; % 主控制器比例增益m/m Ti1 50; % 主控制器积分时间min %% 扰动参数第200分钟起进水量增加0.01 m3/min tStep 200; dAmp 0.01; %% 仿真 tspan [0 500]; [tC, xC] ode45((t,x) tankCascadeODE(t, x, A1, A2, C12, Kv, ... SP1, Kc2, Kc1, Ti1, Qd0, tStep, dAmp), ... tspan, [h1_0; h2_0; 0]); h1C xC(:,1); h2C xC(:,2); % 对照组单回路PI控制器直接控阀门 Kcs 30; % 单回路比例增益%/m Tis 50; % 单回路积分时间min [tS, xS] ode45((t,x) tankSingleODE(t, x, A1, A2, C12, Kv, ... SP1, Kcs, Tis, Qd0, tStep, dAmp), ... tspan, [h1_0; h2_0; 0]); h1S xS(:,1); %% 绘图 figure(Color, w); plot(tC, h1C, b-, LineWidth, 1.5); hold on; plot(tS, h1S, r--, LineWidth, 1.5); xlabel(时间 (min)); ylabel(主水箱液位 (m)); legend(级联控制, 单回路控制); grid on;局部函数放在脚本末尾function dx tankCascadeODE(t, x, A1, A2, C12, Kv, SP1, ... Kc2, Kc1, Ti1, Qd, tStep, dAmp) % 状态x(1)主水箱液位x(2)副水箱液位x(3)积分项 h1 x(1); h2 x(2); ei x(3); % 进水流量扰动 d dAmp * (t tStep); % 主控制器PI输出限幅副水箱液位设定值 SP2 h2_0 Kc1 * (SP1 - h1) (Kc1 / Ti1) * ei; SP2 min(max(SP2, 0), 2); % 防止副设定值超物理范围 % 副控制器P输出限幅阀门开度 u u_ss Kc2 * (SP2 - h2); u min(max(u, 0), 100); % 阀门开度0~100% q12 C12 * sqrt(h2); dx zeros(3,1); dx(1) (q12 - Qd) / A1; dx(2) (Kv * u d - q12) / A2; dx(3) SP1 - h1; % 主控制器积分项 end function dx tankSingleODE(t, x, A1, A2, C12, Kv, SP1, ... Kcs, Tis, Qd, tStep, dAmp) h1 x(1); h2 x(2); ei x(3); d dAmp * (t tStep); % 单回路控制器直接输出阀门开度 u u_ss Kcs * (SP1 - h1) (Kcs / Tis) * ei; u min(max(u, 0), 100); q12 C12 * sqrt(h2); dx zeros(3,1); dx(1) (q12 - Qd) / A1; dx(2) (Kv * u d - q12) / A2; dx(3) SP1 - h1; end4.2 运行结果怎么解读运行代码后你会看到两条液位曲线。以第 200 分钟的扰动为界前段是设定值跟踪后段是抗扰动性能对比。扰动发生前两条曲线都能把液位稳定在 1.0 米附近。扰动发生那一刻级联控制的副回路会立刻检测到副水箱液位变化将阀门开度回调主水箱液位几乎不抬头单回路控制则要等主水箱液位开始上升控制器才慢慢关小阀门液位会出现一个明显的高峰。用我这组参数跑下来扰动阶段主水箱液位的最大动态偏差级联控制大约是单回路的五分之一到三分之一。具体数值可能因步长和 ODE 求解器设置略有差异但趋势非常明显。调参时如果发现级联控制振荡先别改主回路检查副回路是不是太猛。副回路增益 (K_{c2}) 从 100 往 300 慢慢加观察副水箱液位响应是否干脆主回路 (K_{c1}) 从 1 往 3 加同时调整 (T_{i1})。4.3 一个容易被忽略的细节实体防积分饱和代码里我给阀门开度和副液位设定值都加了限幅这不是随便加的。ode45 求解过程中控制器输出可能暂时超出物理范围如果不加限幅积分项会不断累积导致控制器输出跑到几百甚至上千但实际阀门早就开到头了。等误差反向积分项要花很长时间才能“消化”掉系统表现为严重的超调和振荡。这就是积分饱和现象仿真的意义就在于提前暴露这类问题。到实际 PLC 或者 DCS 上做控制时也要打开 PID 模块的抗积分饱和选项原理是一样的。5. Simulink 建模从线性传函到非线性模型的一次验证m 脚本适合快速验证思路但做实验对比的时候Simulink 的图形化连线更直观。而且级联控制的内外环结构在 Simulink 里一目了然。5.1 Simulink 模型布局按这个顺序建模块Step 模块主水箱液位设定值初始 1.0阶跃到 1.1Sum 模块计算主液位偏差PID Controller 模块主控制器选 PI输出限幅 0~2Sum 模块计算副液位偏差PID Controller 模块副控制器选 P输出限幅 0~100Transfer Fcn 模块副对象参数[0.024]/[1.92 1]Integrator 模块主对象积分增益用 Gain 模块设为0.0834输入是副水箱液位副水箱液位信号引出反馈到副控制器主水箱液位信号引出反馈到主控制器两个 PID 模块的输出端都要加 Saturation 限幅这和 m 脚本里的限幅是一个道理。5.2 用非线性模块替代传递函数验证线性化误差前面建模时做了线性化我建议在 Simulink 里再搭一个完全非线性的版本验证线性化误差是否在可接受范围内。非线性部分只需要两个改动用 Fen 模块C12*sqrt(u)替代主对象里的线性增益0.0834系统方程改成直接积分的形式1/A1、1/A2乘以物料平衡式子搭非线性模型时最容易踩的坑是代数环。如果sqrt(h2)直接和某个代数变量互相依赖Simulink 会报 algebraic loop 错误。解决办法是在反馈路径上放一个 Memory 模块或者一个极点远离原点的小惯性环节把代数依赖切断。线性模型和非线性模型跑出来的阶跃响应曲线对比正常情况下偏差不会太大。如果偏差明显说明工作点选得不好或者扰动幅度太大线性化已经不适用了。这本身就是一个很好的验证思路。5.3 对比实验设计思路如果你想做单回路和级联控制的对比Simulink 里最简单的方法是把副控制器和主控制器的连接方式切换一下。单回路模式主控制器输出直接接到副对象输入副控制器模块从反馈环上拿掉。这个开关可以用 Manual Switch 模块实现。扰动对比更简单在副对象输入端叠加一个阶跃扰动信号分别记录两条液位曲线。你会看到级联控制的动态偏差明显小很多。用 Simulink 还有一个好处是可以直接在 Scope 里观察副水箱液位的变化轨迹。级联控制下扰动发生时副水箱液位会先跳一下然后迅速被拉回设定值附近——这个“先跳一下再回来”的动作就是副回路在工作。6. 参数整定顺序先把内环整利索再谈外环整定级联控制最容易犯的错误是同时对主副回路调参。一旦曲线不好看根本分不清是哪个回路引起的。正确顺序是先内后外一个回路一个回路地整。6.1 第一步整定副控制器断开主回路给副控制器一个手动设定值直接对副回路做阶跃实验。副回路面对的是一个一阶惯性对象用 P 控制就够了。增益从小往大调观察副水箱液位的阶跃响应增益太小响应太慢扰动抑制能力不足增益太大副水箱液位出现超调和振荡阀位波动剧烈我推荐副回路整定目标是无超调或轻微超调。因为副回路是“干活”的回路动作必须干脆但也不能把自己整振了。用我给的参数就是 (K_{c2}200) 起步一点一点加。6.2 第二步整定主控制器副回路整定好之后接上主回路投入 PI 控制器。主控制器的整定思路和单回路 PI 差不多只是被控对象变成了“副回路闭环 主水箱积分”的串联系统。(K_{c1}) 从 0 往上加观察主水箱液位阶跃响应出现等幅振荡时记下临界增益然后取临界增益的一半左右。积分时间 (T_{i1}) 从大往小慢慢减。积分时间太大稳态误差消除得太慢太小系统会缓慢“爬坡”振荡。液位对象的惯性大积分时间一般比温度、压力回路长不少用分钟量级很正常。6.3 用 Bode 图交叉验证稳定性光看时域响应还不够我习惯用线性化模型算一遍稳定裕度。下面这段代码用 Control System Toolbox 做交叉验证%% 在线性化工作点检查稳定裕度 G2 tf(0.024, [1.92 1]); % 副对象 G1 tf(0.0834, [1 0]); % 主对象积分环节 C2 200; % 副控制器P Gc2 feedback(C2 * G2, 1); % 副回路闭环 C1 pid(2, 1/50); % 主控制器PI L C1 * Gc2 * G1; % 主回路开环传函 [Gm, Pm, Wcg, Wcp] margin(L); fprintf(增益裕度: %.2f dB\n, 20*log10(Gm)); fprintf(相位裕度: %.2f deg\n, Pm);工程上相位裕度在 30 到 60 度之间比较合适。如果相位裕度太小说明系统接近振荡边界要适当减小 (K_{c1}) 或增大 (T_{i1})。margin 函数返回的频率 (W_{cg}) 和 (W_{cp}) 还有个用处检查主副回路带宽是否拉开。副回路带宽必须明显高于主回路截止频率否则整定顺序就得重新来过。7. 实测中反复踩过的坑和我的处理经验最后这部分是我在调这个模型时真实遇到过的问题。有些问题理论书上很少提但实际卡了你半天。7.1 副回路增益给太猛主水箱慢慢“荡”起来有一次我把 (K_{c2}) 从 200 直接加到 500副水箱液位控制得非常快几乎没超调。但接上主回路以后发现主水箱液位出现一种低频振荡周期很长看起来像主回路没调好。折腾了很久才发现副回路整定过猛等效闭环后反而把高频噪声传给了主对象导致主回路的积分环节被激励出现“慢振荡”。这不是主回路参数问题是内环太激进。处理方法是回调副回路增益让副回路留一点余量。副回路的“快”是有边界的不是越快越好。7.2 微分项在液位回路里就像一个噪声放大器我一开始也试过主回路用 PID想着微分能加快响应还能提前动作。结果液位传感器的测量噪声被微分项放大了两三倍阀门开度跟着高频抖动阀杆动作频繁执行机构磨损加剧。液位对象本身是积分特性微分作用带来的“提前量”和积分作用的“消除偏差”在频域上是重叠的作用很有限。到工程现场液位回路基本没人用 D 项。7.3 阀门死区会让仿真和实物完全对不上理论仿真里阀门开度多少流量就多少。实际工业阀门有死区尤其老式调节阀小信号输入根本不动。我在调另一套系统时就遇到过仿真曲线很漂亮到了现场阀门纹丝不动。处理办法有两个层面仿真阶段在阀门模型里加一个 2% 左右的死区非线性看看系统鲁棒性实际项目给控制器加输出死区补偿或者换线性度更好的阀门我在 Simulink 里加死区的方法是在 PID 输出后串联 Dead Zone 模块死区宽度设成 ±1 或 ±2。跑完之后再看曲线多数调好的仿真参数都能扛住但如果原本就在振荡边界死区一加就原形毕露。7.4 从仿真到实物的最后一个障碍采样周期m 脚本和 Simulink 连续模型仿真里控制器是连续计算的。但实际 PLC 或 DCS 的 PID 是离散执行的采样周期设置不合理级联控制的优势会被大幅削弱。副回路采样周期一定要比主回路快 5 到 10 倍。比如副回路采样 0.1 秒主回路采样 1 秒这样才能保证内环快速响应外环的设定值变化。如果两个回路用同一个慢采样周期内环相当于退化成单回路级联就失去了意义。我在仿真后期特意把模型改为离散 PID 跑了一遍确认只要采样周期拉开差距离散控制的效果和连续仿真基本一致。一点个人体会做水箱液位级联控制这个项目我最大的感受是控制方案的作用顺序应该是“结构优先参数其次”。单回路 PID 调不出效果时不要急着堆参数先回头看控制回路结构是不是不合理。级联控制的代码本身不难写难的是理解两个回路各自的角色——副回路管速度主回路管精度。真到了调试现场我的习惯是先跑设定值阶跃确认系统稳定再加扰动看抗扰能力最后把两种扰动同时加上做压力测试。每一步一步来数据自然会告诉你问题出在哪。最后分享一个土办法整定级联控制时如果曲线乱得没法看先把主控制器的积分时间设成最大值只留 P 作用把副回路调稳再逐步恢复积分。这条路径我用了很多次每次都能把系统从“振荡边缘”拉回到稳定区域。
返回列表