考虑用户舒适度的冷热电多能互补综合能源系统优化调度MATLAB实现
综合能源系统的调度问题这几年不管是做园区项目还是写论文热度都一直很高。不过大部分代码和教程都默认“用户是机器”只盯着购电成本、燃气成本这些经济指标最后算出来的调度方案往往让室内温度飘得离谱——夏天省钱省到28度冬天冻到16度方案拿去汇报的时候自己都心虚。所以我当时拿到“考虑用户舒适度的冷热电多能互补综合能源系统优化调度”这个题目时第一反应是这终于不是纯设备模型堆叠了而是把“人”的感受写进约束和目标函数里。本文就是我基于一套MATLAB实现代码写下的完整拆解从建模、目标函数设计、YALMIP求解器实现到调试中踩过的坑一次说清楚。这套内容适合下面几类人看准备做综合能源优化调度的研究生刚入职做园区能源站运维的技术人员还有想从“纯经济学调度”转向“多目标协调调度”的开发者。代码本身覆盖了冷、热、电三种能源的耦合设备侧包含燃气轮机、余热回收、吸收式制冷、电制冷、储能电池、蓄热罐等常见单元调度层面则把用户热舒适指标引入优化。看完你不仅能理解为什么舒适度要进模型还能直接照着搭出自己的调度框架。1. 项目解析为什么冷热电多能互补要和用户舒适度绑定1.1 先搞清楚“多能互补”到底在补什么很多第一次接触这个概念的朋友会把“多能互补”理解成“多种设备并联哪个便宜用哪个”。这话对了一半但真正的关键在于“能源梯级利用”和“不同能源之间的时空耦合”。我这里举一个最常见的园区配置燃气轮机烧天然气发电发电的同时会产生高温烟气这部分余热不去利用就白白浪费了把余热送到溴化锂吸收式机组夏季可以制冷冬季可以制热如果余热还有富余可以存到蓄热罐里等热负荷高峰再放出来。与此同时电网购电、电制冷机、电锅炉等设备提供第二条能源路径。两条路径之间的“互补”体现在哪一个是设备层面燃气轮机发电多了烟气余热就多但园区电负荷不一定大热/冷负荷也不一定匹配于是需要通过电制冷机、储电、蓄热罐来做解耦和缓冲。另一个是时间层面电价峰谷波动很大谷电时段可以多购电、多存冷/热/电峰电时段少购电甚至卖电实现时间和空间上的能量搬移。调度模型要做的就是在一个优化周期内通常是24小时决定每一台设备出力多少、储能设备充放多少、和电网交换多少功率使得总运行成本最低。1.2 用户舒适度之前被调度模型丢掉的一块拼图传统优化调度模型里冷负荷和热负荷通常被视作“刚性的、必须满足的常数”也就是说负荷曲线是预测好的系统只需要按照这个曲线去分配各设备出力就行。但实际用户体感不是刚性的室内温度哪怕偏离目标两三度人体往往都能接受只是舒适度下降。反过来如果为了省成本把温度控制得过高或过低用户投诉就会立刻找上门。所以“考虑用户舒适度”本质上是在说制冷/供热负荷不该是固定值而是一个可以和室内温度耦合的柔性区间。你需要把建筑热过程比如一个简化的一阶热容热阻模型加入进来让优化算法自己去权衡这半小时在制冷侧少花点电费、把目标温度放宽到27度到底划算不划算如果因为放宽温度导致舒适度指标超限对应的惩罚是多少。这样调度结果就不会再出现“省了几百块电费、办公楼里所有人热到中暑”的离谱方案了。1.3 项目能给出什么结果这套MATLAB代码最终输出的内容包括24小时各设备最优出力曲线、储能设备充放电曲线、与电网的购售电计划以及与用户舒适度相关的室内温度变化曲线、舒适度评价指标本文以预测平均投票PMV为主。另外还会做两个对比场景不考虑舒适度的纯经济调度、考虑舒适度的综合调度通过成本变化和舒适度变化的量化对比你就能清楚看到“舒适度约束到底花了多少钱买回来”。2. 核心模型拆解设备、负荷、舒适度三块基石2.1 设备建模从效率曲线到数学校验这部分是后续优化模型的地基设备模型建得不对后面求解出来的调度方案等于空中楼阁。建模时习惯上把设备分为三类产能设备、转换设备和储能设备。先说产能设备最核心的是燃气轮机。它的关键参数有三个发电效率、热电比、最小稳定出力。很多简化模型直接让发电量乘以固定热电比得到余热量这在小规模算例里够用但稍微严谨一点的做法是考虑部分负荷率的影响——负荷率低于某个阈值时发电效率会明显下降代码里可以用分段线性函数来处理。发电功率、燃料消耗量、余热回收量三者之间的关系一旦确定燃气轮机的行为就完全被刻画出来了。转换设备比如电制冷机和吸收式制冷机。电制冷机的COP能效比一般取3到5吸收式制冷机的COP则低一些通常在1.2到1.5之间。换句话说同样是产生100kW冷量电制冷机只要消耗20到30kW电吸收式机组要消耗70到80kW热。所以直观上电制冷效率高但它的运行费用取决于电价吸收式靠余热驱动燃料成本已经由燃气轮机承担了边际成本很低。调度优化的一部分魅力就在于平衡这两种机组的出力搭配。储能设备包括蓄电池和蓄热罐有些园区还有冰蓄冷原理一致。蓄电池建模需要关注充电功率、放电功率、荷电状态SOC、充放电效率以及当日始末SOC一致性要求。蓄热罐类似只是能量形式变成了热量。储能设备的动态方程是优化模型里最容易写错的地方尤其是充放电效率导致的自损耗问题后文会专门展开。2.2 负荷模型刚性电负荷、柔性冷热负荷园区负荷可以分成两类。电负荷相对刚性照明、水泵、办公设备这些很难在调度周期内调节直接作为已知参数输入。冷负荷和热负荷则要区分“建筑需求”和“能源站供给”——建筑侧的冷/热需求会随着室内温度目标改变而改变这才是舒适度进入模型的关键通道。我用的建筑热过程模型是一阶等效热容热阻模型公式大致是C_b * (T_in(t1) - T_in(t)) / Δt Q_hvac(t) - (T_in(t) - T_out(t)) / R_b这个式子物理含义很直白室内温度变化量等于空调系统注入的热量夏季则是制冷量取负减去建筑围护结构向室外散失的热量。C_b是建筑热容R_b是围护结构热阻这两个参数可以通过建筑的面积、层高、外墙材质等信息粗略估算。有了这个方程室温和供冷/供热量之间就不再是固定的一对一关系而是动态的、可权衡的。2.3 舒适度指标量化PMV怎么进入优化模型PMV是美国供暖制冷空调工程师学会标准里的预测平均投票指标取值通常在-3到3之间0表示不冷不热最舒适正值为偏热负值为偏冷。完整计算PMV需要六个参数空气温度、湿度、风速、人体代谢率、服装热阻、平均辐射温度相当繁琐。真正放在优化模型里直接计算完整PMV公式是不现实的因为它包含非线性指数项会让求解器崩溃。我采用的简化办法是在典型室内湿度、风速条件下将PMV近似表示为室内温度的线性函数即PMV ≈ α * T_in β。这个近似在18到30度范围内误差可接受误差通常不超过0.1个PMV单位。然后把PMV约束在[-0.5, 0.5]之间就转化成了对室温上下限的约束或者更柔和一点在目标函数里加一项舒适度惩罚(PMV - PMV_target)^2。3. 优化调度模型目标函数与约束条件的完整设计3.1 目标函数经济成本和舒适度惩罚怎么配比这一层是整个程序最核心的逻辑。我先给出目标函数的标准写法然后解释每个部分的作用min Σ[ C_gas(t) C_grid_buy(t) - R_grid_sell(t) C_om(t) C_comfort(t) ] * Δt其中C_gas是燃气轮机燃料成本按天然气耗量乘以气价计算C_grid_buy是向电网购电成本按购电功率乘以分时电价R_grid_sell是售电收益如果系统允许余电上网的话C_om是设备运行维护成本一般按发电量和制冷量线性折算C_comfort是舒适度惩罚项这是本文区别于普通经济调度的关键。C_comfort(t) λ * (PMV(t) - PMV_set)^2这里PMV_set设为0λ是权重系数。为什么用平方项而不用绝对值因为平方项对“偏离量”的惩罚是非线性的室内温度偏离越大边际惩罚越重这样优化求解器会自动尽量避免极端温度而绝对值函数在零点不可导对梯度类算法不够友好。λ的取值直接影响调度倾向λ设0模型退化为纯经济调度λ非常大模型几乎把温度锁死在目标值附近运行成本随之上升。实操中我会跑一组不同λ的对比实验画出一条“成本-舒适度”之间的权衡曲线然后由决策者根据实际偏好选点。3.2 约束条件等式约束和不等式约束逐条过约束这部分是代码量最大、最容易出bug的地方。我按类别梳理第一类是功率平衡约束。电功率平衡要求燃气轮机发电、蓄电池放电、电网购电三者之和等于电负荷、电制冷机耗电、电锅炉耗电、蓄电池充电、电网售电之和。冷功率平衡要求电制冷和吸收式制冷的供冷量满足建筑冷负荷。热功率平衡则要处理燃气轮机余热回收、蓄热罐放热、电锅炉制热和建筑热负荷之间的关系。第二类是设备出力约束。每台设备有出力上下限部分设备还有爬坡约束即相邻时段出力变化不能超过设定值。爬坡约束在燃气轮机上尤其重要可以避免调度方案给出“这一小时满发、下一小时停机”的剧烈波动指令。第三类是储能约束。蓄电池SOC在0.2到0.9之间每日始末SOC相等蓄热罐蓄热量在上下限之间同样要求周期始末一致。充放电不能同时进行这里需要引入0-1变量否则模型会同时充电和放电“套利”。蓄热罐的充放热状态类似。第四类是舒适度相关约束。包括室内温度上下限约束、简化PMV取值区间约束。如果目标函数里已经有舒适度惩罚项那么这部分可以放松为仅保证PMV在[-1, 1]之间保证不会出现完全离谱的温度如果采用硬约束方式则可以严格设到[-0.5, 0.5]。3.3 求解思路为什么选YALMIP加商业求解器模型建完里面既有连续变量各设备出力、温度又有0-1变量设备启停和储能充放状态整体属于混合整数规划问题。目标函数含二次项约束大部分是线性或分段线性的所以是混合整数二次规划MIQP。建模我选YALMIP它是MATLAB下的优化建模工具箱接口做得非常干净你不需要手写标准形式的系数矩阵直接写表达式、加约束、然后调用求解器就行。求解器我用的有两类一类是CPLEX或Gurobi这类商业求解器性能和数值稳定性都很好MIQP问题求解规模可以到几十万个变量另一类是开源的CBC或SCIP适合中小规模算例虽然慢一些但胜在免费。如果你的项目规模不大24时段、10台设备以内开源求解器完全够用如果规模大了、变量上万还是建议用商业求解器。需要注意YALMIP只是建模层求解器要自己另外安装并添加路径。4. MATLAB代码实现从参数设置到核心调度循环4.1 工程目录与代码文件划分按我当时搭这套代码的习惯工程目录分成四块./data放负荷曲线、电价参数、设备参数./model放设备模型函数./optimization放优化建模主程序./result放输出图表。模块化拆开的好处是后期调参数不用在几百行的大脚本里翻来翻去。主程序运行流程如下先读取并初始化所有参数然后构建决策变量连续变量用sdpvar整数变量用binvar接着逐条添加约束再写入目标函数最后调用optimize函数求解。求解完成后对结果做后处理——把优化变量还原成设备出力序列、室内温度序列并计算成本项拆分、画图。4.2 关键参数怎么取直接抄作业的话可以按下面这张表设置一个典型的小型园区算例参数取值备注调度周期24小时 / 1小时间隔可根据需要改15分钟燃气轮机容量1000 kW发电功率上限发电效率0.35部分负荷率越高效率越高热电比1.5余热回收功率/发电功率吸收式制冷COP1.3余热驱动电制冷COP4.0分体式/离心式典型值蓄电池容量500 kWh充放电效率各0.95蓄热罐容量800 kWh周期始末一致室内温度范围20~26度对应PMV硬约束舒适度权重λ1.0通过多场景对比确定电价采用分时电价峰段1.2元/kWh、平段0.8元/kWh、谷段0.4元/kWh天然气价格按2.5元/m3折算1立方米天然气热值约9.7kWh。负荷曲线用模拟数据夏季典型日电负荷峰值约1800kW、冷负荷峰值约1200kW。4.3 核心代码YALMIP建模的关键片段下面给出优化模型构建阶段最核心的一段参考代码节选完整代码很长这里放不下%% 定义优化变量 P_gt sdpvar(1, 24); % 燃气轮机发电功率 P_gt_om binvar(1, 24); % 燃气轮机启停状态 P_ec sdpvar(1, 24); % 电制冷机输入电功率 Q_ac sdpvar(1, 24); % 吸收式制冷机供冷功率 P_grid_buy sdpvar(1, 24); % 购电功率 P_bat_d sdpvar(1, 24); % 蓄电池放电功率 P_bat_c sdpvar(1, 24); % 蓄电池充电功率 SOC sdpvar(1, 25); % 蓄电池荷电状态 T_in sdpvar(1, 24); % 各时段室内温度 %% 约束条件 Constraints []; % 电功率平衡 Constraints [Constraints, P_gt P_bat_d P_grid_buy - P_bat_c ... P_load_e P_ec P_eb]; % 冷功率平衡忽略网络损耗 Constraints [Constraints, Q_ec * COP_ec Q_ac P_load_c]; % 蓄电池SOC递推充放电不能同时用0-1变量v_bat Constraints [Constraints, SOC(1) SOC_init]; Constraints [Constraints, SOC(t1) SOC(t) ... - P_bat_d(t) / eta_d / Cap_bat ... P_bat_c(t) * eta_c / Cap_bat]; Constraints [Constraints, SOC 0.9, SOC 0.2]; % 舒适度约束PMV近似线性函数 Constraints [Constraints, a_pmv * T_in b_pmv -0.5]; Constraints [Constraints, a_pmv * T_in b_pmv 0.5]; % 室内温度动态 Constraints [Constraints, C_b * (T_in(t1) - T_in(t)) / dt ... Q_hvac(t) - (T_in(t) - T_out(t)) / R_b]; %% 目标函数 Objective sum(fuel_cost * fuel_cons * dt) ... sum(price_buy .* P_grid_buy * dt) ... - sum(price_sell .* P_grid_sell * dt) ... sum(lambda * (a_pmv * T_in b_pmv).^2 * dt); %% 求解 ops sdpsettings(solver, gurobi, verbose, 2); optimize(Constraints, Objective, ops);上面这段是高度浓缩的骨架实际运行时还需要给每条约束加索引循环把0-1变量的互斥关系充电和放电不同时写成两个不等式约束。值得强调的是温度动态方程里的Q_hvac(t)在夏季制冷模式下是个负值因为空调从室内取走热量这个方向搞反了会导致整个模型无解或者出现“加热和制冷同时开启”的离谱结果。4.4 调度结果长什么样以夏季典型日为例跑完代码后你能看到这样几个现象谷电时段23点到次日7点蓄电池会大量充电电制冷机也会满负荷运行把冷量提前存到蓄冷罐/通过建筑蓄冷把室温压到目标下限附近峰电时段燃气轮机接近满发余热驱动吸收式制冷机组供冷电制冷机降载甚至停机蓄电池放电支撑电负荷。室内温度变化曲线在24度附近小幅波动PMV始终处在-0.5到0.5区间。对比纯经济调度方案你会发现不考虑舒适度的方案会把室内温度顶到接近27.5度对应的总运行成本确实降了一些但舒适度指标已经到了0.8属于“明显偏热、部分人感到不舒适”的区间。舒适度约束加进去后总成本可能上升5%到8%换来的是全天室内温度保持在舒适区内。这个成本增幅就是“舒适度的价格”项目汇报时这张对比图非常有说服力。5. 常见问题与排查实录这套代码的坑我替你踩了一遍5.1 求解器报“Infeasible”问题这是新手碰上概率最高的报错。原因九成以上出在约束条件互相矛盾比如我一开始把室内温度上限设为24度但同时把冷负荷平衡里的供冷量上限设置得过低导致方程无解。排查方法是逐条注释约束二分定位到具体是哪一组约束导致不可行。还有一个简便操作把硬约束改成带松弛变量的软约束比如温度上限写成 T_in T_max slack并在目标函数里给slack加一个很大的惩罚系数这样即使约束有冲突也能解出来同时你能从松弛变量的取值判断哪个约束最紧张。5.2 储能SOC初始值和周期一致性设错蓄电池约束如果写成SOC(1)0.5但没有加最后的SOC(24)0.5循环起来你会发现电池为了追逐峰谷价差从初始0.5一路放到0.2因为没有“第二天还要用”的约束。如果加了周期一致性但条件写反了也可能出现求解器为了让SOC周期相等而强行让设备出力扭曲的情况。我的建议是先不加周期约束跑一遍观察SOC自然变化轨迹看看这个轨迹是否合理再决定周期末SOC该定多少。如果希望保留每日循环就把SOC(25)SOC(1)写进约束因为状态变量有25个点SOC(1)对应第0时段的初始状态。5.3 舒适度权重λ怎么调都别扭λ调太小时模型还是紧抱经济指标不放温度照样失控λ调太大时目标函数里舒适度惩罚项占绝对主导整个调度变成“不惜一切代价维持恒温”运行成本飙升。这个问题没有万能解但有一个比较好的调参路径先跑λ0得到纯经济调度的总成本和平均PMV偏离量再跑一个λ很大比如100的极限得到最低PMV偏离量和对应成本然后在这两个极端点之间用二分法找几个中间点画出一张“成本-舒适度Pareto曲线”。一般取曲线拐点附近的λ值性价比最高。5.4 充放电同时发生如果没有用0-1变量约束充放电互斥优化求解器经常会给你一个“同时充电和放电”的结果比如蓄电池一边以50kW放电、一边以50kW充电从SOC动态方程看完全没有净变化但目标函数里却因为两种功率都为正而产生不必要的损耗项或者在某些公式变形中反而能套到补贴结果既不合理又可能报错。解决办法是引入二进制变量v_bat满足P_bat_c v_bat * P_bat_c_max, P_bat_d (1-v_bat) * P_bat_d_max。蓄热罐同理。5.5 室内温度动态方程方向出错这个坑我记忆特别深。夏季制冷模式下空调向室内注入的是“负热功率”。如果代码里把Q_hvac(t)当作正值加到温度动态方程右侧计算结果会变成室内温度越来越高然后模型为了让温度不超过上限只能让制冷功率为负值——也就是反向加热整体乱套。所以务必在代码里分清制冷和制热两个模式或者用统一的正负号约定温度动态方程右侧为“注入室内的净热功率”制冷时取负值制热时取正值。省略这一步会导致失败。6. 多场景对比与扩展方向这套框架还能干什么6.1 场景一不同舒适度权重下的帕累托前沿做这个对比的价值在于你可以给决策者一个直观的选择依据而不是扔出一句“我把舒适度约束设为±0.5”。具体实现起来非常简单外层循环设定λ序列比如0、0.2、0.5、1、2、5、10每次循环调用一次优化求解把总运行成本和平均绝对PMV偏差记录成两个数组最后用plot画散点图。你会得到一条从左下到右上的曲线左端是纯经济低成本高不适右端是纯舒适高成本低不适。项目评审时把这张图放出来比说一百句“我们考虑了舒适度”都有用。6.2 场景二改变电价结构观察设备调度策略变化把分时电价的峰谷差从0.8元扩大或缩小到0.4元、1.2元观察蓄电池充放电策略和燃气轮机出力策略的变化。峰谷差越大储能就越值得多充多放燃气轮机在峰段发电的经济性也会更突出。这个实验本质上是在验证模型对价格信号的响应能力如果你做的系统后续要参与需求响应或现货市场这样的灵敏度分析非常有参考价值。6.3 扩展方向从日前调度走向滚动优化目前这套代码做的是日前开环调度假设未来24小时负荷、电价完全已知。实际上电价和负荷都有不确定性更贴近工程需求的做法是改成模型预测控制每15分钟或1小时滚动一次用未来4小时或24小时的预测数据滚动求解只执行当前时段的调度指令下一周期再重新优化。代码改造并不难核心是把约束里时段数从24改成预测时域H同时保留当天的储能初始状态。这样就有了闭环反馈抗扰动能力会好很多。6.4 扩展方向把碳排放入模型国家层面的双碳背景下很多园区项目在成本目标之外还要求降低碳排放这相当于额外增加一个“碳排放成本”项。代码上需要做的事情只有两件第一给电网购电、燃气消耗分别加碳排放因子第二在目标函数中加入“碳价×碳排放量”的惩罚项。调度结果会很明显地倾向于在燃气轮机和电网购电之间重新分配——燃气轮机碳排放显著低于燃煤火电模型会自发提高燃气轮机利用率、降低购电比例。7. 最后说几点实在的体会做完这套项目后我对综合能源调度有了几个很深的感受。第一模型的复杂度和可解释性之间需要平衡YALMIP让你什么约束都能往上加但每多加一类约束排查问题的时间可能增加一倍。如果精力有限优先把设备模型和储能约束做扎实舒适度可以先做硬约束版本跑通了再加惩罚项千万不要一上来就上满配模型。第二参数标定的重要性不亚于优化算法本身热电比、COP、效率这些参数如果是从样本手册上瞎抄的算出来的调度策略拉闸就废。如果有条件哪怕用园区一个月的实际运行数据做简单的均值校准都会比拍脑袋好得多。第三把结果画成图真的很有帮助。我不止一次通过画设备出力堆叠图发现“燃气轮机凌晨三点莫名满发”这种逻辑上根本解释不通的调度行为原因追查下来都是约束方向或者参数单位的问题。最后再分享一个小技巧给每一个时段的设备出力、储能SOC、室内温度单独画子图并且加上当日电价曲线作为双纵轴对照。调度方案是否合理一眼就能看出来——如果电制冷机在电价峰段满负荷运行蓄电池在谷段大量放电那多半就是模型约束或者目标函数里漏掉什么了。调参调试时这套可视化脚本比任何调试器都顺手。希望你在自己的项目里也能少踩几个坑早点跑出既省钱、又让人体感舒服的调度方案。