简介:这份资源面向控制系统学习者和MATLAB/Simulink入门用户,聚焦如何在MATLAB环境中绘制S平面上的三维传递函数图,帮助理解动态系统的频率响应与稳定性分析。内容围绕传递函数建模、S平面极点零点分布、tf函数用法以及3D曲面可视化展开,适合正在学习自动控制原理或需要直观观察系统频域特性的读者。压缩包共2个文件,包含1个m脚本和1个txt说明,整体约2KB,其中m脚本用于实现传递函数定义、频率范围设置、响应计算与三维图形绘制,txt文件提供许可相关信息。目前已有1819人学习下载,可作为频域分析与系统仿真的轻量参考,帮助读者快速搭建从传递函数到三维可视化的完整思路,并在此基础上调整参数、观察不同系统在S平面上的行为差异。
1. 从一张“画不出来”的传递函数图说起
如果你在 MATLAB 里敲完tf([1],[1 2 1]),命令行能正常吐出1/(s^2+2s+1),但一到画图环节就卡壳——要么bode出来的曲线跟预期对不上,要么想画个带反馈的闭环传递函数却不知道怎么把feedback和series串起来,那你大概率缺的不是 MATLAB 语法,而是一套“从传递函数到图形”的完整落地路径。这份资源围绕的就是这件事:用 MATLAB 和 Simulink 把传递函数从数学表达式变成可看、可调、可验证的图形。它适合正在学自动控制原理、做课程设计、或者需要快速验证控制器结构的工程师和学生。Simulink 基础不扎实的人,正好可以借这个资源把“模型搭建—参数设置—仿真出图”这条链路走通一遍。
2. 传递函数图的三种画法:从tf到bode再到 Simulink
2.1 为什么先讲tf对象而不是直接画图
MATLAB 里画传递函数图,第一步永远是先把传递函数变成tf对象。很多人图省事,直接用bode([1],[1 2 1])这种写法,结果发现频率范围不对、相位卷绕异常,甚至报错说维度不匹配。原因在于bode对裸分子分母向量的解析规则和tf对象不一致,尤其是高阶系统或者带延迟的系统,裸向量写法很容易翻车。
正确做法是先构造tf对象,再交给绘图函数。下面这段代码覆盖了最常见的三种构造方式:
% 方式一:分子分母系数向量 num = [1]; den = [1 2 1]; % s^2 + 2s + 1 sys1 = tf(num, den); % 方式二:零极点增益形式 z = []; % 无零点 p = [-1 -1]; % 两个重极点 k = 1; sys2 = zpk(z, p, k); % 方式三:带延迟的传递函数 sys3 = tf(1, [1 2 1], 'InputDelay', 0.5); % 统一转成 tf 对象再画图 figure; bode(sys1, sys2, sys3); legend('系数向量', '零极点形式', '带延迟'); grid on;逻辑说明:tf(num, den)是最基础的构造方式,num和den按 s 的降幂排列。zpk适合从零极点分布反推传递函数,在根轨迹分析里用得更多。InputDelay参数用来模拟纯滞后环节,比如管道传输、通信延迟。三个系统放在同一个bode图里对比,能直观看到延迟对相位的影响——延迟越大,相位下降越快,增益裕度越容易被吃掉。
参数说明:num和den的系数顺序不能乱,缺项必须补零。比如s^2 + 1要写成[1 0 1],不能写成[1 1]。InputDelay的单位是秒,和TimeUnit属性配合使用,默认是秒。
2.2bode、nyquist、nichols的选型边界
传递函数图不止一种。bode图看幅频和相频,nyquist图看包围圈数判断稳定性,nichols图把幅值和相位画在同一张图上,适合调增益。选哪个取决于你要回答什么问题。
| 绘图函数 | 横轴 | 纵轴 | 典型用途 |
|---|---|---|---|
bode | 频率(对数) | 幅值(dB) / 相位(度) | 看带宽、谐振峰、相位裕度 |
nyquist | 实部 | 虚部 | 判断闭环稳定性、看包围(-1,j0)情况 |
nichols | 相位(度) | 幅值(dB) | 调增益、看灵敏度 |
step | 时间 | 幅值 | 看时域响应、超调、调节时间 |
我一般会先用bode扫一遍频率特性,确认相位裕度和增益裕度;如果裕度不够,再用nichols图微调增益;最后用step验证时域指标。nyquist图在判断条件稳定系统时特别有用,但新手容易看错包围方向,建议配合margin函数一起用。
% 计算裕度并标注在 bode 图上 sys = tf([1], [1 2 1]); figure; margin(sys); % 自动标注幅值裕度和相位裕度 grid on; % 获取具体数值 [Gm, Pm, Wcg, Wcp] = margin(sys); fprintf('幅值裕度: %.2f dB\n', 20*log10(Gm)); fprintf('相位裕度: %.2f 度\n', Pm); fprintf('穿越频率: %.2f rad/s\n', Wcp);逻辑说明:margin函数会自动在bode图上标出幅值裕度和相位裕度的位置,省去手动读图的麻烦。Gm是幅值裕度的绝对值,转成 dB 要取20*log10。Wcg是相位穿越频率,Wcp是幅值穿越频率。这两个频率决定了系统的响应速度和稳定程度。
参数说明:margin对多输入多输出系统返回的是数组,单输入单输出才是标量。如果系统不稳定,Gm和Pm可能返回负值或空值,这时候要看nyquist图确认包围情况。
2.3 Simulink 里搭传递函数模块的实操步骤
Simulink 基础里最容易出错的地方,是把传递函数模块的参数填错。Transfer Fcn模块的 Numerator 和 Denominator 参数,填的是系数向量,不是符号表达式。很多人习惯性写s+1,结果仿真直接报错。
正确步骤:
- 打开 Simulink,新建空白模型。
- 从 Continuous 库拖入
Transfer Fcn模块。 - 双击模块,Numerator 填
[1],Denominator 填[1 2 1]。 - 从 Sources 库拖入
Step模块作为输入。 - 从 Sinks 库拖入
Scope模块观察输出。 - 用信号线连接 Step → Transfer Fcn → Scope。
- 设置仿真时间,点击 Run。
% 用命令行批量设置 Simulink 模型参数 modelName = 'myTFModel'; open_system(modelName); % 设置传递函数模块参数 set_param([modelName '/Transfer Fcn'], ... 'Numerator', '[1]', ... 'Denominator', '[1 2 1]'); % 设置仿真时间 set_param(modelName, 'StopTime', '10'); % 运行仿真 sim(modelName);逻辑说明:set_param可以在不打开图形界面的情况下批量修改模块参数,适合脚本化测试。Numerator和Denominator的值是字符串形式的向量,注意方括号和空格。StopTime控制仿真时长,太短看不到稳态,太长浪费计算资源。
参数说明:Transfer Fcn模块默认使用Continuous采样时间,如果要做离散仿真,需要改成Discrete并设置采样周期。Scope模块的采样点数默认是 5000,高频信号可能失真,可以在 Scope 设置里调大。
3. 闭环传递函数图的坑:feedback和series的隐藏规则
3.1feedback的正负号陷阱
开环传递函数画完了,下一步通常是画闭环。MATLAB 的feedback函数签名是feedback(sys1, sys2, sign),sign默认是 -1,表示负反馈。但很多人不知道,sign的位置在第三个参数,如果写成feedback(sys1, sys2, 1),就变成了正反馈,画出来的图完全不对。
% 开环传递函数 G = tf([1], [1 2 1]); H = tf([1], [1 1]); % 负反馈闭环(默认) sys_cl_neg = feedback(G, H); % 正反馈闭环 sys_cl_pos = feedback(G, H, +1); % 对比阶跃响应 figure; step(sys_cl_neg, sys_cl_pos); legend('负反馈', '正反馈'); grid on;逻辑说明:负反馈降低增益、提高稳定性,正反馈提高增益但容易发散。feedback(G, H)计算的是G/(1+GH),feedback(G, H, +1)计算的是G/(1-GH)。正反馈的阶跃响应通常表现为持续上升或振荡发散,和负反馈的收敛特性形成鲜明对比。
参数说明:G是前向通道,H是反馈通道。如果反馈通道是单位反馈,H可以省略,直接写feedback(G, 1)。sign参数只接受+1和-1,其他值会报错。
3.2series和parallel的连接顺序
多环节串联时,series函数的参数顺序不影响结果,因为乘法满足交换律。但parallel不一样,parallel(sys1, sys2)计算的是sys1 + sys2,顺序也不影响。真正容易出错的是混合连接:先串联再反馈,和先反馈再串联,结果完全不同。
% 三个环节 G1 = tf([1], [1 1]); G2 = tf([1], [1 2]); G3 = tf([1], [1 3]); % 先串联 G1 和 G2,再与 G3 构成反馈 sys_a = feedback(series(G1, G2), G3); % 先反馈 G1 和 G3,再与 G2 串联 sys_b = series(feedback(G1, G3), G2); % 对比 figure; bode(sys_a, sys_b); legend('先串联再反馈', '先反馈再串联'); grid on;逻辑说明:series(G1, G2)等价于G1 * G2,feedback的第二个参数是反馈通道。两种连接方式的传递函数完全不同,频率特性也有明显差异。实际系统里,反馈通常加在局部环节上,所以sys_b的接法更常见。
参数说明:series和parallel都支持多参数输入,比如series(G1, G2, G3)。如果环节数量多,建议用connect函数或者 Simulink 的connect命令,避免手动拼接出错。
3.3 用minreal消去零极点对消
传递函数经过多次series和feedback运算后,分子分母可能出现相同的零极点。这些零极点对消在数学上不影响传递函数,但在数值计算里会引入误差,导致bode图出现毛刺或者step响应异常。
% 构造一个带零极点对消的系统 num = [1 1]; den = conv([1 1], [1 2]); % (s+1)(s+2) sys = tf(num, den); % 消去零极点对消 sys_min = minreal(sys); % 对比 disp('原始系统:'); sys disp('最小实现:'); sys_min逻辑说明:minreal会自动消去分子分母的公因式,返回最小实现。对于高阶系统,minreal还能降低状态空间模型的阶数,提高仿真速度。conv函数用来做多项式乘法,构造分母时很方便。
参数说明:minreal的第二个参数是容差,默认是sqrt(eps)。如果零极点非常接近但不完全相等,可以适当调大容差。但容差太大会误消有用的零极点,建议先用默认值试。
4. 避坑与排查:传递函数图常见的五个翻车现场
4.1 现象:bode图频率范围不对,低频段看不到
原因:bode默认的频率范围是根据系统极点自动选的,如果系统有极低频极点,默认范围可能从 0.1 rad/s 开始,导致低频段被截断。
解决:手动指定频率范围。bode(sys, {1e-3, 1e3})表示从 0.001 到 1000 rad/s。也可以用logspace生成频率向量:w = logspace(-3, 3, 500); bode(sys, w);。
4.2 现象:step响应一直不收敛,仿真时间到了还在振荡
原因:系统本身不稳定,或者反馈极性接反了。正反馈会让系统发散,负反馈才能收敛。
解决:先用pole(sys)看闭环极点实部。如果有正实部极点,系统不稳定。再检查feedback的sign参数,确认是 -1 而不是 +1。
4.3 现象:Simulink 仿真报错“代数环”
原因:传递函数模块直接反馈到自身,或者多个模块形成无延迟的闭环,Simulink 无法求解代数方程。
解决:在反馈路径上加一个Memory模块或者Unit Delay模块,打破代数环。或者改用Transfer Fcn的离散版本,设置采样周期。
4.4 现象:nyquist图包围方向看不清,判断不了稳定性
原因:nyquist默认只画正频率部分,负频率部分需要手动开启。包围圈数要看整个围线,只看一半容易误判。
解决:nyquist(sys)之后加axis equal,让坐标轴比例一致。再用nyquist(sys, {wmin, wmax})指定频率范围,放大关键区域。必要时用nyquistplot的ShowFullContour选项画完整围线。
4.5 现象:margin返回空值或负值
原因:系统不稳定,或者幅值裕度和相位裕度的定义不适用。对于非最小相位系统,margin的结果可能没有物理意义。
解决:先用isstable(sys)判断稳定性。如果不稳定,margin的结果只能作为参考,不能直接用来设计控制器。改用nyquist或者root locus分析。
5. 进阶技巧:用ltiview和sisotool做交互式调参
bode和step是静态图,调参要反复改代码、重新运行。MATLAB 提供了两个交互式工具:ltiview和sisotool。ltiview可以同时显示多个系统的多种响应,支持鼠标缩放和游标读数。sisotool是单输入单输出设计工具,可以直接拖拽零极点、实时看bode图和step响应的变化。
% 打开 ltiview,加载系统 sys = tf([1], [1 2 1]); ltiview({'bode', 'step'}, sys); % 打开 sisotool,交互式调参 sisotool(sys);逻辑说明:ltiview适合对比多个设计方案,比如不同增益下的bode图。sisotool适合从零开始设计控制器,支持根轨迹、bode图、nichols图三种视图联动。在sisotool里拖拽零点或极点,所有视图会实时更新,比手动改代码快得多。
参数说明:ltiview的输入是响应类型和系统数组,响应类型可以是'bode'、'step'、'nyquist'、'nichols'等。sisotool的输入是开环传递函数,工具会自动计算闭环响应。如果系统有延迟,sisotool的根轨迹视图可能不准确,建议用bode视图调参。
我自己的习惯是:先用sisotool粗调,确定控制器结构和大致的零极点位置;然后把参数写回脚本,用bode和step做精细验证;最后用minreal消去零极点对消,确保模型干净。从那以后我每次画传递函数图之前,都强制走一遍tf→minreal→margin→step的流程,再也没出现过“图不对但不知道哪错了”的情况。希望帮到你。
本文还有配套的精品资源,点击获取