做医药洁净室暖通自控的朋友,应该没少被温湿度“打架”这件事折腾过。我之前处理某制药车间的净化空调系统,控制平台用的是S7-200 SMART,对象是一台典型的两管制空气处理机组,涵盖混风、表冷、加热、加湿、送风机、过滤段这些常规工艺。项目本身不算复杂,但自动模式一投问题就来了:回风温度勉强能压住,回风湿度却跟着温度上下震荡,水阀一会儿全开一会儿全关,车间值班室天天翻报警记录。后来我把温湿度控制策略改成串级PID,用回风温湿度做主环、送风温湿度做副环,把控制链拆成两层;又把空调箱涉及的几十个模拟量通道、设定值、PID参数、报警状态全部用结构体变量重新组织。改完之后,程序结构清爽很多,现场调试速度和系统稳定性都明显上了一个台阶。这篇文章想把当时的控制方案和落地细节聊清楚,尤其是S7-200 SMART这个平台上不太被细讲的实现部分。
1. 洁净室空调箱的控制难点:为什么单回路老被“打脸”
1.1 温湿度强耦合:看起来是两个回路,实际是一条链
医药洁净室之所以麻烦,是因为温度和相对湿度并不是两个独立变量。空气温度一变,相对湿度立刻跟着变。车间回风温度稍微升高1℃,相对湿度可能掉3%~5%。如果温度和湿度各自搭一个单回路PID,温度回路让表冷水阀关小一点,湿度回路马上就感觉到湿度升高,赶紧去开加湿阀;加湿阀一开,空气带进水汽后温度又掉一点,温度回路又去开加热阀。两个回路就像两个人拔河,最后谁也稳不住,阀门还频繁折腾。
洁净室的特殊之处在于送风量很大,很多剂型要求换气次数15次/小时以上,这意味空调箱承担的热湿负荷变化快、惯性也大。从表冷段、加热段、加湿段的阀门动作,到回风温度传感器感受到变化,中间往往隔着十几米风管、过滤器和房间空间,一两分钟的滞后是常态。这个滞后对单回路PID相当不友好:增益给大了就振荡,给小了回风温度半天回不到设定值,湿度更是在加湿和除湿之间来回摆。我在现场见过不少项目,单回路PID参数已经缩得很保守,结果湿度的动态偏差还是能到±15%。
1.2 空调箱的典型工艺段与执行器配置
先给刚接触净化空调的朋友补个背景。医药洁净室空调箱一般由混风段、初效过滤段、表冷器段、加热段、加湿段、风机段、中效过滤段组成。表冷段通常走7~12℃冷水,用来降温和除湿;加热段走热水或者用电加热,负责把除湿后的冷风再热到送风温度;加湿段一般用纯蒸汽加湿,负责冬季或低湿工况加湿。执行器就是水管路上的比例积分调节阀,4~20mA或者0~10V信号控制阀位开度时按行程缓慢动作。
这套配置决定了温度和湿度控制并不是各管各的。表冷器的冷水阀关小了,送风温度升高、除湿量下降;再热阀开大了,送风温度上升但绝对含湿量基本不变;加湿阀开启,相对湿度上升,同时因为蒸汽温度比较高,也会轻微改变送风温度。这些耦合关系,决定了简单并联控制很难同时把温度和湿度都稳定在医药行业常见的指标里。医药洁净区通常要求温度20~24℃、相对湿度45%~60%,看起来范围挺宽,但药监检查要的是稳定性和记录,波动太大连验证都过不了。
1.3 为什么串级PID更适合这个场景
串级控制的本质是“把环套起来”:外环负责慢变量,也就是回风温湿度,代表房间真实状态;内环负责快变量,也就是送风温湿度,直接反映空调箱出口状态。外环的输出作为内环的设定值,内环直接驱动执行器。因为内环比外环快得多,新风温湿度变化、水阀扰动这类干扰首先被内环压住,外环面对的其实是一个已经被内环稳定过的对象,滞后大大缩短,外环PID参数也能给得更从容。
我之前见过一个很贴切的类比:单回路PID就像让老板直接去操作生产线上每一个旋钮,老板看到最终结果不对了再拧一下,反应慢还容易拧过头;串级PID则是老板定目标,现场班长看到送风状态稍有波动立刻微调,老板只管盯着车间最终指标。医药空调箱这种大滞后、强耦合对象,明显需要后一种结构。
2. 温湿度串级控制策略:主环副环定谁,执行器怎么分工
2.1 主环副环的选择原则
串级结构里最关键的问题是:温湿度串级,到底哪个环控制哪个执行器?很多人一上来把两个回路接到同一个水阀上,逻辑必然打架。我最后采用的做法是按执行器的物理作用来分:
- 湿度主回路控制除湿用的表冷水阀开度,夏季湿度高时通过它把空气温度压到露点以下,完成深度除湿。
- 温度主回路控制加热/再热段阀门,补偿表冷除湿带来的冷风感,把送风温度拉回目标。
- 加湿阀单独由湿度回路的反向动作控制,冬季干燥时开启,夏季除湿工况下强制关闭。
这个策略能成立的原因,在于“除湿+再热”是一条经典解耦链。表冷水阀开大必然让送风温度降低,但送风温度又是温度副环的控制对象,副环会迅速用再热阀把温度拉回来。再热不改变空气绝对含湿量,所以湿度靠表冷除湿来压,温度靠再热来顶,两个量在这一条链上被拆开了。实际运行中,夏季典型的控制动作就是:湿度偏高→冷阀开大→送风温度下降→温度副环感知到→热阀开大→送风温度恢复。
当然要分季节和工况:夏季湿度高,冷阀是湿度的主要执行器,热阀归温度管;冬季湿度低,加湿阀作为湿度执行器,冷阀和热阀一起负责温度。这些工况切换可以做成手动方式,也可以根据回风温湿度自动判断,我实际项目里是先在触摸屏上给了“夏季/冬季/过渡季”三个手切位,逻辑跑顺之后才做的自动判段。
2.2 主环输出到副环设定值的量程变换
这一步在S7-200 SMART上最容易翻车。PID运算内部使用的是归一化后的0~1.0标幺值,主回路的PID输出也是0~1.0的量。如果你直接把主环输出接到副回路PID的设定值输入,副回路会把送风温度设定值当成0~1来处理,实际想要的16℃、22℃全都对不上。
我的一般做法是做一次线性变换:
副回路SP = SP_MIN + 主环PID输出 × (SP_MAX - SP_MIN)
比如送风温度副环设定值范围设成10℃~30℃,主环输出0.5时,副环SP = 10 + 0.5×(30-10) = 20℃。湿度主环输出映射到送风湿度设定范围,比如30%~70%RH。这样主环和副环才能正确“对话”。这里特别提醒一句:主环输出和副环SP的上下限要跟PID向导里设定的过程变量上下限保持一致,否则同一个工程值会被两套量程算成不同的归一化结果。
2.3 串级PID参数初值怎么给
串级PID参数没有绝对标准,但给初值是有套路的。我这次调试的经验数据大致如下:
| 回路 | 比例增益P建议范围 | 积分时间TI建议 | 微分TD | 说明 |
|---|---|---|---|---|
| 温度副环(送风温度) | 1.0~3.0 | 30~120秒 | 0或很小 | 先整定这个,阀门行程慢时TI取大 |
| 温度主环(回风温度) | 0.3~1.0 | 180~600秒 | 0 | 滞后大,积分要放慢 |
| 湿度副环(送风湿度) | 0.8~2.5 | 30~90秒 | 0 | 湿度传感器噪声较大 |
| 湿度主环(回风湿度) | 0.2~0.8 | 300~900秒 | 0 | 湿度波动比温度慢得多 |
整定顺序永远是从副环到主环。副环先把送风温湿度稳定在固定SP附近,主环再关环。主环的积分时间至少是副环积分时间的2倍以上,否则两个环会同频共振,产生一种周期十几分钟的低频振荡,比单回路还难调。微分在温湿度控制里我一般不用,因为湿度传感器信号本身噪声不小,微分容易把阀门指令放大成毛刺。
2.4 分程控制:冷阀、热阀、加湿阀别打架
空调箱里冷阀、热阀、加湿阀如果都由不同PID回路独立输出,很容易出现冷热同开、能量对冲的情况。我在程序里用了分程控制思想,让同一套PID输出按区间分配到不同执行器:
| PID输出区间 | 动作对象 | 说明 |
|---|---|---|
| 0% ~ 40% | 热阀由全关到全开 | 低温需要再热时动作 |
| 40%~60% | 死区 | 防止冷热阀频繁切换 |
| 60%~100% | 冷阀由全关到全开 | 高温需要降温/除湿时动作 |
湿度回路类似:输出低位段控制加湿阀,高位段控制除湿冷阀,中间留死区。分程的好处是只有一套PID输出信号,不存在两个调节阀抢同一个被调量的问题。死区宽度要结合执行器行程时间设置,一般5%~10%就够,太大会导致温湿度对设定值存在静差。
3. 用结构体变量把空调箱程序做干净
3.1 没有结构体时,项目会乱成什么样
很多人在S7-200 SMART上写空调箱程序,习惯一个点一个点地定义符号,结果项目后期符号表里密密麻麻全是“送风温度”“回风湿度”“冷阀反馈”“热阀反馈”这种名字。一台机组还好,两台、三台机组时,每个人命名习惯不一样,有的叫AI0、有的叫AHU1_T、有的叫T_SEND,程序里查一个地址要把交叉引用翻半天。最怕的是复制粘贴后改错地址,调试时查几天都查不到。
所以我在这个项目里坚持用结构体变量来做信息建模。S7-200 SMART的编程环境虽然没有高端平台那么完善的UDT生态,但新版Micro/WIN SMART是支持用户自定义数据类型(UDT)的。UDT就是自己拼出来的一种变量模板,写成一次,就可以批量实例化成多台机组的数据结构。可以说,一台空调箱需要关注的所有信号和参数,都在同一个结构体里,程序自然干净。
3.2 UDT成员怎么规划
我的习惯是按功能段划分,一台空调箱一个结构体实例。下面是一个简化后的成员设计,实际命名按Micro/WIN SMART允许的规则来:
INPUT_ZONE // 输入区 AIT_SEND REAL // 送风温度工程量 AIH_SEND REAL // 送风湿度工程量 AIT_RTN REAL // 回风温度工程量 AIH_RTN REAL // 回风湿度工程量 DI_FAN_RUN BOOL // 风机运行反馈 DI_FAN_FAULT BOOL // 风机故障 DI_FILTER_ALM BOOL // 过滤器压差高 OUTPUT_ZONE // 输出区 AO_COLD REAL // 冷阀指令 AO_HOT REAL // 热阀指令 AO_HUMI REAL // 加湿阀指令 AO_FAN_FREQ REAL // 风机变频频率 DO_FAN_START BOOL // 风机启动指令 SET_ZONE // 设定区 SP_TEMP REAL // 回风温度目标 SP_HUMI REAL // 回风湿度目标 SP_SEND_TEMP REAL // 送风温度目标(副环SP) SP_SEND_HUMI REAL // 送风湿度目标(副环SP) PID_ZONE // PID参数区 KP_T, TI_T, TD_T REAL KP_H, TI_H, TD_H REAL STATUS_ZONE // 状态区 MODE_AUTO BOOL // 自动模式 ALM_WORD WORD // 报警字 RUN_TIME DWORD // 累计运行时间这个结构体示意不代表能直接编译,但思路是通用的。设计时要特别注意类型对齐:REAL占4字节、BOOL按位、WORD占2字节,条件允许就把同类型成员放在一起,减少后期地址偏移计算的麻烦。结构体实例多了以后,每一次地址偏移都要根据软件里自动生成的结果来核对,不能凭脑子硬算。
3.3 从模拟量通道到结构体:全局变量表的关键一步
结构体实例在全局符号表里定义之后,程序里可以直接看到类似“AHU1.SP_TEMP”这样的符号路径。但模拟量模块的通道地址是AIW0、AIW2、AIW4这样的顺序排列,它不会自动进入结构体的输入区,必须手动做一次一一映射。
我通常把模拟量转换做成一个独立子程序:每台空调箱调用一次,把一个或者若干个AIW通道地址读出来,经过滤波、量程变换、断线判断之后,写入结构体对应的REAL成员。这一步不建议偷懒直接让PID指令的PV去读AIW地址。因为我前面吃过亏:换了模拟量模块或者调整了通道顺序,所有和地址绑定的逻辑全都要翻一遍;改成统一映射之后,后面换模块、改量程、增加传感器,只需要动开头那一段转换程序,PID回路完全不受影响。
3.4 多台机组和V区规划
S7-200 SMART的V区是共享存储区,容量和具体CPU型号有关。一个UDT实例如果成员比较多,比如几十个REAL加几十个BOOL,一个实例大概占一两百字节,带十台空调箱也就两K字节左右,V区容量基本不是瓶颈。真正紧张的是模拟量通道数量和PID回路数量,而不是结构体本身。
用结构体做多台机组还有一个好处:可以规划一块连续的V区,把每台空调箱的输入区和状态区排在一起。这样后续做Modbus通讯时,从站寄存器地址可以按偏移量批量计算,上位机组态只需要按同一张布局表一次性读取,不需要一个点一个点去对地址。我在这个项目里就把AHU1到AHU5的状态区连续放在同一段V区里,触摸屏和中控读取都省了很多功夫。
4. S7-200 SMART上的程序实现:PID向导与串级联动细节
4.1 PID向导生成多个单回路
S7-200 SMART的编程环境里,PID功能主要是靠“向导”生成的,没有像更高端平台那种直接拖一个“串级PID”功能块的现成东西。实现串级的思路,就是用它生成多个单回路PID子程序,然后在主程序里把它们按顺序串联起来。
我在项目树里打开PID向导,一共生成了四个回路:回路0做回风温度主环,回路1做送风温度副环,回路2做回风湿度主环,回路3做送风湿度副环。每个回路会生成一个类似PIDx_INIT的子程序,调用时指定过程变量、设定值、手动/自动切换、手动输出等参数。向导里要填写好过程变量上下限、输出类型、采样时间、PID参数,这些数值后续都可以通过修改向导再重新生成。
要注意的是,向导生成子程序的输入输出接口,默认涉及的是归一化后的工程百分比值。而我们在结构体里用的是20.0℃、60.0%RH这样的工程量,两者之间必须有明确的归一化和反归一化环节。这部分我没有放在向导里硬填,而是在程序中写了一个统一的换算逻辑:先把结构体里的工程量折算成0~1.0给到PID子程序,再把PID输出折算回工程量或者直接分程给阀门指令。
4.2 主环输出到副环SP:连续赋值还是带安全跟踪
串级联动在程序里其实不复杂,关键是要想清楚主环输出什么时候允许更新副环SP。我实际写的逻辑是:每个扫描周期先读回风温度工程量,归一化后送入主环PID子程序;主环PID计算得到的输出,先做0.02~0.98的限幅,再通过线性变换映射成送风温度副环的设定值;副环PID再读这个设定值,和自己的送风温度PV一起计算输出,最后经过分程逻辑分给冷阀和热阀。湿度回路同理。
这里有个容易踩的坑:系统刚启动或者送风机还没运行时,主环的输出是没有意义的。如果不做保护,主环可能会在开机前一直朝某个方向积分,等风机一启动,副环SP已经被推到量程上限,送风温度一下就冲上去。所以我在主环输出到副环SP之间加了一个“运行允许”位:只有送风机运行且空调箱处于自动模式时,主环输出才允许更新到副环SP;其他情况下副环SP保持一个安全值,比如送风温度固定20℃、送风湿度固定55%,同时主环切到手动保持状态,不让它盲目积分。
4.3 手自动切换与无扰逻辑
无扰切换是医药项目验收时经常被盯着检查的功能。S7-200 SMART的PID向导子程序一般带有自动/手动切换输入端子,手动模式下可以直接把外部给定的手动输出值送到子程序接口。我在触摸屏上做了每个阀门的单独手自动切换,手动模式下PID的输出通道被切断,当前阀门开度完全由操作员给定。
从手动切回自动前,要把当前阀位反馈折算成PID的0~1.0输出,作为手动值先注入一次,再做切换。这样保证切自动的瞬间,阀门开度保持原样,然后由PID慢慢接管。串级结构下还要多加一层配合:副环切手动时,主环也强制切到手动保持;主环切手动时,副环可以继续自动,但SP不再跟随主环,而是使用安全值。这样就不会出现副环已经手动去动阀门,主环还闷头对着回风温度积分的情况。
4.4 报警与联锁:PID算法之外的安全网
空调箱程序不能只有PID,医药洁净室对传感器断线、风机故障、温湿度超限非常敏感。我在结构体的状态区里规划了几个报警字,并把报警逻辑和PID逻辑完全分开处理:
| 报警条件 | 判定方式 | 动作策略 |
|---|---|---|
| 温度传感器断线 | 4~20mA输入信号低于4mA对应原始值 | 对应PID切手动,阀位保持,报警提示 |
| 湿度传感器断线 | 同上 | 对应PID切手动,阀位保持,报警提示 |
| 风机运行反馈丢失 | 运行指令发出后10秒无反馈 | 禁止冷阀/热阀/加湿阀自动输出,防止无送风时水阀大开 |
| 过滤器压差高 | 压差开关闭合 | 只报警提醒更换滤网,不停机 |
| 回风温湿度超限 | 超出设定范围并持续一段时间 | 报警,记录超限时间,联动上位机界面提示 |
这些逻辑单独写起来不难,但很容易被忽略。现场调试时第三方验证经常会专门测传感器断线、风机反馈丢失这些边界情况,如果程序里没有对应保护,PID可能会对着错误信号猛推阀门,把空调箱弄得更糟。安全逻辑和PID逻辑解耦,是我在这个项目里坚持的程序结构原则。
5. 现场调试:串级PID不是调完参数就完事
5.1 先内环后外环,顺序千万别反
串级PID调试顺序是固定的:先把内环拆开来调稳,再合上外环。内环调试阶段,主环输出固定在一个中间值,副环SP手动设定一个固定温度,比如20℃,观察送风温度能否稳定在设定值附近、阀门动作是否频繁。内环稳定了,再让主环闭环,从很小的外环P开始,慢慢加。
我当时踩过一个坑:觉得串级高级,直接两个环同时投,结果回风温度出现周期五分钟的大幅振荡,整个车间的空调像是在“呼吸”。后来拆开一测,发现副环的PID在阀门行程超过两分钟的场景下,积分时间给得太短,副环自己就在振荡。先把副环P降到1.2、积分时间升到三分钟,振荡才消掉。所以别跳步骤,内环不稳,外环一定炸。
5.2 阀门执行器响应慢引发的“假振荡”
比例积分调节阀的执行器行程时间一般在30秒到3分钟不等。程序扫描周期是几十毫秒,如果PID输出0.1%的微小变化,执行器根本来不及响应,但PID觉得“阀没动”,于是继续积分。等执行器终于走完这0.1%,阀位可能已经过头了,温度一下子冲过设定值,形成一种频率很低但振幅很大的假振荡。
这个问题单靠PID参数很难完全解决。我后来在程序里加了两层处理:一是PID输出变化率限制,两个扫描周期之间输出变化超过某个阈值才更新阀门指令;二是给PID输出加了一阶惯性滤波,时间常数按执行器行程时间的五分之一左右设置。这样PID就不会对着一个慢吞吞执行器猛追猛打。这个方法虽然牺牲了一点响应速度,但换来了稳定,医药空调场景完全值得。
5.3 传感器安装位置会直接决定串级效果
回风温湿度传感器的安装位置如果太靠近门、回风口或者直吹空调箱回风柱,数据会带明显的局部波动,主环就会跟着乱动。送风温湿度传感器要放在风机均流段之后、送风管道足够长的直管段上,不能紧贴加湿段出口,否则蒸汽还没混合均匀,湿度传感器读数会剧烈跳动。
有一次调试,送风湿度曲线高频毛刺特别明显,PID输出也跟着抖。我一开始还以为是PID参数问题,后来到现场一看,湿度传感器就装在加湿段后面不到一米的地方,蒸汽喷出来直接打在探头上。把传感器挪到均流段后两米左右的直管段,曲线马上平了。所以调试时我习惯先连续记录一个小时的回风、送风温湿度曲线,看看有没有明显毛刺,有就先把传感器和安装位置的问题解决,再谈PID参数。
6. 方案扩展:值班模式、Modbus通讯与平台升级
6.1 夜间值班模式与变设定值
串级PID搭好之后,扩展节能逻辑会方便很多。医药厂房夜间不生产时,洁净室不一定完全关机,一般切到值班模式,保持正压和基础洁净度。我在结构体的设定区里做了两套设定值:正常生产设定值和值班设定值,再通过时间表自动切换。切换时主环SP会变化,副环自动跟踪,不需要改任何PID接线。操作员在触摸屏上还能手动微调值班值,用起来很顺手。
这套做法本质上是把串级控制的设定值“变成变量”,而不是把PID参数改来改去。只要主副环参数整定合理,变设定值不会引起大的波动,这也是串级结构相对单回路的一大优势。
6.2 Modbus把结构体数据送给上位机
S7-200 SMART本身支持Modbus RTU和Modbus TCP库。用结构体变量规划的好处在这里体现得很明显:我可以把AHU1到AHU5的所有输入区、状态区、报警区连续放在一段V区里,Modbus从站地址表按偏移量生成,上位机组态只要按同一张偏移表一次性读取,不需要一个点一个点去对地址。
这里要提醒:结构体成员的偏移不是想当然的连续字节,不同类型存在对齐规则。我在做Modbus地址表时,一定要先在软件里查看交叉引用生成的变量地址,再回填到上位机组态里。有的是因为想当然算偏移,结果某一位对不齐,整块数据都读乱。这个习惯算是从这个问题里养成的。
6.3 向S7-1200/1500迁移的思路
如果项目后续要扩容,点数超过200 SMART的能力,或者需要使用更专业的PID功能块,把这里的控制思路迁移过去并不难。高端平台的PID功能支持直接填工程值、自带手自动无扰切换,串级结构在程序里也更容易组织。结构体变量迁移过去就是更成熟的UDT加全局数据块,使用体验比在200 SMART上顺畅得多。
迁移之前,建议先把控制策略部分整理成一份文档,包括主环副环对应关系、量程变换公式、分程死区、手自动切换条件。换平台最大的坑不是语法,而是控制逻辑没有固定下来。先文档,后编码,永远是这种迁移项目最稳的做法。
最后分享一个自己常用的习惯:每次调完一遍串级PID,我都会把回风温度、送风温度、回风湿度、送风湿度的历史曲线导出保存,同时在结构体里留一块PID参数备份区。后面环境变化导致控制不稳定时,不用从头盲目试参,直接把备份参数调出来对比,往往几分钟就能判断是参数漂了还是执行机构出了问题。串级PID和结构体变量都不是新技术,但在S7-200 SMART这个平台上把它们用好,医药空调箱的稳定性问题真能解决大半。