模型预测控制在楼宇负荷响应与热储存系统中的应用实践

发布时间:2026/10/18 23:19:12
模型预测控制在楼宇负荷响应与热储存系统中的应用实践
每年夏天最热的时段基于模型预测控制的楼宇负荷响应与热储存系统就成了能耗管理领域绕不开的话题电价在峰谷之间跳动冷机能不能少开、蓄冷罐该怎么配合、房间温度会不会越界这些老问题突然都有了系统性解法。某园区办公楼的运维主管曾在下午三点对着尖峰电价发呆——谷段0.35元一度峰段1.15元一度冷机却不得不满功率运转。这栋楼不是没有蓄冷罐也不是不想做需求响应真正卡住他的问题是没人能靠经验说出明天早上该预冷几小时、蓄冷罐要蓄到几成、下午到底敢不敢把冷机压下来。我这两年一直在做楼宇能源控制方面的项目从规则表改到模型预测控制再把蓄冷加进来前后迭代了好几版踩的坑比收获的成果印象更深。下面我按建模、优化设计、代码实现、调试踩坑这个顺序把这套系统的完整思路摊开讲。适合正在做楼宇能源管理、需求响应、储能运行控制的研究生和工程师参考就算你暂时不写代码读完也能理解为什么MPC在这个场景下比规则控制靠谱得多以及上线一套这样的系统大概要准备哪些东西。1. 楼宇负荷响应的问题本质为什么“预冷两小时”这种经验做法不够用1.1 需求响应不缺麻烦缺的是把麻烦算清楚的方法先说说背景。楼宇在电网需求响应里扮演的角色其实很简单电价高或者电网紧张的时候多省电电价低或者电网宽松的时候多用电。整栋楼里最大的可控对象就是暖通空调尤其是电驱动冷机能占到楼宇总用电的40%~60%。热储存系统蓄冷罐、蓄热水箱在这里的意义就是给冷机加了一个“仓库”——低谷电价时段多产冷存起来峰段少产甚至不产靠存着的冷量把室内温度压住。这个思路听着直白做起来却是个组合优化问题。楼宇本质是一个热惯性非常大的对象白天太阳辐射、设备散热、人员活动都会让热量持续进逼冷机负责把这些热量“抽”走。问题是热量什么时候进来、进来多少每个小时都不一样电价每隔一小时可能就换一档冷机功率、蓄冷罐容量、舒适温度范围又全都有硬边界。一句话概括这是一个“多变量、带约束、有预测信息可用”的控制问题而这种问题恰恰是传统人工经验和简单规则表处理不好的。1.2 传统规则控制的软肋我见过很多实际项目用的是规则表rule-based凌晨4点开始预冷把室温拉到22度上午9点以后冷机降到30%功率下午高峰直接停机靠蓄冷罐顶着。好处是简单、不用建模、运维师傅也容易理解。坏处同样明显预冷时间固定遇到第二天阴天或下雨冷得过头白白浪费电蓄冷罐放完就没了一旦下午温度反弹超过舒适上限只能临时开机峰段照样用电完全不看电价曲线的形状。比如午间平段和下午峰段的价差明明可以利用规则表里却没有“什么时候该多充一点、什么时候该少用一点”的逻辑。换句话说规则控制的本质是开环控制。它把“未来会怎样”这份最有价值的信息丢掉了只盯着当前时刻做判断。短期看问题不大但只要峰谷价差拉开、蓄冷罐容量变大、需求响应事件变多这种做法的天花板就会很快撞到。1.3 MPC的思路把调度问题变成滚动求解的优化问题模型预测控制Model Predictive ControlMPC换了一个玩法。它每时每刻都在干三件事用模型预测未来一段时间比如24小时的系统状态在这个预测的基础上求解一个带约束的优化问题得到未来每一步的最优动作但真正执行时只取第一步等下一个采样时刻到了把实测状态拿回来重新预测、重新优化再执行第一步。这就是常说的“滚动时域receding horizon”。“只执行第一步”这个细节非常关键。因为所有预测都有误差模型也不可能100%精确与其把一整天的调度计划一次性锁死不如每隔一小时修正一次让控制器始终贴着真实状态走。反馈校正这个动作正是MPC区别于“提前算好一天计划再照做”的离线优化调度的核心差异。从控制理论角度讲MPC最大的价值是天然支持约束。室温不许超过26度、蓄冷罐不许超容量、冷机功率不许超过上限这些在MPC里都是优化问题的不等式约束而不是事后补救的if-else。理解了这一点你就能明白为什么这个场景几乎是为MPC量身定做的。下面就从最基础的建模说起——优化算得再漂亮模型不准一切都是白搭。2. 热储存与建筑热动态建模把物理系统翻译成优化问题2.1 RC等效热模型把楼宇当成一块会“充放电”的电池MPC要用的模型不需要像CFD仿真那么精细关键是抓住热惯性这个主导动态。学术界和工业界最常见的做法是RC等效模型——把热阻R类比成电阻热容C类比成电容房间温度类比成电压热量流类比成电流。这个类比非常实用因为电路分析里那些成熟的理论可以直接搬过来用。对单区域或者把整层楼聚合成一个区域来说热平衡方程可以写成C·dT/dt (T_out − T)/R Q_internal − Q_hvacT是室内温度T_out是室外温度Q_internal是人员、设备、光照产生的被动热量Q_hvac是冷机送进房间的冷量。这个一阶模型的物理直觉是楼宇的热容C越大温度越“惰性”这也是预冷和蓄冷能起作用的前提。为什么商场、医院这类大体量公共建筑特别适合做热储存响应就是因为它们的等效热容大短时间停机温度也不会立刻飙上去。2.2 离散化与参数确定模型预测控制里用的是离散时间方程。采样周期一般取15分钟到1小时为了覆盖完整电价周期又能控制计算量我的习惯是1小时采样、24步预测时域。用零阶保持假设每个采样周期内输入恒定做离散化上面的微分方程就变成T(k1) a·T(k) b·(Q_internal − Q_hvac) c·T_out(k)其中a exp(−dt/(R·C))b R·(1−a)c 1−a。别小看这三个系数它们决定了模型的“性格”。比如一栋中等规模的办公楼等效热容C取500 kWh/K热阻R取0.02 K/kW时间常数R·C就是10小时一小时采样下a≈0.905。意思是房间温度在一小时内只会向室外温度方向自行靠近9.5%剩下90.5%靠自身惯性撑着。热惯性越大预冷越划算。参数从哪来两个途径一是从建筑图纸和材料表估算R和C快但粗糙二是拿历史运行数据做最小二乘辨识准但费事。我的建议是两条路都走——先用估算值把控制器框架跑通再收集两周的冷机功率、室内外温度数据做参数校准交叉验证后更新进模型。不要迷信任何一边实测数据永远是最终裁判。2.3 蓄冷罐的状态方程蓄冷罐就好比楼宇的“电量”不过存的是冷。用一个状态量S(k)表示罐内剩余冷量kWh动态方程是S(k1) S(k) η_charge·COP·P_ch(k) − Q_disc(k)/η_disc这里有两个效率要特别注意。充能效率η_charge是冷机造出来的冷打进罐里的损失放能效率η_disc是从罐里取冷供到房间的损失通常都在0.85~0.95之间。COP是冷机能效比代表一度电能制多少冷取3.5是比较常见的值。P_ch是充电耗电功率kWQ_disc是放能侧的热功率kW。除了动态方程蓄冷罐还有一组运行约束罐容量上限S_cap、最大充放电功率、SOC不允许为负。做日循环调度时我还会加一个“当天结束罐内排空”的约束也就是S(N)0避免把成本悄悄挪到第二天。如果你的目标函数和电价周期设计得允许跨天搬移电量这个约束可以适当放宽但第一版建议还是加上逻辑更干净。2.4 状态空间形式的完整拼装把建筑温度T、罐内冷量S拼成状态向量x [T, S]把冷机直接供冷功率P_cool、充电功率P_ch、放能功率Q_disc拼成控制向量u再把室外温度T_out和被动冷负荷Q_base当成外部输入整个系统就变成一个线性状态空间模型x(k1) A·x(k) B·u(k) E·d(k)这一步的意义不只是形式上好看。线性状态空间模型可以直接丢给凸优化求解器把一个看似复杂的楼宇调度问题转成每秒都能算完的线性规划问题。这也是我坚持用线性模型而不是神经网络黑箱模型的根本原因——可解释、可求解、可在线运行。神经网络模型做预测可以但放在控制回路里可解释性和实时性都会让你头疼。3. 目标函数与约束设计在省电费、保舒适、不超功率之间找平衡3.1 目标函数把“买电”变成可计算的成本MPC的“最优”必须有明确度量。楼宇负荷响应场景里最自然的度量就是全天电费J Σ_{k0}^{N−1} price(k)·P_grid(k)其中P_grid(k) P_cool(k) P_ch(k) P_other(k)price(k)是分时电价或实时电价P_other是照明、插座这类非可控负荷。这个目标函数一写出来蓄冷的套利逻辑就很清楚了谷段电价低让冷机多产冷存入蓄冷罐峰段电价高让罐子放冷代替冷机运行。我算过一笔很直观的账一个600 kWh的蓄冷罐假设COP3.5、放能效率0.9峰段放出600 kWh冷量相当于省了600/3.5/0.9≈190度电按峰谷价差0.8元/度算理论日收益约150元。当然充能环节也有损耗实际能捞回七八成一个制冷季下来对电费的影响非常明显。前提是调度策略真能把每次充放都安排在正确的时段这正是MPC要解决的核心问题。有时目标函数还要加项。比如楼宇合同里有需量电费按当月最大需量kW计费那就要在目标或约束里考虑峰值功率。我一般把目标改成“电费λ·峰值功率”或者干脆把P_grid≤P_cap写成约束。再比如舒适度严格的22~26度硬约束在极端天气下可能导致无解这时候我会引入松弛变量让温度可以轻微越界但每超过1度罚一笔钱比如0.5元/℃·h。这样目标函数从纯LP变成带惩罚项的权衡问题工程上稳健得多。3.2 预测时域与控制时域取多长才合适预测时域N的选择基本取决于三件事电价/需求响应信号的周期、蓄冷罐能撑多久、以及天气和负荷预测的有效精度。如果只做日内调度N取24小时级采样最自然正好覆盖一天内峰谷平的完整循环如果蓄冷罐容量大到能跨天搬移电量N要延长到48甚至72小时如果当地执行实时电价每15分钟变化一次采样周期压缩到15分钟N取96步同样覆盖24小时。控制周期和采样周期取一致即可不需要单独设更细的控制时域。楼宇热过程慢1小时一级的更新频率已经足够。采样太细反而会让蓄冷罐充放动作过于频繁阀门和压缩机启停寿命会受影响运维也会抱怨。3.3 约束条件哪些必须硬哪些可以软我整理了一张常用的约束表按“物理硬约束”和“可软化约束”分类第一版照着抄基本不会错约束项数学表达硬/软说明室温舒适范围T_min ≤ T(k) ≤ T_max软加惩罚硬约束在极端天气下容易导致无解蓄冷罐容量0 ≤ S(k) ≤ S_cap硬超出物理极限绝对不允许蓄冷罐日清S(N) S_0可适度放宽防止成本跨日转移冷机功率上限P_cool P_ch ≤ P_c_max硬设备铭牌决定充放电功率0 ≤ P_ch ≤ P_ch_max0 ≤ Q_disc ≤ Q_disc_max硬泵、阀、换热器限制需量限制P_grid(k) ≤ P_peak可软与合同电费相关越界用惩罚代替硬拒有个很常见的坑把舒适度写成硬约束后一旦天气预测偏了几度或者某个小时冷负荷突然升高整个优化问题就会无解infeasible控制器当场“罢工”。改成软约束加惩罚项之后即便出现极端情况求解器也会找到一个温度略微越界但其余指标都可接受的方案。对工程运行来说一个可执行的非最优解永远比一个无法执行的“最优解”有价值。3.4 为什么线性规划够用不要急着上非线性很多研究者一上来就想把冷机COP建模成功率相关的非线性函数甚至用混合整数规划处理设备启停。我的观点是第一版MPC坚决用LP。理由很实在楼宇热过程的时间常数以小时计采样周期1小时的情况下模型误差才是主导因素COP在部分负荷段的波动对优化结果的影响经常被其他误差淹没。而LP求解是确定性的、毫秒级、数值稳健便于快速上线验证。等你有充足的历史数据、明确的非线性痛点比如冰蓄冷的结冰融冰曲线再逐步升级成QP或混合整数MPC不迟。工程上讲究“够用就好”先跑起来再慢慢优化。4. 代码实现一套从预测到滚动优化的可运行框架4.1 总体架构四个模块串成闭环一套能实际跑起来的MPC程序至少包含四个模块预测模块产出预测时域内的电价、室外温度、被动冷负荷序列优化模块把模型、目标、约束实例化成LP/QP并求解执行模块从解里取出第一步控制量下发给冷机、阀门、水泵状态更新模块读取实测室温、蓄冷罐液位/温度作为下一轮优化的初值。这四个模块在代码里必须严格解耦否则你调试的时候会陷入“改一行参数不知道是预测的问题还是优化的问题”的泥潭。我见过太多项目把预测和优化写在一个大函数里最后排查问题全靠二分法删代码效率极低。4.2 核心代码一个可以直接跑通的MPC控制器我用开源库写了一个简化示例建模参数沿用前面章节的数值采样周期1小时、预测时域24小时。代码可以直接阅读接上真实数据就能改造成你的第一版原型。import numpy as np import cvxpy as cp # ---------- 模型参数 ---------- C 500.0 # 建筑等效热容 kWh/K R 0.02 # 等效热阻 K/kW dt 1.0 # 采样周期 h tau R * C a np.exp(-dt / tau) b R * (1 - a) c 1 - a COP 3.5 # 冷机能效比1度电可制3.5 kWh冷 S_cap 600.0 # 蓄冷罐容量 kWh P_ch_max 150.0 # 最大充电电功率 kW Q_disc_max 200.0 # 最大放能热功率 kW eta_ch 0.92 # 充能综合效率 eta_disc 0.90 # 放能综合效率 P_cool_max 400.0 # 冷机总电功率上限 kW T_min, T_max 22.0, 26.0 T0, S0 24.0, 0.0 N 24 # 预测时域24小时 # ---------- 外部预测序列示意数据 ---------- price np.array([0.35]*8 [1.15]*6 [0.55]*6 [1.15]*4) T_out 35.0 - 3.0 * np.sin(np.linspace(0, 2*np.pi, N)) Q_base 300.0 150.0 * np.sin(np.linspace(0, np.pi, N)) # ---------- 优化变量 ---------- T cp.Variable(N 1) # 室内温度轨迹 S cp.Variable(N 1) # 蓄冷罐冷量轨迹 P_cool cp.Variable(N) # 冷机直接供冷耗电 kW P_ch cp.Variable(N) # 冷机充能耗电 kW Q_disc cp.Variable(N) # 蓄冷放能热功率 kW constraints [] for k in range(N): Q_direct COP * P_cool[k] # 直接送入房间的冷量 # 建筑热平衡净加热量 被动负荷 - 冷机供冷 - 蓄冷放能 constraints [ T[k1] a * T[k] b * (Q_base[k] - Q_direct - Q_disc[k]) c * T_out[k], # 蓄冷罐动态充进/放出都要按效率折算 S[k1] S[k] eta_ch * COP * P_ch[k] - Q_disc[k] / eta_disc, T[k1] T_min, T[k1] T_max, S[k1] 0, S[k1] S_cap, P_cool[k] 0, P_ch[k] 0, Q_disc[k] 0, P_cool[k] P_ch[k] P_cool_max, P_ch[k] P_ch_max, Q_disc[k] Q_disc_max, ] constraints [T[0] T0, S[0] S0, S[N] 0] # 日清约束 # 目标全天电费最小恒定负荷项不影响最优解可省略 P_grid P_cool P_ch objective cp.Minimize(cp.sum(cp.multiply(price, P_grid))) prob cp.Problem(objective, constraints) prob.solve(solvercp.OSQP)这段代码的核心是两行状态方程第一行把冷机直接供冷和蓄冷放能一起打进建筑热平衡第二行更新蓄冷罐冷量。其余全是约束。求解完成后P_cool.value、P_ch.value、Q_disc.value就是未来24小时的最优动作序列但我们只取第一个值去执行。注意在约束里舒适度约束我写的是硬约束版本实际部署建议改成带松弛变量的软约束道理在上一节已经说过了。4.3 滚动时域循环MPC和离线调度的分水岭上面只是“算一次”真正的MPC必须包进滚动循环里def run_mpc(horizon_steps, get_state, forecast_provider, plant): for step in range(horizon_steps): # 1. 读取当前实测状态温度、罐内冷量 T_cur, S_cur get_state() # 2. 获取最新预测序列 price, T_out, Q_base forecast_provider.get() # 3. 重新构建并求解 update_problem(T_cur, S_cur, price, T_out, Q_base) prob.solve(solvercp.OSQP, warm_startTrue) # 4. 只执行第一步 u_first get_first_control(prob) plant.apply(u_first)注意第3步的warm_startTrue。MPC每轮求解的问题结构几乎一样只是参数和初值微调用上一轮的解做热启动求解时间能从几十毫秒再降一个量级。这个细节在控制周期压到15分钟时尤其重要没有热启动的MPC在线运行会有明显卡顿。执行第一步之前务必把功率值乘上采样周期再下发给下层设备或者在下层控制器里做积分保持。很多人第一次仿真发现“控制器算出来功率很大实际设备却没动作”多半就是单位换算或保持策略没对齐。这个问题不大但排查起来很浪费时间。4.4 工程化之前先做的三件事代码能跑通仿真只是第一步。我建议在接真实设备之前先干三件事做一周的“影子模式”控制器照常计算但不直接下发和现有的人工或规则策略并行跑逐小时对比两条策略的电费和温度曲线检查求解器的退出状态确保每次都是optimal。如果出现infeasible或time limit先排查约束和预测数据不要急着调权重给所有外部输入电价、温度预测加数据质量检查缺失、跳变、单位错误都能让MPC算出离谱的充放策略宁可跳过这一轮控制也不要执行坏结果。5. 实际运行中踩过的坑模型失配、求解器与数据质量问题5.1 模型失配的第一课状态初值错了优化再准也没用第一次把MPC接到真实楼宇时我遇到一个很典型的怪现象仿真里温度曲线漂亮得很实测却整体偏高1.5度。排查了半天发现不是模型参数错了而是状态初值T0用了前一天的最后计算值没有和现场传感器对齐。蓄冷罐的SOC也是标定值和实际累计放能量对不上下午罐子提前放空控制器才开始手忙脚乱地开机补救。这个坑的教训就一条每个控制周期开始必须用实时测量更新状态而不是沿用上一轮的预测值。楼宇MPC不是航天器不需要高精度状态估计但至少保证“温度取传感器、SOC取液位或热量计累计值”这种级别的反馈校正。有条件的话在热平衡方程里加一个缓慢变化的偏差项T(k1) a·T(k) b·(...) c·T_out(k) d_est(k)d_est用上一轮预测和实测的温差做指数平滑估计本质就是一个最简单的扰动观测器。加上它之后模型失配和未建模的被动热负荷都能被吸收掉鲁棒性提升非常明显。我现在的项目里几乎每套MPC都会带这个偏差项已经成了标配。5.2 蓄冷罐SOC漂移日清约束也会骗人蓄冷罐的“电量”并不可直接测量通常用液位、进出口温差和流量来估计。泵的启停、水流掺混、罐内温度分层都会让估算值和真实冷量差一截。这个误差如果不每轮校正会累积成很麻烦的后果控制器以为罐里还有200 kWh实际上只剩50 kWh下午高峰放不出冷温度直接越限。我的做法是两层防护。第一每个周期用直接测量重新初始化SOC不用上一轮递推出来的值。第二目标函数里对罐内冷量设定一个安全下限比如S(k) ≥ 30 kWh。这相当于给蓄冷罐留了“底油”宁可少赚一点峰谷价差也不让罐子在关键时刻掉链子。对楼宇这种慢过程系统稳健性永远优先于理论最优。5.3 天气预测和电价数据的坑坏数据比没有数据更危险MPC的信条是“预测得越准控制得越好”但现实是天气预测经常偏差。有一次连续三天预报有雨预测温度比实际低了5度控制器整天都在少开机少蓄冷结果峰段冷量不够用。痛出来的教训是MPC上线时预测误差的分布比均值更重要尤其是最坏情况。我的做法是在预测模块里人为加安全裕量——夏季用电高峰的午后时段把预测冷负荷上浮10%~15%相当于给MPC留了安全垫。电价数据同样要小心。分时电价本身是确定性的但需求响应事件往往是临时通知。如果优化过程中突然插入一条“今天14点到16点功率必须压到多少以下”的要求约束会瞬间变成不可行。工程上要专门做事件优先级处理要么把该时段改成固定功率上限并允许温度软约束越限要么直接切换到应急规则模式等事件结束再切回MPC。千万别让临时事件把主控制器的求解器搞崩。5.4 求解速度与数值问题LP也要讲卫生线性规划理论上是多项式时间可解的但实际求解器对问题的数值尺度非常敏感。楼宇MPC规模很小24步、几十个变量常规情况下求解器几十毫秒就能解完根本不用担心性能。真正让我吃过亏的是数值尺度——要是一开始把容量写成600000 Wh、功率写成400000 W目标函数系数和约束尺度差好几个数量级求解器的终止判据就变得不可靠可能返回一个看似“最优”实则残差很大的解。解决的办法很土但很有效把所有物理量统一到工程常用量级——温度用摄氏度、功率用kW、能量用kWh、电价用元/kWh。这样模型矩阵的元素基本在0.01到几百之间求解器就不会犯糊涂。另外用开源求解器时留意默认精度参数实测里把精度要求从1e-5放宽到1e-4求解速度能翻倍而优化成本只差不到千分之一。对楼宇这种慢过程这种取舍非常划算。6. 从单栋楼到多场景这套方法还能怎么延伸6.1 把蓄冷和蓄电放在一起优化楼宇真正灵活的不只是冷机还有储能电池、光伏、甚至电动汽车充电桩。把它们一起纳入MPC框架在数学上并不复杂——电池的状态方程和蓄冷罐几乎一样只是效率和功率约束的数值不同再把并网功率的权重改成“电费需量费电池老化成本”即可。我最近在做的某跨平台系统就是把电池SOC和蓄冷罐SOC都作为状态量目标函数里同时考虑峰谷价差套利和需量削减实测下来比单独优化每一类设备再手工叠加要平滑得多。两类储能一个管热一个管电时间尺度不同互补性很强。6.2 从单栋楼到虚拟电厂聚合单个楼宇的灵活性有限但几十栋楼聚合起来对电网就是一份很可观的调节资源。MPC在这条路上的延伸方向是分层控制底层每栋楼各自跑本地MPC上层聚合商做配额分配和协调。每栋楼把“响应能力曲线”上报上层上层根据总目标回传调节指令。这个方向工程量大但逻辑骨架仍然是前面讲的“模型预测滚动优化”只是优化问题的规模从一栋楼扩展到一群楼。我在实际项目中比较深的体会是分层结构里每层都要有独立的反馈校正机制否则上层模型的误差会传导到下层整个聚合系统的稳定性就很难保证。6.3 一点部署上的个人建议如果让我给正在读这篇文章的人一句真话别一上来就追求“最先进”先用LP把闭环跑通再逐步加复杂度。我见过好几个项目死在“模型很精细但永远无法校准”或者“优化器很先进但现场设备根本执行不了毫秒级指令”上。先把简单版本在影子模式里跑一到两周和现有规则策略做横向对比用数据说服运维团队信任这套系统比任何论文里的仿真效果都更有说服力。最后再分享一个小技巧给MPC的每个目标函数项和每条约束都写上单位注释长期维护的时候你会感谢自己。楼宇能源系统是多专业协作的战场电气、暖通、自控的人会看同一份代码单位不写清楚迟早有人把kW当成kWh那才是真正的灾难。代码可以朴素但工程习惯不能省。