简介:面向自动控制原理课程学习与 MATLAB 仿真实操的入门资料,围绕脉冲响应、阶跃响应、伯德图与 PID 控制器构成一条从时域到频域的分析链路,适合需要把课堂概念落到代码与模型中的学生及自控初学者。压缩包共 3 个文件、约 7KB,以 2 个 m 脚本和 1 个 mdl 模型为主:脚本侧侧重系统响应的计算与曲线绘制,模型侧便于在 Simulink 中搭建并观察 PID 控制回路。已有 1684 人学习下载,可作为同类练习的参考样本。读者可借助其中的代码框架复现 impulse、step、bode 等分析过程,结合传递函数或状态空间模型查看阶跃输入下的动态行为与幅频、相频特性,并通过调整比例、积分、微分增益体会参数变化对稳定性与响应速度的影响,为课程实验和简单控制设计提供可运行的起点。
1. 从敲一下水箱说起:脉冲响应、阶跃响应、伯德图到底在测什么
在 MATLAB 里敲三个函数——impulse、step、bode,就能分别画出脉冲响应、阶跃响应和伯德图,再接一个 pid 对象把闭环跑起来,一套控制入门的小实例就齐了。这几个词经常一起出现,也经常一起把人绕晕。打个比方:你往水箱里猛灌一瓢水然后立刻停手,水位先冲高再慢慢回落,这是脉冲响应;换成把水龙头一次拧到固定开度不再动,水位抖两下停在新高度,这是阶跃响应;伯德图问的是另一个问题——如果进来的不是一次动作,而是一串快慢不同的正弦波,这套系统对每个频率分别放大多少、延迟多少。搞懂它们,看到一条抖动曲线时才知道该调哪个参数、该补哪张图。
2. 脉冲响应与阶跃响应:给系统“敲一下”和“推一把”的区别
2.1 脉冲响应:松手之后系统自己的余振
想象你拿勺子敲一下玻璃杯,耳朵听到的那声“叮——”会持续一小会儿,音调固定、音量渐弱。敲击给杯子的能量是瞬间注入的,之后杯子按自己的固有频率振动、按自己的阻尼慢慢衰减。脉冲响应就是把“敲一下”这件事在数学上标准化:输入是一个宽度无限窄、面积刚好等于 1 的理想冲激 δ(t),系统在零初始状态下产生的输出记作 h(t)。
为什么规定面积是 1?因为这样不同系统拿到的“总能量”一样,输出才有可比性。要是允许随便定面积,大系统小系统画出来的曲线就没法放在一张图上比较了。
从数学上看,脉冲响应和传递函数是一枚硬币的两面:h(t) 就是 G(s) 的拉普拉斯逆变换,知道 h(t) 等于知道 G(s),反过来也成立。这个性质让脉冲响应成了系统辨识里的“指纹”——锤击法测模态、房间声学的混响时间、电路里打一个窄脉冲看振铃,本质上都是在测 h(t)。
读脉冲响应主要看两件事:一是它衰减到接近零要多久,对应极点的实部,衰减越快说明阻尼越大;二是它来回振荡的频率,对应极点的虚部。把这层对应关系列成表,比死记公式直观得多。
| 极点位置 | 脉冲响应形态 | 直观感受 |
|---|---|---|
| 负实轴 | 单调指数衰减,不穿零 | 一杯热水慢慢凉下来 |
| 左半平面共轭复极点 | 幅值递减的振荡 | 敲钟后声音越来越小 |
| 虚轴上共轭极点 | 等幅振荡,不衰减 | 没有摩擦的理想单摆 |
| 右半平面 | 幅值越来越大 | 话筒贴近音箱后的啸叫 |
这张表解释了为什么调参的人总盯着阻尼比:阻尼比小,极点靠近虚轴,脉冲响应要振很久才消停;阻尼比大,极点远离虚轴,响应干脆但可能变慢。
在 MATLAB 里拿到脉冲响应只要一行:
s = tf('s'); G = 1/(s^2 + 0.6*s + 1); % 阻尼比 0.3、自然频率 1 rad/s 的二阶对象 impulse(G); % 画脉冲响应,横轴自动取合适的时间范围 grid on;tf('s')先声明复变量 s,G就是传递函数对象,impulse(G)内部做逆变换并选时间向量。想自己控制时间范围,写成impulse(G, 0:0.01:30)即可。
有一点容易被忽略:真实世界里不存在宽度为零的冲激。工程上的做法是让脉冲宽度远小于系统最快的时间常数,比如系统最快动态是毫秒级,那用微秒级的窄脉冲去激励就足够近似。宽度不够窄,测出来的其实是脉冲响应和输入波形的卷积,曲线会被“抹圆”。
2.2 阶跃响应:一次把输入拧到位
阶跃响应的输入是从 0 突然跳到 1 然后一直保持。听起来比冲激还简单,但它是工程里出现频率最高的测试信号,原因很实在:大多数执行器的工作方式就是“给一个常值指令并保持住”。阀门开到 30%、电机给定某个转速、加热器功率设到某个百分比,全是阶跃动作。用最常发生的输入去测系统,结论自然最贴近日常使用。
阶跃响应图上通常读五个指标,stepinfo会一次性算给你:
| 指标 | 含义 | 关注点 |
|---|---|---|
| 上升时间 | 从稳态值的 10% 到 90% 所用时间 | 响应快不快 |
| 峰值时间 | 到达第一个峰值的时间 | 振荡周期的一半左右 |
| 超调量 | 峰值超出稳态值的百分比 | 会不会冲过头 |
| 调节时间 | 进入并保持在一定误差带内的时间 | 多久能消停 |
| 稳态误差 | 时间趋于无穷时与目标值的差 | 最后准不准 |
一阶系统 G=K/(τs+1) 的阶跃响应是单调爬升的指数曲线,没有超调,时间常数 τ 决定快慢,2% 误差带下的调节时间大约是 4τ。二阶系统就热闹多了,超调量只由阻尼比决定:
Mp = exp(−πζ / √(1−ζ²))
代入 ζ=0.3,超调约 37%;代入 ζ=0.7,超调约 4.6%。这组数字解释了一个行业习惯:调参时喜欢把闭环阻尼比往 0.7 附近推,超调落在 5% 以内,既快又不冲。看到有人把目标超调定在 5% 左右,不必觉得是拍脑袋,背后就是这条曲线。
s = tf('s'); G1 = 1/(0.5*s + 1); % 一阶,时间常数 0.5 s G2 = 1/(s^2 + 0.6*s + 1); % 二阶,阻尼比 0.3 info1 = stepinfo(G1); info2 = stepinfo(G2); fprintf('一阶超调 %.1f%%,二阶超调 %.1f%%\n', ... info1.Overshoot, info2.Overshoot);fprintf里的%%是转义写法,输出一个百分号。运行结果会告诉你一阶超调 0%、二阶接近 37%,和公式算出来的一致。stepinfo默认按稳态值的 2% 误差带判定调节时间,想要 5% 可以加参数SettlingTimeThreshold。
2.3 两者是积分与求导的关系,不是两套东西
很多人把脉冲响应和阶跃响应当成两种独立的分析工具,各画各的。其实它们严格咬合:阶跃响应等于脉冲响应的积分,脉冲响应等于阶跃响应的导数。
y_step(t) = ∫₀ᵗ h(τ) dτ
道理不难想:阶跃输入相当于从 0 时刻开始,每时每刻都在往里“加一点冲激”,把所有这些冲激的响应累加起来,就是阶跃响应。反过来,把阶跃响应求导,得到的正是每一刻新注入那一点冲激造成的即时影响。
这条关系有个很实用的推论:阶跃响应是脉冲响应的积分,而积分本身是低通,会把快速抖动抹平。所以一条看起来光滑漂亮的阶跃曲线,不代表系统内部没有高频振铃,只是被积分藏起来了。想看系统真实的“抖动性格”,得回头看脉冲响应。
s = tf('s'); G = 1/(s^2 + 0.6*s + 1); t = 0:0.005:20; % 步长 5 ms,远小于振荡周期 h = impulse(G, t); % 脉冲响应 y = step(G, t); % 阶跃响应 y2 = cumtrapz(t, h); % 梯形法数值积分还原 err = max(abs(y - y2)); % 两种算法的最大偏差 fprintf('最大偏差 %.4f\n', err);cumtrapz是梯形积分,返回和输入等长的累积结果;err反映离散化带来的误差,正常情况下在千分之一量级。步长取得越细,偏差越小;但步长太细会拖慢仿真,取最快时间常数的二十分之一左右就够用。
提示:想验证“阶跃响应求导等于脉冲响应”,用
diff(y)./diff(t)做数值微分即可,但数值微分对噪声敏感,仿真数据干净才靠谱。
3. 伯德图:把频率从慢到快扫一遍,能看见什么
3.1 频率响应:一串快慢不同的正弦波打进去
前面两种测试都是“给一下、看反应”,伯德图换了个问法:如果输入不是一次动作,而是一串连续的正弦波,频率从很慢到很快逐点变化,系统对每个频率分别放大多少倍、滞后多少角度?
线性系统有个很好的性质:输入 A·sin(ωt),稳态输出仍然是同频率的正弦,只是幅值变成 B、相位偏移了 φ。B/A 就是该频率下的幅值放大倍数,φ 就是相位滞后。把 ω 从很小扫到很大,每个频率记一个点,连起来就是频率响应。
生活里的类比是声音穿过一面墙。低频的鼓点透过来还挺清楚,高频的细节被墙吃掉不少;同一面墙对不同频率的“通过率”不一样,对每个频率造成的延迟也不同。伯德图就是把这面墙的通过率和延迟画成两条曲线。
具体画法是两张子图:上面是幅频,纵轴用 20·log₁₀|G(jω)|,单位分贝;下面是相频,纵轴是角度;两张图的横轴都是对数刻度的频率。用对数横轴的好处很实际——一套系统的工作频段可能横跨四五个数量级,线性坐标根本画不下;而且串联环节的幅值相乘在对数下变成相加,相位本来就直接相加,手画渐近线时特别顺手。
渐近线的规律值得记:每遇到一个极点,幅频斜率往下折 20 dB/dec;每遇到一个零点,往上折 20 dB/dec;一个积分环节 1/s 从头到尾都是 −20 dB/dec,相位恒定 −90°。看到一条 −40 dB/dec 的斜线,基本可以判断那个频段有两个极点在一起起作用。
3.2 幅频相频里藏着四个读数
伯德图上信息不少,但真正天天用到的就四个。
第一个是低频增益。频率趋于零时幅值曲线的位置,决定了系统跟阶跃指令的贴合程度。0 型系统低频增益是个有限值,阶跃输入下会留静差;1 型系统因为含一个积分环节,低频增益趋于无穷,静差被消掉。这也是为什么加积分能消除静差——它在频域上把低频增益抬起来了。
第二个是穿越频率 ωc,也就是幅值曲线穿过 0 dB 的那个频率。它粗略对应闭环带宽:穿越频率越高,闭环能跟上的指令变化越快,响应越迅速;但同时高频噪声也更容易被放进来。响应速度和噪声抑制在这里是一对矛盾,调参本质上是在这两者之间找平衡点。
第三个是相位裕度 PM。在穿越频率处读相位,距离 −180° 还差多少度,就是相位裕度。经验上 45° 到 60° 是个舒服的区间:太小,阶跃响应超调大、振铃多;太大,响应变得迟钝。二阶系统有个好用的口算近似,ζ ≈ PM/100,相位裕度 60° 对应阻尼比 0.6 左右,超调约 10%。
第四个是增益裕度 GM。找到相位正好到 −180° 的那个频率,看此时幅值距离 0 dB 还有多少分贝。它回答的是“增益还能再放大多少倍才开始出问题”。
s = tf('s'); G = 1/(s^2 + 0.6*s + 1); [Gm, Pm, Wcg, Wcp] = margin(G); fprintf('增益裕度 %.2f dB,相位裕度 %.1f 度,穿越频率 %.2f rad/s\n', ... 20*log10(Gm), Pm, Wcp);margin返回的Gm是绝对增益倍数而不是分贝,所以要再取一次20*log10;Wcg是相位穿越频率,Wcp是增益穿越频率,后者就是前面说的 ωc。margin(G)不带输出参数时会直接在图上一并标出这两个裕度,做报告很方便。
注意:
margin对含积分环节的系统也能算,但如果幅值曲线多次穿越 0 dB,返回的是最保守的那一组,看图上标注确认一下更稳妥。
3.3 伯德图读得出趋势,读不出所有细节
伯德图强在全局视野:哪些频段被放大、哪些被压制、带宽多宽、裕度够不够,一眼扫过去就有数。它还能直接看出时域图上看不到的东西,比如系统对某个频段扰动的敏感程度,以及加入滤波器后噪声抑制能力改善了多少。
但它也有明确的边界。横轴是频率,没有“第几秒”,所以读不出具体的上升时间和调节时间;它描述的是线性时不变系统,饱和、限幅、死区、齿隙这些非线性环节在图上完全体现不出来;超调量只能靠二阶近似估算,高阶系统直接读会偏。
有个细节值得单独说:纯延迟在伯德图上非常好认——幅值曲线一动不动,相位曲线随频率线性往下掉。时域上延迟只是把曲线整体右移,看着不起眼,频域上却是相位持续流失,吃掉大量相位裕度。这就是为什么控制系统里一个不大的延迟常常让裕度忽然不够用,调参时反复翻车。
想看指定频段,bode(G, {0.1, 100})可以直接限定横轴范围,把注意力放在关心的区间。
4. PID 实例:三个参数在曲线上各留下什么指纹
4.1 把对象、控制器和反馈接成一个圈
选一个具体的对象来跑:G(s) = 1/(s² + 0.6s + 1),自然频率 1 rad/s,阻尼比 0.3,直流增益 1。挑它是因为它自己就带明显超调,任何调参动作都能在曲线上看出来,不像过阻尼对象那样加什么都平平的。
控制器用并联型:C(s) = Kp + Ki/s + Kd·s。三项各管一件事,用洗澡调水温来类比最贴切。Kp 是“觉得凉就拧一把”,误差越大拧得越狠;Ki 是“一直偏凉就一直往热的方向拧”,把历史误差累积起来;Kd 是“手碰到水发现正在快速变热,提前收一点”,看的是误差变化的速度。
闭环传递函数是 T = C·G / (1 + C·G),单位负反馈。这个式子说明一件事:调参改变的不是对象本身,而是闭环整体的形状,所以三个参数的影响会互相纠缠,不存在“调好一个再调下一个就完事”的独立性。
实际工程里的微分项几乎不会用纯微分,而是串一个低通:Kd·s/(1 + s/N),N 取带宽的 10 到 20 倍。原因很简单,纯微分对高频的放大是无上限的,传感器上一点噪声会被放大成执行器的大幅抖动。
4.2 三个参数各改曲线哪一段
先把经典结论列成表,再看代码验证。
| 参数增大 | 上升时间 | 超调量 | 调节时间 | 静差 | 噪声敏感度 |
|---|---|---|---|---|---|
| Kp | 变短 | 变大 | 通常变长 | 减小但不为零 | 中等 |
| Ki | 略变短 | 变大 | 变长 | 消除 | 较低 |
| Kd | 略变短 | 变小 | 变短 | 不变 | 高 |
这张表是调参的出发点,但表里的“通常”“略”说明它不是铁律,实际形状取决于对象。最靠得住的办法是逐项扫描,亲眼看曲线怎么变。
s = tf('s'); G = 1/(s^2 + 0.6*s + 1); Kp_list = [0.3 0.8 1.5 3]; figure; hold on; for k = 1:numel(Kp_list) C = pid(Kp_list(k), 0, 0); % 只开比例项,Ki 和 Kd 置零 T = feedback(C*G, 1); % 单位负反馈闭环 step(T, 20); % 统一仿真 20 秒,方便对比 end legend('Kp=0.3','Kp=0.8','Kp=1.5','Kp=3'); grid on;hold on让四条曲线叠在一张图上,legend的顺序要和循环里Kp_list的顺序一致,否则标错颜色就白看了。跑完会看到:Kp=0.3 时曲线爬得慢,但很平;Kp 一路加到 3,上升明显变快,超调接近一半,还带明显振荡。这就是“比例增大加快响应、同时推高振荡”的直观版本,光看表格体会不到那个抖动有多难受。
再单独看积分项。Ki 的作用是消除静差,代价是相位滞后——积分环节在低频提供增益,同时贡献最多 −90° 的相位,裕度被吃掉,超调自然上来。只开比例时,闭环对阶跃指令往往留一个小静差;把 Ki 从一个很小的值(比如 0.1)往上加,静差会逐渐消失,然后超调开始变大、调节时间变长。
这里有个绕不开的坑叫积分饱和。执行器有上限,误差长时间存在时积分项会一直累积,等误差终于反号,积分项已经憋得很大,要很久才能退回来,表现为曲线冲上去后回落特别慢。解决思路是抗积分饱和:一旦输出打到限幅,就停止积分或按超出量回算。
微分项 Kd 的效果在曲线上很直观:超调被压下去,第一个峰变矮,振荡次数减少,看起来“更沉稳”。代价是高频放大,传感器噪声一旦存在,执行器就开始抖。所以实际做法往往是对测量值微分而不是对误差微分,避免指令突变时微分项打出一个尖峰。
4.3 自动整定当起点,手调做收尾
MATLAB 提供了pidtune做自动整定,默认设计目标是把相位裕度做到 60°,这个默认值和前面说的经验区间是对上的。
s = tf('s'); G = 1/(s^2 + 0.6*s + 1); Cauto = pidtune(G, 'PID'); % 按 60 度相位裕度整定 Tauto = feedback(Cauto*G, 1); info = stepinfo(Tauto); fprintf('Kp=%.3f Ki=%.3f Kd=%.3f\n', Cauto.Kp, Cauto.Ki, Cauto.Kd); fprintf('超调 %.1f%%,调节时间 %.2f s\n', info.Overshoot, info.SettlingTime);pidtune(G,'PID')返回一个 pid 对象,Cauto.Kp、Cauto.Ki、Cauto.Kd直接读三项系数。想指定穿越频率或设计偏好,用pidtuneOptions设置CrossoverFrequency或DesignFocus。
自动整定给的是一组能用的起点,不是终点。它按线性模型算,模型一旦有延迟、饱和、噪声,结论就会偏。比较稳妥的流程是:拿pidtune的结果作为初值,先看阶跃响应,再回头看margin打印的相位裕度,两个视角都对得上再往实际系统上搬。手调时按 Kp、Ki、Kd 的顺序走,每加一项都回头同时看阶跃曲线和裕度,比一口气调完再验要少走很多弯路。
提示:仿真模型里加一个
TransportDelay或InputDelay,再跑一遍pidtune,会看到它给出的增益明显变小。这个对比能让人对延迟的杀伤力有具体感受。
5. 常见误区:响应曲线、传递函数与 PID 参数最容易混在哪
5.1 误区一:阶跃响应漂亮就等于系统没问题
易混点:把一张好看的阶跃响应当成系统的全貌,看到超调小、调节快就收工。
为什么混:阶跃响应最好测、报告里最常见,看多了容易产生“这就是系统”的错觉。而且阶跃响应确实综合了上升、超调、静差几个关键指标,很像一份完整答卷。
怎么区分:阶跃响应只是某一种输入下的一个切面,而且积分会掩盖高频振铃。两个系统阶跃响应几乎重合,脉冲响应可能一个干净一个抖得厉害。更实际的问题是大信号行为:小阶跃(0.1 的指令)跑出来漂亮,不代表 1.0 的指令也漂亮,执行器一饱和,曲线立刻变形。所以看到漂亮的阶跃曲线,顺手做两件事——补一张脉冲响应看内部有没有振铃,换一个更大的阶跃幅值看饱和边界在哪。
5.2 误区二:伯德图只是用来判断闭环会不会发散
易混点:把伯德图等同于稳定性判据,觉得裕度算出来够大,这张图的任务就完成了。
为什么混:教材讲频域分析时,先从奈奎斯特判据和伯德图判据切入,考试也围绕裕度出题,久而久之伯德图就被贴上了“判稳工具”的标签。
怎么区分:裕度只是伯德图上的一项读数。低频增益告诉你静差能力,穿越频率告诉你带宽和响应速度,幅频曲线的斜率告诉你噪声在哪个频段被放大,谐振峰的高度和超调有对应关系。把伯德图只当判据用,等于买了一台能测十项指标的仪器,每次只看一个数。实际调参时,判断“还能不能再加一点增益”,看的往往是裕度还剩多少和带宽是否已经超出执行器能力,两件事一起看。
5.3 误区三:PID 三个参数可以一个一个独立调好
易混点:认为 Kp 管速度、Ki 管静差、Kd 管超调,三件事互不干扰,按顺序各调各的就行。
为什么混:教科书表格把三项的影响分行列出,看起来边界清晰;手调口诀也常写成“先比例、再积分、后微分”,像是三个独立步骤。
怎么区分:三项在闭环里是叠加的,改一个,另外两个的最优值就移动了。加 Ki 相当于在低频增加增益,等效于把比例作用也加强了一部分,超调会跟着变;加 Kd 引入相位超前,裕度改善,原先合适的 Kp 又显得保守。所以顺序法只是启发式,每调一步都要回头重看整条曲线。更靠谱的心态是把三个参数当成一个整体在搜索,而不是三个独立的旋钮。
5.4 误区四:仿真曲线贴合就算完事
易混点:MATLAB 里 step 曲线和预期一模一样,就认为实际系统接上去也会一样。
为什么混:仿真环境里对象是理想线性的,没有延迟、没有噪声、没有量化误差、没有执行器限幅,跑出来的曲线干净得让人放心。
怎么区分:把仿真当成“理想条件下的上限”,而不是“实际结果的预测”。做三件事能提前发现大部分问题:加一个几十毫秒的延迟看裕度掉多少;在测量端叠一点噪声看执行器输出抖不抖;给执行器加限幅看积分饱和会不会出现。还有采样周期,连续域设计完直接离散化,采样太慢会让相位裕度悄悄缩水,这一点在仿真里不加离散环节是看不出来的。仿真负责验证思路,实测定终稿。
6. 什么时候看阶跃、什么时候画伯德:一张判断表和一个踩坑习惯
这几张图不是替代关系,各回答不同的问题。手上有个具体疑问时,按下面这张表挑工具,能省掉不少来回试的时间。
| 你手上的问题 | 先看哪张图 | 理由 |
|---|---|---|
| 响应快不快、超调多大、多久消停 | 阶跃响应 | 时域指标直接读,和验收标准对得上 |
| 系统内部有没有振铃、振荡频率多少 | 脉冲响应 | 不被积分抹平,极点信息最直接 |
| 带宽多宽、裕度还剩多少、噪声从哪进来 | 伯德图 | 频域全局视野,调增益前必看 |
| 参数往哪个方向调、还能加多少 | 阶跃响应为主,伯德图校验 | 一个看效果,一个看余量 |
| 加了延迟或滤波器后会不会出问题 | 伯德图 | 相位流失在频域上一目了然 |
大致的分工是:设计阶段先看伯德图,确定带宽和裕度的可行区间,避免一上手就把增益加到边缘;调参阶段以阶跃响应为主,因为验收指标通常写在时域里;怀疑系统内部有异常振荡、或者阶跃曲线平滑得可疑时,补一张脉冲响应。
有几条边界值得记住。对象是非线性的,比如带明显死区或齿隙,伯德图的意义会打折扣,因为线性化只在一个工作点附近成立,这时候多用不同幅值的阶跃去扫,比看频域曲线实在。系统阶次很高时,二阶近似公式给出的超调估计只能当参考,别拿它当验收依据。还有延迟,只要延迟量级接近甚至超过系统最快时间常数,任何基于无延迟模型调出来的参数都要打问号,先补延迟再调。
我自己的教训来自一个模拟项目:当时阶跃曲线调得很漂亮,超调 3%、调节时间也达标,直接交付。实际接上去以后执行器一直有轻微的高频抖动,查了半天才发现是微分项把传感器噪声放大了,而仿真里根本没有噪声。从那以后我每次拿到一条漂亮的阶跃曲线,都强制再补一张脉冲响应和一次margin打印,确认裕度不是卡着二十几度过关的,也确认执行器输出没有在高频上偷偷抖动。这个习惯救过不止一次。
这份资料把 impulse、step、bode、pidtune 四类脚本和参数对照表收在了一起,对象、扫描变量、裕度打印都写成可直接运行的完整例子,拿到手改几个数就能套到自己的模型上。希望帮到你。
本文还有配套的精品资源,点击获取