简介:面向测控技术与仪器专业本科学生及自动化初级研究者,这份自动控制原理MATLAB仿真与系统校正实验任务书,以两个核心实验为主线:控制系统性能分析仿真和自动控制系统校正仿真。内容覆盖系统建模、时域响应、频域分析,以及超前校正、滞后校正、PID校正等常用策略,每个任务均要求结合具体传递函数编写程序、搭建Simulink模型并完成结果分析。资源共1个PDF文件,压缩包整体418KB,文档结构完整,包含实验目的、步骤、任务及报告要求,可直接作为课堂辅助材料或个人项目实践指南。已有166人学习,尤其适合需要通过动手仿真加深理论理解、提升MATLAB/Simulink实操能力的读者。完成全部实验后,读者不仅能掌握控制系统分析和校正的基本方法,还能体会理论推导与仿真结果之间的对应关系,训练独立解决工程问题的能力。
1. 为什么自动控制原理要在MATLAB与Simulink里先仿真再校正
用MATLAB的step()一条命令就能画出一条标准的单位阶跃响应,但很多人在纸上画根轨迹时很清楚,到了课程设计要用控制系统校正把超调量压到10%反而开始乱试参数。自动控制原理的核心是改变开环频率特性,而校正器(超前、滞后、PID)的每个参数都会同时影响增益裕度、相角裕度和稳态误差,靠手算只能得到一个可用起点。MATLAB与Simulink的价值在于把被控对象模型、开环bode图、闭环阶跃响应放到同一个工作区里,让“建模—仿真—校正—再仿真”变成一个短循环。下面流程以常见的三阶积分型被控对象为例,从MATLAB的传递函数和频域分析入手,再接到Simulink模型,最后完成控制系统校正与参数整定。适合正在做自动控制原理课程设计、准备实验报告或从理论过渡到实际调试的工程师。
2. 在MATLAB里搭出被控对象并测出未校正特性
2.1 用传递函数把被控对象写进MATLAB
自动控制原理教材里,被控对象最常见的是线性时不变模型,传递函数是分析的基本起点。常见做法是先在MATLAB里定义拉普拉斯变量s,再用tf生成对象模型。我习惯写成:
clear; close all; clc; s = tf('s'); % 被控对象:I型三阶,有积分环节,可用作电机或热工对象的简化模型 G = 1 / (s * (s + 1) * (s + 5));这里s = tf('s')的作用是让后续表达式自动按有理传递函数化简。G的分母展开后对应系数为[1 6 5 0],分子系数是[1],其中0代表积分环节的零次项系数,说明系统型别为I型。这个系数组合原封不动地出现在Simulink的Transfer Fcn块参数里,所以先在MATLAB里跑一遍有两个好处:一是验证对象是否稳定,二是把系数固定下来,避免到Simulink填参数时把常数项顺序写反。对于参数化的工程对象,也可以从电机或温度系统中提取电阻、电感、转动惯量,再组装成tf对象,这时用zpk保存零极点更方便。如果后续要处理延迟环节,一般用pade近似;初学校正时先不引入延迟,到后续章节再做扩展。得到G之后,单位负反馈闭环传递函数就是feedback(G,1),这一步不要省略,因为阶跃响应和稳定性分析都需要它。
2.2 阶跃响应与bode图:确定系统现在缺什么
建立好G之后,先用step命令观察闭环阶跃响应,再用bode和margin观察开环频率特性。这两步对应自动控制原理里时域与频域两个维度,校正前必须都看。
% 单位负反馈闭环阶跃响应 T_closed = feedback(G, 1); figure; step(T_closed); % matlab 阶跃响应 grid on; % 提取时域指标 info = stepinfo(T_closed); fprintf('RiseTime=%.3f s\nSettlingTime=%.3f s\nOvershoot=%.2f%%\n', ... info.RiseTime, info.SettlingTime, info.Overshoot); % 开环频率特性 figure; bode(G); grid on; figure; margin(G); [Gm, Pm, Wcg, Wcp] = margin(G);step函数默认仿真到系统接近稳态,但遇到慢系统时可能提前结束,此时应手动指定时间向量t=0:0.01:30,再调用step(T_closed,t)。stepinfo返回的RiseTime是从10%到90%的时间,Overshoot是百分比,SettlingTime按2%误差带计算,这几个指标正是自动控制原理里最常要求的。bode与margin都基于开环传函,区别是bode只绘制幅频相频曲线,margin额外标注幅值裕度与相角裕度并返回数值。[Gm,Pm,Wcg,Wcp]的返回值中,Gm是线性比值,输出相角裕度时注意单位。
这一步最重要的是把“目标”带进来。比如想达到Mp≤10%,Ts≤2s,那么从stepinfo打印结果能立刻判断超调量是否超过目标;想看系统还有多少相位储备,就看Pm是否在45度以上。对当前三阶对象,由于低频有积分,单位阶跃稳态误差为0,但相角裕度往往偏低,这正是校正要解决的问题。
2.3 从响应曲线读稳态误差、超调量和相角裕度
校正不是盲目调增益,而是先确定系统缺的是“型别”还是“相角储备”。这里有一个很实用的对应表:
| 现象 | 缺什么 | 典型校正手段 |
|---|---|---|
| 单位斜坡稳态误差大 | 系统型别不足/开环增益低 | 滞后校正、提高Kp |
| 超调量大、调节时间长 | 相角裕度不足、带宽不合理 | 超前校正、PID微分 |
| 高频振荡或发散 | 增益裕度不足、滞后太大 | 降低开环增益、减少纯滞后 |
| 响应太慢但无超调 | 带宽过低 | 超前校正、增大比例 |
比如当前的G是I型系统,单位阶跃稳态误差为零,但如果输入是单位斜坡,会存在常值速度误差。需要用开环增益或系统型别来消除。超调量和相角裕度之间有经验关系,相角裕度在45度左右时超调量约在20%到30%,想压到10%以下,相角裕度通常要提到55度以上。这些要求都是后续确定校正参数的依据。如果没有先画bode图,直接给PID加大Kp,很可能会让相角裕度继续下降,最终导致震荡,这也是很多仿真发散问题的真正起点。
3. Simulink仿真模型搭建与校正环节的接法
3.1 从传递函数到Simulink框图
现在把MATLAB里的传递函数移植到Simulink。新建一个模型,命名为ctrl_demo,从Simulink Library Browser的Sources库里拖入Step,从Math Operations库里拖入Sum,从Continuous库里拖入Transfer Fcn,从Sinks库里拖入Scope。各块按单位负反馈顺序连接:Step输出接Sum的“+”,Sum的“-”端接从Scope后反馈回来的信号,Sum输出接Transfer Fcn,Transfer Fcn输出接Scope。这样搭出来的模型和理论框图完全对应。
双击Transfer Fcn块,把Numerator coefficients填为[1],Denominator coefficients填为[1 6 5 0]。这里与MATLAB里的系数顺序完全一样,都是按s降幂排列。分母最后一位是0,代表积分环节,填的时候不要漏。Step块保持默认即可,但建议将Step time设为0,Initial value设为0,Final value设为1,这样Scope里看到的就是标准的阶跃响应。运行模型后,Scope里会出现和MATLAB step图一致的曲线。如果曲线方向向下或者根本没有输出,优先检查Sum块是否设置了“+ -”符号。
这个由Step-Sum-Transfer Fcn-Scope组成的骨架,后续所有校正实验都在这条前向通路上加环节。保留这个模型,不要随意修改块名,因为后面的set_param脚本都要引用块路径。
3.2 用PID Controller或传递函数块实现校正
校正环节最直接的接法是在Sum之后、Transfer Fcn之前串入一个PID Controller块。也可以用Continuous库里的Zero-Pole块或Transfer Fcn块表示超前/滞后网络。我建议先用PID Controller,因为参数可以在MATLAB脚本里逐次修改,方便看趋势。
从Continuous库拖入PID Controller,放到Sum和Transfer Fcn之间,连线会自动串接起来。双击PID Controller,将Controller parameters里的P、I、D分别填为变量名Kp、Ki、Kd,而不是具体数字。这样在脚本里set_param时,块参数会读取工作区变量。若直接写数字,后面批量仿真时要反复打开对话框,效率低。要注意,Simulink块路径中的斜杠和块名区分大小写,块名如果叫PID,访问路径就是'ctrl_demo/PID'。
接下来用一段MATLAB脚本驱动仿真:
% 设置PID参数并仿真 Kp = 1.2; Ki = 0.5; Kd = 0.1; set_param('ctrl_demo/PID', 'Kp', num2str(Kp), ... 'Ki', num2str(Ki), ... 'Kd', num2str(Kd)); sim('ctrl_demo');set_param会把数值转成字符串写入Simulink块。这里容易踩的坑是PID Controller块参数名在不同MATLAB版本里可能显示为P、I、D而不是Kp、Ki、Kd,需要先在命令行执行get_param('ctrl_demo/PID','DialogParameters')查看完整参数名。用变量名的好处是批量仿真时循环体内只改Kp、Ki、Kd。如果校正环节是超前/滞后网络,不一定要PID Controller,在Simulink里拖入Transfer Fcn,分子分母系数由4.1节的计算结果写入即可。两者可以同时保留在模型里,用开关切换到不同方案,方便对比。
3.3 仿真参数与MATLAB脚本交互:参数怎么设才不发散
Simulink仿真发散是初学最常遇到的现象,Scope里出现1e10量级的直线,或者曲线直接飞到正负无穷,不一定是PID给得太大。第一步要检查的是求解器步长。模型空白处点击Simulation、Model Configuration Parameters,在Solver面板里选择变步长ode45,并将Max Step Size从auto改为一个明显小于系统最小时常数的值。对这个三阶对象,最大步长取0.01通常够用。如果被控对象包含高增益环或刚性动态,比如电机电气时间常数远小于机械时间常数,就要换成ode15s。
| 参数 | 建议值 | 说明 |
|---|---|---|
| Solver | ode45 | 非刚性连续系统默认求解器 |
| MaxStep | 0.01 | 防止步长过大导致仿真发散 |
| StopTime | 20 | 覆盖完整阶跃响应过程 |
见下面的配置代码:
% 在仿真前配置求解器 set_param('ctrl_demo', 'Solver', 'ode45', ... 'MaxStep', '0.01', ... 'StopTime', '20'); out = sim('ctrl_demo'); plot(out.tout, out.y); grid on;这里out.y来自模型内的To Workspace块。To Workspace块在Sinks库里,输出变量名填y,保存格式选Timeseries,仿真完成后out.tout和out.y自然可用。发散时除了调MaxStep,还要注意模型里是否有代数环。代数环表现为反馈回路中在同一采样步长内产生输入和输出互相依赖,Simulink会给出蓝色虚线提示。解决办法是在环路上加一个很小的滞后或低通滤波,比如加一个高频惯性环节1/(10*s+1),或把Integrator初始条件改为非零。这些做法不会明显改变系统主频率特性,但能打破代数环。
如果模型已经调好,想要连真实硬件在线修改参数,可以把Simulation Mode改为External,配合外部模式在主机上用set_param改PID参数。外部模式要求目标端已经运行从模型生成的代码,适用于快速控制原型。纯课程设计阶段不必用到,但知道这一点对理解Simulink的仿真和硬件部署区别很有帮助。
4. 控制系统校正参数整定方法与仿真验证
4.1 频域法串联超前/滞后校正怎么算
Simulink里的控制器参数不是瞎试出来的,自动控制原理里频域法的套路在MATLAB中可以直接转成脚本。串联超前校正的传递函数写成
C(s) = (1 + αTs) / (1 + Ts), α > 1
它把一个零点放在1/(αT),一个极点放在1/T,极点在左半平面比零点更远,提供正的相角超前。滞后校正写成
C(s) = (1 + Ts) / (1 + αTs), α > 1
零点靠近原点,极点更小,主要作用是减小高频增益、保留低频增益。
手动计算时,先由margin(G)读出未校正系统在期望剪切频率处的相角裕度,再确定期望裕度。比如希望wc=5 rad/s,期望相角裕度50度,当前裕度只有18度,校正器需额外提供32度的超前相角,再补偿5度作为安全余量。计算公式是:
wc = 5; % 期望剪切频率 pm_desired = 50; % 期望相角裕度 pm_existing = 18; % 当前在wc处的相角裕度,由margin得到 phi_m = pm_desired - pm_existing + 5; % 需补偿的超前相角 alpha = (1 + sind(phi_m)) / (1 - sind(phi_m)); T = 1 / (wc * sqrt(alpha)); C = (1 + alpha*T*s) / (1 + T*s); % 验证校正后的开环与相角裕度 L = G * C; [Gm, Pm] = margin(L);sind函数接受角度并换算成弧度,直接使用sin会把phi_m当成弧度处理,这是代码里最容易出错的地方。alpha越大,超前相角越大,但同时会把中频段增益抬高,让剪切频率右移。所以计算后要回到bode图上检查实际相角裕度,如果偏离目标,将phi_m的补偿量从5度改成10度重新算。这套计算可以用sisotool(G)做图形化验证。sisotool允许直接拖动开环根轨迹或零极点,实时看阶跃响应,设计结束后可以直接导出控制器模型。
滞后校正的思路是选择比原剪切频率低很多的零极点对,比如把1/T放到0.1 rad/s,1/(αT)放到0.01 rad/s,这样在目标剪切频率处,滞后网络只提供增益衰减,不产生明显相角拖累。它适合模型已经满足相位要求、但低频增益不够导致稳态误差偏大的场景。
4.2 用MATLAB脚本自动整定PID参数
如果不想手动走一遍频率校正,MATLAB Control System Toolbox的pidtune可以直接整定PID参数。它基于开环传递函数,在指定剪切频率或相角裕度下优化控制器零极点。常见用法是:
C = pidtune(G, 'PID'); % 自动整定PID T_closed = feedback(G*C, 1); step(T_closed); grid on;默认pidtune会在系统可稳定的前提下自动选择带宽。想更贴近课程设计目标,可以指定期望剪切频率,比如pidtune(G,'PID',6)表示让校正后开环穿越频率大约在6 rad/s。返回的C对象是连续时间PID控制器,其Kp、Ki、Kd分别对应C.Kp、C.Ki、C.Kd。在Simulink的PID Controller块中填入这几个变量名即可。
需要注意pidtune生成的控制器经常带有比例微分滤波器系数或二阶形式,Simulink的基础PID Controller块未必能直接接收。解决办法是先读标准参数:
Kp = C.Kp; Ki = C.Ki; Kd = C.Kd;再填入PID块。如果pidtune返回的是PID带一阶滤波器,也就是PIDF,需要把微分滤波器系数合并到PID块的Filter coefficient里,否则带宽差异会导致仿真结果和理论不一致。还有一点,pidtune默认优化的是相角裕度和带宽,不会自动帮你压稳态误差;对I型系统它能解决阶跃误差,但斜坡误差未必为零,这时还要结合滞后校正或提高型别。
4.3 在Simulink里验证校正后系统并对比指标
校正参数拿到手后,需要回Simulink验证。最简单的做法是先在模型里放好To Workspace块,然后在MATLAB循环里改PID参数并仿真,一次性对比多组曲线。
figure; hold on; grid on; legend_str = {}; Kp_list = [0.5 1.2 2.0]; for i = 1:length(Kp_list) Kp = Kp_list(i); set_param('ctrl_demo/PID', 'Kp', num2str(Kp)); out = sim('ctrl_demo', 10); t = out.tout; y = out.y; plot(t, y, 'LineWidth', 1.2); info = stepinfo(y, t); fprintf('Kp=%.2f: Ts=%.3f s, Overshoot=%.2f%%\n', ... Kp, info.SettlingTime, info.Overshoot); legend_str{i} = ['Kp=' num2str(Kp)]; end legend(legend_str);这段脚本的循环里只改了Kp,实际使用时可以同时改Ki、Kd甚至超前校正的alpha和T。stepinfo在输入是向量t和y时按时间序列提取指标,比直接用反馈传函更贴近Simulink真实响应。记录结果时用表格:
| 校正方案 | 超调量 | 调节时间 | 说明 |
|---|---|---|---|
| 未校正 | 高 | 长 | 相角裕度不足 |
| 超前校正 | 明显下降 | 变短 | 若alpha选得过大可能噪声放大 |
| PID | 取决于Kp/Ki/Kd | 可调整 | Ki过大会产生低频振荡 |
对比时不要只看最终值,还要看曲线是否在2%误差带内收敛。如果Kp增大后超调反而上升,说明微分没有跟上;这时优先增大Kd,不要继续加Kp。如果Ki继续增大导致稳态附近出现持续抖动,一般是因为积分饱和或控制器输出被饱和限幅。Simulink中可以在控制器输出串一个Saturation块模拟输出限幅,再观察是否出现积分风轮效应。
5. 收尾时最值得做的验证:把Simulink模型线性化再和理论对照
5.1 用linearize检查Simulink里的传递函数
校正完成后,我一般会做一次“模型校核”:用Simulink Control Design的linearize命令,把Simulink模型里的连续动态线性化出传递函数,再和MATLAB里直接计算的开环L做bode对比。这一步能查出连线错误、增益放反和块参数填错等问题,比盯着Scope更可靠。
io(1) = linio('ctrl_demo/Sum', 1, 'input'); io(2) = linio('ctrl_demo/Transfer Fcn', 1, 'openoutput'); L_sim = linearize('ctrl_demo', io); bode(L_sim, L); legend('Simulink linearized', 'MATLAB L=G*C');linio的第一个参数要写模型内真实块路径,开关'input'和'openoutput'决定在哪个点注入激励、在哪个点测量并断开反馈。运行后如果两条bode曲线完全重合,说明Simulink配置和MATLAB理论模型一致。只要曲线在剪切频率附近有偏差,就要回去检查Transfer Fcn的系数顺序、Sum块反馈极性或PID Controller是否启用了滤波器。
5.2 从仿真过渡到实际应用时的参数移交
如果这套Simulink模型要往下游走,比如做硬件在环或生成控制器代码,校正参数不宜一直写在PID Controller对话框里。常见做法是把Kp、Ki、Kd以及采样时间写进一个MATLAB脚本,模型里只引用变量。这样无论换机器还是换项目,一个脚本就能重建所有配置。导到嵌入式环境前,需要把连续PID改为离散PID,并把采样时间设为实际控制周期。Simulink的PID Controller块可以直接打开“Domain”为Discrete time,再把Sample time改成对应秒数。之后使用Simulink Coder生成C代码,或从模型菜单导出FMU,就能把仿真平台里的控制器交给其他工具链使用。整理模型时,给每个块设置明确的名字和注释,把Scope输出统一换成To Workspace,才方便批量仿真和写报告。仿真技术上的最后一道检查,是看离散化和连续仿真的阶跃响应差异是否仍然在指标范围内,这一步能避免实际部署时频率特性的偏移。
本文还有配套的精品资源,点击获取