ARTICLE DETAIL

资讯详情

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

温控对象传递函数辨识:从阶跃响应实验到Matlab系统辨识实战

温控对象传递函数辨识:从阶跃响应实验到Matlab系统辨识实战 做温控项目最头疼的不是PID参数怎么调而是你根本不知道被控对象长什么样。上次我调试一台恒温实验箱加热丝和循环风扇耦合在一起进气扰动还忽大忽小靠试凑法折腾了三天都没调到理想状态。后来换了个思路先用Matlab系统辨识工具箱从一次干净的阶跃响应实验里拿到数据直接拟合出一个传递函数再回头看控制器参数所有事情突然就变得有据可依了。这篇文章就是把那套完整流程写下来阶跃响应实验怎么做、数据怎么清洗、系统辨识工具箱里的tfest怎么用、识别出来的传递函数到底能不能务实并且附上可以直接跑的Matlab代码。这套方法特别适合四类人一是手里有实际温控硬件加热器、半导体制冷片、热水箱、烤箱想做闭环控制的同学二是只学过自控原理但没亲手辨识过模型的人三是被非线性、滞后、噪声折磨的现场调试工程师四是毕业设计需要建立温控系统仿真的学生。我会尽量把每一步的“为什么”也讲清楚而不只是扔一段代码。1. 温控对象建模的第一步把阶跃响应做对1.1 为什么绝大多数温控对象可以近似成一阶惯性加纯滞后温控系统的物理本质是热量流入、流出和热容量之间的平衡。风扇或加热丝给对象注入热量同时对象通过外壳散热或者被流动介质带走热量。这种过程在数学上通常表现为一个储能元件和一个阻性元件的组合反映到传递函数里就是一个惯性环节分母上有一个一阶极点即G(s) K / (T s 1)如果热量从热源到传感器的传递路径上有明显的空间距离或者管路延迟还会出现纯滞后项 exp(-L s)。所以工程上最常采用的温控模型是G(s) K * exp(-L s) / (T s 1)K是静态增益T是时间常数L是等效纯滞后。这三个参数足够描述大部分温度回路的动态特性。系统辨识工具箱里的tfest函数要估计的正是这样一组参数。我见过很多人一上来就尝试高阶多项式模型觉得“阶数越高越准确”。但在温控这种实际对象里高阶模型的过拟合问题非常严重尤其是用阶跃响应这种信息含量有限的信号做辨识时高阶模型往往在拟合数据上很好看换个工况就彻底失真。所以第一步要建立的思维是优先选一阶惯性加纯滞后只有当残差明显不是白噪声时再考虑二阶甚至更高阶。1.2 阶跃响应实验的完整操作步骤阶跃响应实验质量直接决定辨识结果的上限数据不好再好的算法也是白搭。我当时做恒温箱实验时严格按下面这套流程来把系统稳定在某个工作点记为初始温度 y0。比如让恒温箱稳定在30°C。持续记录y0至少几分钟观察温度波动范围。如果波动超过传感器分辨率的2~3倍就要先解决环境扰动否则后面的辨识会被噪声带偏。施加一个阶跃激励控制量 u 从 u0 直接阶跃到 u1。比如加热器占空比从30%跳到50%或者从0跳到20%。保持u1不变持续记录温度直到温度上升到新的稳态并且稳定一段时间。停止记录撤掉阶跃回到初始工况。这里有两个关键点。第一阶跃幅度要控制好。我当时一开始图省事直接把加热功率从0加到100%结果温度曲线出现了明显的小圆弧而不是直上直下的惯性曲线因为系统进入了非线性区响应已经不是线性定常系统能描述的。后来把阶跃幅度控制在稳态温升的5%~10%左右曲线才变得规整。第二控制器不能处于闭环状态。做辨识实验时一定要把自动控制回路断开让控制输出保持开环阶跃否则反馈会动态改变输入无法得到真实的被控对象特性。1.3 实验数据记录与采样时间选择采样周期是容易被忽略的坑。太慢会丢掉动态信息太快会导致数据量臃肿而且高频噪声被放大。工程上一般建议采样周期取时间常数的1/10到1/20但做实验前你并不知道时间常数是多少。我的习惯是先粗估用秒表记录温度从阶跃开始上升到63.2%温升所花的时间这个时间就是大致的时间常数T。如果T大约120秒那采样周期可以在6~12秒之间。如果没把握就先用1秒采一遍后面再降采样也不迟。实验总时长建议覆盖到系统进入稳态之后至少两三个时间常数也就是从阶跃开始到结束至少要5T。数据记录格式上我通常直接用Matlab把时间和温度保存成.mat文件同时记录控制量。因为后面iddata需要的是输入向量和输出向量的时间序列而不是单独一条温度曲线。在实验现场我还会同时开一份手动日志记下阶跃发生的准确时间点、环境温度、是否有风吹过、是否有人进出房间。这些看起来不起眼的记录在排查辨识结果异常时非常有用。2. 用系统辨识工具箱之前的必要数据预处理2.1 从原始温度曲线到辨识数据的清洗拿到实验数据后千万别直接丢进tfest。原始温度曲线里通常有四个问题初始稳态偏移、传感器噪声尖峰、阶跃瞬间的电磁干扰、以及实验中的偶发扰动。先说初始稳态偏移。理论上阶跃前系统应该稳定在某个固定值但实际温度总有小波动。如果我们直接用原始绝对温度做辨识模型会试图去拟合细节噪声导致增益估计偏差。我通常做法是直接截取阶跃前一段时间计算平均值然后把整段温度数据减去这个平均值。这样输出变量就变成了“温度变化量”更符合线性模型的处理习惯。其次是噪声尖峰。加热器功率切换时传感器电路偶尔会产生一个突刺。这种尖峰在原始曲线图上就是一个孤立的异常点直接使用会让残差分析出现假相关的现象。可以用medfilt1或移动中位数滤波把尖峰去掉但要注意滤波窗口不能太大否则会把真实的动态边沿抹圆影响滞后L的估计。最后是选择辨识区间。完整实验数据包含阶跃前基线、动态响应段、稳态段三部分。动态响应段才是辨识信息所在。我一般只保留“阶跃时刻前一小段基线 完整动态过程 接近稳态后的一个短尾”尾部留够时间常数的一半即可不需要把后面漫长的稳态全放进去。设置一个截取区间既能减少无关数据干扰也能让拟合算法把注意力集中在动态段。2.2 去除趋势项与重采样所谓“去除趋势项”不只是减初始稳态还要注意环境温度缓慢漂移造成的数据基线斜坡。尤其是夏天做实验空调间歇启动房间温度有缓慢周期起伏这会在温度曲线上叠加上一个低频分量让辨识出来的时间常数偏大。处理办法有两种一种是在同一环境温度下多做几次实验取平均另一种是简单地对动态响应段做detrend把线性趋势去掉。对温控对象来说detrend足够用。重采样的问题出现在采样间隔不均的时候。有些数据采集卡会偶发丢点导致时间向量间隔不严格相等。iddata对时间向量的要求比较严格均匀采样是最稳妥的。我通常在预处理阶段用interp1把数据重采样到固定采样周期。比如原始数据时间向量可能有几个抖动点统一插值到1秒间隔后面的估计结果会更稳定。预处理完的数据应该长这样一段从0时刻开始、长度为N、采样周期为Ts的均匀时间序列对应输入控制量序列和输出温度序列。控制量在阶跃前是u0阶跃后是u1输出温度经过了减Offset和去尖峰。2.3 用iddata对象组织数据Matlab系统辨识工具箱的函数几乎都围绕iddata对象展开。它相当于把时间序列、采样时间、输入输出名称打包成一个对象后续的tfest、compare、resid都直接吃这个对象。创建代码很简单% 假设data.mat里有三个变量 % t: 时间向量单位秒 % temp: 温度输出单位摄氏度 % heat: 控制输入任意归一化单位 load(data.mat); % 截取辨识区间 idx (t t_start) (t t_end); t_seg t(idx); u_seg heat(idx); y_seg temp(idx); % 减去初始稳态 y0 mean(y_seg(t_seg t_step)); % t_step是阶跃时刻 y_seg y_seg - y0; % 创建iddata Ts 1; % 采样周期1秒 data_id iddata(y_seg, u_seg, Ts, ... Name, 温控阶跃响应, ... InputName, 加热控制, ... OutputName, 温度变化量, ... TimeUnit, seconds); % 查看数据 plot(data_id);这里有一点经验iddata的第一个参数是输出第二个才是输入别写反了。我一开始就是写反了结果tfest拟合出来的模型怎么看都不对增益符号都是反的。输出是温度变化量输入是控制量方向性一定要理清楚。3. 传递函数辨识的完整Matlab代码实现3.1 基于tfest的直接拟合数据组织好之后辨识的核心就是一个tfest调用。它可以在给定模型阶次的情况下拟合连续时间传递函数。下面是针对一阶惯性加纯滞后模型的标准做法% 指定模型1个极点0个零点1个纯滞后 np 1; % 极点个数 nz 0; % 零点个数 pd 1; % 是否有纯滞后1表示有 % 先用估计初值 init_sys idtf([], [1 1], IODelay, 0); init_sys.Structure(1).Numerator.Value 1; % 初始增益1 init_sys.Structure(1).Numerator.Minimum 0.01; % 增益下限 init_sys.Structure(1).Denominator.Value [1 1]; % 初始T1 init_sys.Structure(1).Denominator.Minimum [1 0.1]; % 辨识 sys1 tfest(data_id, np, nz, pd, init_sys); % 显示结果 disp(sys1);tfest里的np是极点个数nz是零点个数pd是延迟阶次。一阶惯性加滞后就是np1, nz0, pd1。如果不想要滞后就设pd0。init_sys是初始猜测不提供的话工具箱会自动搜索初值提供准确的初值能够显著加快收敛。实际运行之后控制台会显示类似这样的输出Discrete-time transfer function estimated using TFEST From input 加热控制 to output 温度变化量: K G(s) --------- * exp(-L*s) T*s 1 K 2.35 T 96.8 L 8.5你会看到fit百分比通常在80%以上就算可以用。但我遇到过一个有意思的情况拟合度很高但查看残差时发现明显相关性。这说明模型结构不够准确需要增加阶次。增加阶次的代码很简单% 二阶模型带纯滞后 sys2 tfest(data_id, 2, 0, 1); % 二阶模型带一个零点 sys3 tfest(data_id, 2, 1, 1);关键在于比较这几个模型的拟合度和残差然后选一个最简单且残差白噪声化的。我的原则是先用一阶如果残差通过检验就停在一阶。不要因为拟合度多出1%就去选二阶。控制的复杂度、参数不确定性都会随阶次上升。3.2 手动切线法求增益和时间常数tfest是黑盒优化方法有时候工程师还需要一个能口头解释的结果。从阶跃响应曲线上手动读取K、T、L也叫切线法是一个很经典的手工辨识方法。做法是在阶跃响应曲线变化最快的位置作一条切线切线与初始稳态水平线的交点横坐标就是纯滞后L切线与最终稳态水平线的交点横坐标对应TL所以时间常数T等于这两个水平截距之差。静态增益K用稳态输出变化量除以阶跃输入变化量。Matlab里可以用差分法近似求最大斜率点% y_seg已经减去初始稳态u_step是阶跃幅度 dy diff(y_seg); [~, idx_max_rate] max(abs(dy)); t_max_rate t_seg(idx_max_rate); % 求稳态值取最后一段均值 y_ss mean(y_seg(end-50:end)); u_ss u_seg(end) - u_seg(1); K_manual y_ss / u_ss; % 过最大斜率点作切线求与时间轴交点 % 切线方程: y y(idx_max_rate) slope * (t - t_max_rate) slope dy(idx_max_rate) / Ts; % 与y0交点 t_axis_intersect t_max_rate - y_seg(idx_max_rate)/slope; % 与yy_ss交点 t_ss_intersect t_axis_intersect y_ss/slope; L_manual t_axis_intersect; T_manual t_ss_intersect - t_axis_intersect; fprintf(手动切线法结果: K%.3f, T%.2f, L%.2f\n, ... K_manual, T_manual, L_manual);这个方法读出来的T和L在阶跃响应很干净时精度还不错。我自己的经验是手动切线法更适合用来做初值之后再用tfest精调。因为切线法对曲线噪声很敏感最大斜率点一偏L和T就都偏了。把它作为init_sys的初值能有效提高tfest的收敛速度和稳定性。3.3 模型阶次的选择与比较模型阶次选择没有绝对标准但有清晰的比较思路。把几个候选模型放在一起用compare算拟合度用resid看残差还要参考模型的参数不确定性大小。参数不确定性可以直接看tfest返回模型的parameter属性里的标准误差如果某个时间常数估计的误差超过30%基本可以认为这个参数没有被数据充分激励模型阶次过高了。一个简单的对比表格可以这样生成sys_models {sys1, sys2, sys3}; names {1阶无滞后, 1阶滞后, 2阶滞后}; for i 1:3 [~, fit_val] compare(data_id, sys_models{i}); fprintf(%s拟合度: %.2f%%\n, names{i}, fit_val); end我通常会选拟合度最高、参数较少的那个模型。比如一阶滞后拟合度91%二阶滞后92%拟合度只提升了1%但二阶模型多了两个参数而且参数不确定性明显增大这时就坚决选一阶滞后。模型是为了控制服务的不是越复杂越好。4. 模型验证拟合度不等于一切4.1 用没参与辨识的数据做交叉验证这是很多人会跳过的关键一步。tfest返回的fit百分比是用同一份数据计算出来的只能反映模型对训练数据的贴合程度不能代表真实泛化能力。要确认模型有效必须用另一段未参与辨识的数据来验证。我在做实验时通常会连续做两次几乎相同的阶跃响应实验第一次用来辨识第二次用来验证。两次实验之间间隔十几分钟确保系统回到同一起点。然后把验证数据也整理成iddataload(data_validation.mat); val_data iddata(y_val - mean(y_val(1:100)), u_val, Ts, ... InputName, 加热控制, OutputName, 温度变化量); % 用训练出来的模型去预测验证数据 compare(val_data, sys1);compare输出会显示模型预测曲线和实际曲线的重合程度还有一个拟合百分比。如果验证集拟合度和训练集拟合度差距很小差几个百分点以内说明模型是可信的。如果验证集拟合度骤降比如从92%掉到50%基本可以判断过拟合或者实验条件不一致。4.2 残差分析与白噪声检验一个合格的辨识模型它的残差应当接近白噪声也就是说残差序列不应该还有可预测的相关性。系统辨识工具箱的resid函数可以直接检查。resid(data_id, sys1);运行后会出现两个图上面是残差的自相关函数下面是残差与输入的互相关函数。图里通常会有两条虚线表示一个标准误带。只要自相关和互相关曲线大部分落在两条虚线以内只有个别点轻微越界就说明残差没有明显的动态信息残留。我第一次看到这个图时自相关曲线在低阶滞后上明显超过了虚线说明一阶模型没把动态完全吸收。后来加上纯滞后之后曲线才缩回带内。这个过程让我理解了为什么不能光看拟合度拟合度可能把噪声也当信号拟合进去了残差检验才能发现结构性问题。4.3 实际温控系统常见的辨识坑这几条坑我都踩过列出来给各位省点时间。第一阶跃幅度过大导致非线性响应。温度升高会导致散热系数变化所以大阶跃下模型线性度很差。我那次从0跳到100%功率拟合出来时间常数比小阶跃下大了将近40%因为温度越高散热越快上升后期被“压平”了。整理数据后我把阶跃幅值限制在使稳态温升不超过系统最大温升范围的20%以内效果立刻稳定。第二执行器饱和。如果你用的是PWM加热控制量进入饱和区之后实际加热功率不再随占空比线性变化这会在阶跃响应中引入非线性。所以设计实验时要把初始控制量u0和阶跃后控制量u1都避开饱和区。第三传感器位置造成的测量延迟。热敏电阻放在出风口和放在加热丝旁边辨识出来的滞后L可能相差几秒甚至十几秒。模型只是对实际对象的一种等效描述传感器位置不同同一台物理设备可能得到两组不同的K、T、L参数。这一点做控制器设计时必须心里有数。第四环境低频扰动。空调、开窗、人的走动都会在温度曲线上叠加低频分量。我在夏天下午做实验时环境温度半个小时内漂了2°C阶跃响应曲线在后面一段完全被环境漂移带偏。后来改为清晨做实验关闭空调并且分两段数据验证问题就解决了。5. 从模型到控制器一次PID整定实战5.1 用辨识传递函数整定PID参数模型识别出来了最直接的应用就是设计控制器。Matlab里可以用pidtune或pidTuner交互式整定PID参数。对于一阶惯性加滞后模型PID控制器已经足够应付。% sys1是上一节辨识出的传递函数 [C_pid, info] pidtune(sys1, PID, 0.05); % 0.05rad/s目标带宽运行后C_pid就是一组PID参数。为什么目标带宽选0.05这来自于我的时间常数约97秒纯滞后8.5秒。经验法则是目标带宽不要超过纯滞后倒数的一半也就是0.5/8.5≈0.06 rad/s。把目标带宽设置到0.05控制器输出和闭环稳定性都比较稳健。得到PID参数之后可以用一个闭环仿真快速验证S1 feedback(sys1 * C_pid, 1); step(S1); % 再加上扰动通道 Sd feedback(1, sys1 * C_pid); step(Sd);这套流程跑通之后恒温箱的实际温控效果比原来试凑法好得多超调量从原来的20%以上降到了5%以内稳定时间也缩短了一截。核心原因在于PID参数有了模型依据不再是瞎猜。5.2 模型不准确时的鲁棒性检查辨识模型总归有误差控制器参数必须保留安全裕度。实际使用时我会做这样几件事第一把辨识模型的增益K上下浮动20%把时间常数T上下浮动30%滞后L上下浮动2秒分别做闭环阶跃仿真。如果每种偏差下系统都不发散、振荡衰减这组PID参数才敢下到设备上。第二在设备上先做无扰动跟踪测试再做加扰动测试。加扰动时可以手动开关风扇或者遮挡散热口。闭环响应如果能在合理时间内返回设定值就说明鲁棒性基本过关。第三控制器里最好不要用太高的微分增益。热敏电阻的测量噪声会被微分项放大导致执行器频繁抖动。我一般会在PID结构里把微分项的低通滤波系数调到相对较低的水平比如滤波器时间常数取5~10秒。最后分享一个小技巧辨识模型得到的传递函数即使精度有限也比完全没有模型强得多。我后来在另一个水浴温控项目里直接沿用这套流程只是把采样周期换成0.5秒阶跃幅度改成总功率的15%一天之内就完成了从实验到闭环稳定的全过程。Matlab系统辨识工具箱的tfest并不神秘它就是帮你完成从数据到模型最后一步的工具但真正决定模型质量的还是实验设计那一个小时的耐心。
返回列表