
供水压力忽高忽低、高峰用水时水压上不去、泵房里的工频泵却还在满负荷傻转这是绝大多数恒压供水改造项目立项时的真实状态。恒压供水一拖三系统简单说就是一台变频器拖三台水泵电机根据管网压力自动调节频率并在一台泵不够用时自动切入下一台泵把出水压力稳定在设定值附近。这篇文章我会从整套系统的架构设计开始讲逐步拆解控制策略最后落到可运行的代码实现上。内容适合正在做供水自动化项目、或者准备用PLC/单片机自研泵控系统的工程师参考。1. 一拖三这套系统到底在解决水压的哪个痛点在做任何技术方案之前先把“为什么要这么干”想清楚比急着画电路图重要得多。恒压供水的本质是用水量随时在变而我们希望管网出口压力保持恒定。1.1 为什么行业里普遍选“一拖三”而不是“三拖三”先解释一个最常被问到的问题为什么非要“一拖三”给每台泵都配一台变频器不就行了从控制原理上说三台泵各配一台变频器确实能做更灵活的调节比如三泵同时变频运行分摊流量。但实际工程里很少这么干原因很直接成本高。一台同功率变频器的价格摆在那里一拖三只需要一台变频器三拖三至少三台电气柜体积、发热量、谐波治理成本全部跟着涨。没必要。恒压供水场景下绝大多数时间只要一台泵变频运行就够用。只有高峰时段才需要第二台、第三台泵投入而额外的泵投入后基本运行在工频状态靠变频泵做细调。维护简单。一拖三的故障点更少变频器坏了直接切到检修模式人工工频运行也能临时供水。所以一拖三本质上是“一台变频器做无级调速其余泵做有级投入”的经济型方案。当然也有限制任何时刻只能有一台泵接在变频器输出端泵组切换时变频器需要先停机再切换接触器这个过程是几十毫秒的瞬时断开实际对供水压力影响不大因为电机惯性还在。1.2 系统必须满足的工况边界与设计指标一拖三系统的边界条件通常在方案阶段就要定清楚否则后面调试会反复扯皮。我一般会先列这几项流量需求单台泵额定流量、最大需水量、最小夜间流量。这决定了一台泵变频运行能不能覆盖整个流量区间。扬程与压力设定最高楼栋高度、最不利点所需自由水头换算成泵出口压力设定值。常见居民小区设定在0.40.6MPa。电机参数每台泵的额定功率、额定电流、额定转速。变频器选型按电机功率放大一档比较稳妥。切换时间要求从加泵到压力恢复允许的时间。一般要求20秒内压力不跌出设定值20%。休眠条件夜间小流量时要不要自动停机这涉及后面的休眠逻辑。把这些参数定下来后面所有代码和PID整定才有依据。很多项目翻车不是因为控制逻辑复杂而是边界条件一开始就没定清楚。2. 从主回路到信号链硬件架构与选型思路一拖三系统的硬件架构可以拆成三块看主回路负责电能传输和泵组切换控制回路负责逻辑判断和信号处理信号链负责采集压力、频率、运行状态。2.1 主回路变频器加接触器组的切换逻辑主回路的经典做法是三相电源先进总开关经过变频器后接到三个变频接触器KM1、KM3、KM5分别对应1号、2号、3号泵。同时三台泵还有各自的工频接触器KM2、KM4、KM6直接接在电源上。这套结构的关键在于互锁同一台泵的变频接触器和工频接触器必须电气互锁绝对不能同时吸合否则变频器输出和工频电源会“撞车”轻则跳闸重则炸变频器。不同泵的变频接触器之间也必须互锁确保同一时刻只有一台泵接在变频器输出端。工频接触器之间可以同时吸合因为多台泵工频并联运行本来就是加泵的最终状态。以常见的加泵流程为例当1号泵变频运行频率升到上限仍不能维持压力时先把1号泵退出变频然后2号泵的变频接触器吸合让2号泵变频启动同时1号泵工频接触器吸合转为工频运行。这样变频器一直带一台泵已投入的泵稳定工频运行。从安全角度我强烈建议在PLC程序里做软件互锁之外接触器线圈回路里还要串常闭触点做硬件互锁。软件逻辑再完善总有CPU死机的时候硬件互锁是最后一道防线。2.2 信号链压力采集、PID输出与运行状态检测恒压供水最核心的传感器就是压力变送器。常见配置是两线制4-20mA输出的压力变送器量程01.6MPa供电DC24V接到PLC的模拟量输入模块。信号链有一个容易被忽略的细节压力变送器安装位置。一般装在出水总管上要避开泵出口直吹的位置否则测得的是动压而不是静压压力波动会很大。我见过一个项目把测压点装在泵出口1米处PID怎么调都振荡最后把取压点挪到总管末端问题立刻消失。除了压力信号建议采集以下信号变频器频率反馈确认实际输出频率判断是不是到了上限/下限。变频器运行状态、故障状态干接点信号用于联锁和报警。每台泵的工频运行接触器反馈确认接触器真的吸合了。水流开关或流量计用于休眠判断避免低压小流量时误加泵。PID输出通常是模拟量信号常见的是4-20mA或0-10V接到变频器频率给定端子对应050Hz。PLC的PID块输出0100%最后要换算成对应的模拟量值。2.3 控制器选型PLC、泵控一体机还是单片机我接触过的项目里控制器有三类主流选择PLC比如西门子S7-200 SMART、三菱FX系列最灵活代码可维护性最好适合需要自定义逻辑、后期要扩展通讯的项目。我自己的项目大多数走这条路线。泵控一体机如施耐德Altivar配套泵控卡、专用供水控制器内置恒压供水逻辑参数化配置就能用省去了大量编程。适合标准场景、施工周期紧的项目但定制能力弱。单片机/嵌入式板卡成本最低适合产品化、批量化的设备比如小型一体式供水机组。自己从头写代码对数字滤波、PID、状态机都要有足够功底。如果你只是想快速交付一个标准项目直接用泵控一体机。如果你想在技术上形成自己的产品和积累PLC或者单片机方案更值得投入后面控制逻辑能完全按照自己思路来。这篇博文接下来的代码部分我采用“PLC结构化文本为主嵌入式C为辅助”的方式来讲原因是这两种语言的读者覆盖最广。3. 控制策略拆解恒压调节、加减泵判据与泵组轮换硬件架构搭好之后真正的灵魂在于控制策略。一拖三的逻辑核心可以拆成四块PID恒压调节、加泵判据、减泵判据、泵组轮换。3.1 恒压调节中的PID工程化处理PID是恒压供水的核心闭环。直接套用教科书公式往往不行工程上必须做几处处理设定死区。压力在设定值±0.010.02MPa范围内时PID输出保持不变避免变频器频率因为微小波动来回调整。死区太小等于没有太大又会让压力偏离明显一般按量程的0.5%1%设置。输出限幅。PID输出必须限制在0100%以内对应变频器050Hz。注意很多变频器在低频段5Hz以下输出力矩不足所以下限不要给0我给的是10%20%510Hz。抗积分饱和。当PID输出到达上限且误差仍然为正压力不够积分项必须停止累加到达下限且误差为负时同样要停。否则压力恢复过来后积分项还滞留在高位系统会持续超调。微分项慎用。供水系统惯性大、滞后大微分项对噪声敏感容易引出振荡。绝大多数恒压供水场景PI就够用了微分项保持为0。PID采样周期建议0.10.5秒不宜太快。供水管道从泵出口到测压点有一定距离信号本身有滞后采样太快反而让控制器对管道噪声更敏感。3.2 加减泵“什么时候切”比“怎么切”更重要加减泵判断是恒压供水里最容易出问题的地方。切早了高峰刚来就多开一台泵之后流量回落又得减泵系统在加泵/减泵之间反复震荡切晚了压力掉得太多用户已经感知到水小了。我的经验是以“频率超限持续时间”为判据而不是以压力偏差为单一判据。加泵判据当前泵变频运行频率已经到达上限比如49Hz避免真到50Hz触发变频器过载且持续超过2030秒同时实测压力仍低于设定值0.05MPa以上则执行加泵。减泵判据当前有两台或以上泵在运行变频泵频率已经跌到下限比如25Hz且持续超过3060秒同时压力仍高于设定值0.05MPa以上则执行减泵。这里的“持续”非常重要。因为管网压力波动是渐变过程单瞬间满足条件就动作很容易被瞬时扰动骗过去。我习惯用TON定时器累计时间到了才确认。加泵延时比减泵延时短因为从用户体感来说压力不足要尽快响应而压力偏高多耗一点电可以容忍。加减泵切换有一个关键细节切换顺序。以从1台泵切到2台泵为例1号泵变频运行先断开KM11号泵离开变频器。稍作延时吸合KM32号泵接入变频器变频器按当前频率输出启动2号泵同时吸合KM21号泵工频运行。PID重新接管变频器带2号泵做闭环调节。这个顺序的意义是变频器永远带一台在线泵不会出现变频器空载或同时带两台泵的情况。工频泵一旦启动就是满转速不参与频率调节。3.3 轮换策略与休眠功能的必要性一拖三系统里如果每次都优先启动1号泵那1号泵的磨损会远大于另外两台。所以必须有轮换策略常见的做法有按累计运行时间轮换记录每台泵的累计运行时间新一次启动时优先选运行时间最短的泵。按启动次数轮换让每台泵的启动次数接近适合频繁启停的场景。定期主备切换比如每天零点自动切换主泵适用于长期稳定运行的泵站。我倾向用“累计运行时间优先”为主同时叠加故障泵切出功能。这样既均衡磨损又能保证轮换规则的确定性。休眠功能也值得做。夜间用水量极低时一台泵在10Hz以下运行大部分能量都浪费在阀门和管道阻力上。这时候可以判断压力持续偏高、流量低于某个阈值让所有泵停机利用稳压罐维持管网压力。当压力跌到休眠恢复值比如设定值-0.1MPa时再自动启动一台泵变频运行。4. 代码落地结合状态机写出一套可维护的控制程序讲完策略进入代码环节。我会用两种方式展示一种是PLC上常见的结构化文本ST一种是嵌入式C语言。两者的核心逻辑完全一致都是状态机模型。4.1 结构化文本ST实现的泵组控制主程序假设使用支持ST的PLC西门子S7-1200/1500、施耐德M241、国产汇川/信捷等都支持程序框架如下VAR bAutoMode : BOOL; // 自动/手动模式 rPressure : REAL; // 当前压力单位MPa rSetpoint : REAL : 0.5; // 压力设定值单位MPa rPIDOut : REAL; // PID输出 0~100 stPumpRunTime : ARRAY[1..3] OF TIME; // 各泵累计运行时间 bPumpFault : ARRAY[1..3] OF BOOL; // 各泵故障标志 bFreqKM : ARRAY[1..3] OF BOOL; // 变频接触器 bLineKM : ARRAY[1..3] OF BOOL; // 工频接触器 iState : INT : 0; // 状态机0停止1单泵变频2两泵运行3三泵运行4休眠 iActivePump : INT : 1; // 当前变频泵编号 iLinePumps : INT : 0; // 当前工频泵数量 nStartOrder : ARRAY[1..3] OF INT; // 泵启动顺序 tOverTimer : TON; // 频率超上限计时 tUnderTimer : TON; // 频率低于下限计时 tSwitchDelay : TON; // 切换延时 END_VAR主控制循环每100ms执行一次IF NOT bAutoMode THEN // 手动模式直接按面板按钮控制跳过自动逻辑 iState : 0; RETURN; END_IF // PID运算采用带死区和输出限幅的PI算法 rPIDOut : PID_Calculate( setpoint : rSetpoint, actual : rPressure, kp : 5.0, ti : 10.0, dt : 0.1, deadband : 0.01, minOut : 10.0, maxOut : 100.0 ); // 变频器频率给定 FreqSet : rPIDOut * 0.5; // 0~100% 对应 0~50Hz CASE iState OF 0: // 停止状态 IF rPressure rSetpoint - 0.05 THEN // 压力不足启动优先级最高的泵 iActivePump : nStartOrder[1]; iState : 1; END_IF 1: // 单泵变频运行 // 判断是否需要加泵 IF FreqSet 49.0 AND rPressure rSetpoint - 0.05 THEN tOverTimer(IN : TRUE, PT : T#20S); IF tOverTimer.Q THEN // 执行加泵先切出当前变频泵再投入下一台泵变频当前泵转工频 bFreqKM[iActivePump] : FALSE; tSwitchDelay(IN : TRUE, PT : T#500MS); IF tSwitchDelay.Q THEN iLinePumps : 1; bLineKM[iActivePump] : TRUE; iActivePump : nStartOrder[2]; bFreqKM[iActivePump] : TRUE; tOverTimer(IN : FALSE); iState : 2; END_IF END_IF ELSE tOverTimer(IN : FALSE); END_IF // 判断是否需要休眠 IF FreqSet 12.0 AND rPressure rSetpoint 0.05 AND FlowRate 0.5 THEN // 小流量休眠关闭所有泵 bFreqKM[iActivePump] : FALSE; iState : 4; END_IF 2: // 两泵运行一台变频、一台工频 IF FreqSet 49.0 AND rPressure rSetpoint - 0.05 THEN // 继续加泵 iLinePumps : 2; bLineKM[nStartOrder[2]] : TRUE; iActivePump : nStartOrder[3]; bFreqKM[iActivePump] : TRUE; iState : 3; ELSIF FreqSet 25.0 AND rPressure rSetpoint 0.05 THEN tUnderTimer(IN : TRUE, PT : T#30S); IF tUnderTimer.Q THEN // 减泵当前变频泵退出工频泵转变频 bFreqKM[iActivePump] : FALSE; iActivePump : nStartOrder[1]; bFreqKM[iActivePump] : TRUE; bLineKM[nStartOrder[1]] : FALSE; iLinePumps : 0; tUnderTimer(IN : FALSE); iState : 1; END_IF ELSE tUnderTimer(IN : FALSE); END_IF 3: // 三泵运行 IF FreqSet 25.0 AND rPressure rSetpoint 0.05 THEN // 依次减泵 bLineKM[nStartOrder[2]] : FALSE; iLinePumps : 1; bFreqKM[iActivePump] : FALSE; iActivePump : nStartOrder[1]; bFreqKM[iActivePump] : TRUE; bLineKM[nStartOrder[1]] : FALSE; iState : 2; END_IF 4: // 休眠状态 IF rPressure rSetpoint - 0.1 THEN // 压力跌破恢复值重新启动 iActivePump : nStartOrder[1]; bFreqKM[iActivePump] : TRUE; iState : 1; END_IF END_CASE这段代码是核心框架实际项目里还需要补充故障处理、接触器反馈校验、手动/自动切换的平滑过渡等。但只要你理解了状态怎么流转这些细节就只是填坑而已。4.2 用C语言实现嵌入式精简版的加减泵逻辑如果你用的是单片机方案STM32、GD32这类核心逻辑同样可以用状态机实现。下面给一个精简但可运行的C代码框架typedef enum { SYS_STOP 0, SYS_RUN_SINGLE, SYS_RUN_DUAL, SYS_RUN_TRIPLE, SYS_SLEEP } sys_state_t; typedef struct { float setpoint; float pressure; float freq; float pid_out; uint8_t active_pump; // 0/1/2 uint8_t line_count; // 工频泵数量 sys_state_t state; uint32_t timer_over; // 加泵计时 uint32_t timer_under; // 减泵计时 } pump_ctrl_t; void pump_ctrl_run(pump_ctrl_t *pc, uint32_t tick_ms) { // PID计算略见4.3节 // 频率判断加泵上限49Hz减泵下限25Hz switch (pc-state) { case SYS_STOP: if (pc-pressure pc-setpoint - 0.05f) { pc-active_pump 0; freq_kms_on(pc-active_pump); pc-state SYS_RUN_SINGLE; } break; case SYS_RUN_SINGLE: if (pc-freq 49.0f pc-pressure pc-setpoint - 0.05f) { if (check_continue(pc-timer_over, 20000)) { // 持续20秒 freq_kms_off(pc-active_pump); line_kms_on(pc-active_pump); // 当前泵转工频 pc-active_pump 1; freq_kms_on(pc-active_pump); // 2号泵变频启动 pc-line_count 1; pc-state SYS_RUN_DUAL; reset_timer(pc-timer_over); } } else { reset_timer(pc-timer_over); } // 休眠判断 if (pc-freq 12.0f pc-pressure pc-setpoint 0.05f flow_rate 0.5f) { freq_kms_off(pc-active_pump); pc-state SYS_SLEEP; } break; // 其他状态类似此处省略 } }这里freq_kms_on、line_kms_on是接触器驱动函数内部一定要做互锁判断void freq_kms_on(uint8_t pump) { // 先关所有工频接触器再开目标变频接触器 for (int i 0; i 3; i) line_kms_off(i); for (int i 0; i 3; i) freq_kms_off(i); // 延时几毫秒确保接触器完全断开 delay_ms(50); // 开目标泵的变频接触器 gpio_write(FREQ_KM[pump], 1); }这种“先全关、再开目标”的做法能最大限度避免互锁风险代价是切换时有几十毫秒所有接触器都断开实际运行中完全可接受。4.3 PID代码的手写要点与防积分饱和处理很多小型PLC没有内置PID指令或者内置PID块的可调参数不够灵活这时候就需要手写PID。位置式PID适合这类慢速对象代码很简单typedef struct { float kp; float ti; // 积分时间秒 float td; // 微分时间秒 float dt; // 采样周期秒 float deadband; // 死区 float out_min; float out_max; float integral; float last_err; } pid_t; float pid_calc(pid_t *pid, float setpoint, float actual) { float err setpoint - actual; float out; // 死区 if (fabsf(err) pid-deadband) { err 0.0f; } // 积分项带抗饱和 pid-integral (err * pid-dt); // 输出预计算 out pid-kp * err (pid-kp / pid-ti) * pid-integral; // 抗积分饱和 if (out pid-out_max) { out pid-out_max; pid-integral - (err * pid-dt); // 不累加积分 } else if (out pid-out_min) { out pid-out_min; pid-integral - (err * pid-dt); } pid-last_err err; return out; }很多人会忽略初始化问题程序启动瞬间integral要先清零否则设备重启后PID会先猛冲一段。另外一个经验是在自动模式切换的瞬间把当前PID输出作为手动值送出去然后再切入自动做到无扰切换。执行方式是停机时用固定频率如30Hz手动给定变频泵启动后先按当前输出值接管再把PID切入闭环。5. 联调过程与典型故障排查代码写完了接下来是最磨人的联调阶段。这部分我总结成“参数整定”和“故障排查”两小节都是现场最容易踩的坑。5.1 参数整定的顺序和实用办法PID参数整定不需要高深理论现场用工程方法就能调好。我的习惯是先手动开环验证。用面板或程序强制变频器输出一个固定频率比如35Hz观察压力稳态值。确认传感器、变频器、管道都正常。把PID设置为纯比例控制Ti极大Td0Kp从2左右开始调。逐渐加大Kp直到压力出现等幅振荡记下此时的Kp临界增益Ku和振荡周期Tu。用经验公式给出初始参数Kp0.45KuTi0.85Tu。这是齐格勒-尼科尔斯整定法里的典型参数对大多数供水场景是个很好的起点。微调。如果超调大加大Ti或适当减小Kp如果响应慢减小Ti。供水系统允许一定超调但绝不能长时间振荡。我做的几个项目最终参数大致在Kp38、Ti820秒的取值范围具体还要结合管道长度、泵的功率来定。管道越长滞后越大Ti就要越大。5.2 现场最常见的三个毛病及排查链路问题一压力来回振荡频率一直波动停不下来。排查链路先看PID参数是否太激进Kp减半试一次。如果还振荡看压力变送器信号是否干净用万用表量4-20mA信号里有没有叠加高频干扰必要时在PLC模拟量通道加数字滤波比如一阶惯性滤波。再看取压点位置是否合理离泵太近的信号本身就跳。问题二频繁加泵减泵一天之内几十次切换。这个问题十有八九出在判据窗口设置上。压力设定值0.5MPa加泵条件是频率49Hz持续20秒减泵条件是频率25Hz持续30秒窗口重叠得非常小系统很敏感。解决方法是把减泵频率下限从25Hz降到20Hz或者把减泵延时拉长到60秒。增加滞回区间给系统留缓冲。问题三加泵瞬间压力暴跌甚至触发缺水保护。加泵瞬间当前泵从变频切出、下一台泵变频投入中间有短暂失速如果泵的出口止回阀动作不灵敏压力确实会掉。排查时先看切换时序有没有问题必须先断开当前变频接触器再吸合目标泵变频接触器顺序不能反。如果顺序没问题问题通常在止回阀。可以给切换动作加一个补水缓冲在加泵前把PID输出预先抬到80%以上让当前泵先把压力冲上去一点再切换。5.3 用水厂的视角看这套系统还能怎么优化恒压供水一拖三做完基本功能只是起步。从运维角度看还有几个值得做的优化点远程监控。给PLC加一个以太网模块或者4G DTU把压力、频率、泵状态、故障报警、累计运行时长传上去。无人值守泵站最需要这个。趋势记录。记录24小时压力曲线和泵启停次数对泵组健康度评估非常有用。故障自恢复。某个泵故障后自动把它从轮换队列里摘除用剩下的泵继续维持供水不能因为一台泵坏了整个系统瘫掉。电动阀联动。如果出水口有电动阀加泵时先把电动阀打开到一定开度再启动工频泵减少水锤冲击。这些优化单拎出来每一项都不复杂但组合起来就是一套完整的产品级系统。6. 用“运维视角”再看系统设计最后说一点我跑了几年维护之后的体会也是最容易被研发阶段忽略的东西。现场维护人员不会看代码他们打开柜门看到的是接触器和端子排。所以无论PLC程序写得多优雅都要在柜门上贴一张清晰的运行状态指示灯图哪个灯亮代表几号泵在变频、几号泵在工频、哪个故障灯亮了该查哪里。这比任何技术文档都管用。另外强烈建议把轮换策略做成可配置项而不是写死在代码里。每个水厂的用水习惯不一样有的白天高峰明显、夜里几乎断流有的全天流量都很平均。轮换时间、休眠恢复压力、加泵延时这些参数最好都放到触摸屏或上位机的参数页里让维护人员能直接修改而不是每次都要重新下载程序。恒压供水一拖三项目技术上并不算难真正决定项目成败的往往是对细节的态度接触器互锁有没有做双保险、加泵判据有没有留滞回、压力取压点选在哪儿、PID积分有没有做抗饱和。把这些点逐一落实系统稳定运行只是时间问题。