冷热电联供微网多时间尺度优化调度:冰蓄冷空调建模与YALMIP复现
这个题目我在实验室里泡了大半个月才真正理顺。含冰蓄冷空调的冷热电联供型微网多时间尺度优化调度初看是一个标准的综合能源优化问题实际做起来涉及的坑非常多——冷热电三种能量流的耦合关系、蓄冰槽跨时段的状态衔接、日前日内实时三个尺度之间的变量传递任何一个环节断了结果都会出现明显的物理不守恒。这篇博文不打算从综述开始讲直接聊我在用Matlab复现这个调度框架过程中的设计思路、关键模型、代码组织方式和踩过的坑。内容面向正在做微网优化调度方向的研究生、需要搭综合能源算例的工程师以及所有被YALMIP加商业求解器这个组合折磨过又离不开它的朋友。看完之后你至少能把一条能跑通、结果合理的复现路径带回去而不是在茫茫多的公式和报错之间继续摸索。1. 项目整体设计与思路拆解1.1 微网系统结构冷热电三条能量流怎么串起来先把这个系统的家底理清楚。冷热电联供型微网英文缩写是CCHPCombined Cooling, Heating and Power核心思想是让一套能源系统同时供应电、热、冷三种负荷。典型结构包含这几块供电侧燃气轮机或燃气内燃机、光伏、上级电网购电、蓄电池。供热侧余热锅炉或热交换器回收燃气轮机余热、燃气锅炉补燃调峰。供冷侧溴化锂吸收式制冷机用热能制冷、电制冷机用电制冷、冰蓄冷空调蓄冰加融冰。负荷侧电负荷、热负荷、冷负荷。能量流的关系是燃气轮机烧天然气同时发电和产出高温烟气烟气余热经过余热锅炉回收后一部分直接变成热功率供应热负荷另一部分进入吸收式制冷机变成冷功率。电制冷机和冰蓄冷空调则用电来制冷。这样一来原本电是电、热是热、冷是冷的割裂系统就变成了燃气进、三能出的联供系统。综合能源利用率比单纯的分布式光伏加电空调高不少这也是这个方向一直有人研究的原因。从调度的视角看三条能量流的平衡必须同时满足任意时刻电负荷等于各电源出力之和减去用电设备的耗电热负荷等于余热供热加锅炉补燃冷负荷等于直供冷量加融冰冷量加吸收式制冷量。三条平衡通过燃气轮机的热电比耦联在一起——你多发电余热就多热和冷就多反过来如果冷负荷很大热却用不完就需要想办法把多余的热散掉或加大制冷。这种耦合关系是单做电力的优化调度完全不会遇到的。1.2 为什么偏偏要加冰蓄冷空调做这个课题之前我对冰蓄冷空调的认知停留在商场夜里制冰、白天化冰省钱的粗浅印象。真正建模之后才发现它在微网里的价值远比省钱两个字大。先说痛点。夏季典型的工业园区或商业综合体制冷负荷峰值和电负荷峰值高度重叠——中午最热的时候空调拼命制冷电负荷也冲到最高。这时候燃气轮机可能已经满发光伏出力再高也顶不住只能靠高价购电。如果单纯扩大设备容量投资成本和运行成本都会水涨船高显然不经济。冰蓄冷空调的思路就是移峰填谷夜间电价低谷时段电价便宜系统用电驱动制冷主机把水制成冰存起来白天电价高峰系统停掉部分制冷主机靠融冰释放冷量来满足冷负荷。这样就把白天的制冷耗电平移到了夜间缓解了电负荷峰值也减少了高价购电。在建模层面冰蓄冷空调相当于一个冷量储能装置但比蓄电池的模型简单得多。蓄电池要考虑充放电效率、SOC-功率耦合曲线、循环寿命衰减这些复杂约束而蓄冰槽只需遵守能量守恒和容量限制。它跟冷热电联供结合之后等于给整个微网增加了一个时间搬移的自由度白天冷负荷高但电价贵就可以多用融冰供冷夜间电价便宜就多制冰把冷量存起来。这个自由度对优化结果的影响非常明显我后面会详细展开。1.3 多时间尺度优化到底解决了什么问题为什么不能只做一次全天优化因为实际运行中光伏出力预测误差、负荷预测误差、电价波动都会让算好的计划在执行时失效。单层优化模型的假设是未来24小时参数全部已知现实显然不是这样。多时间尺度优化的思路有点像天气预报的体系长期预报看趋势短期预报盯细节实况监测做校验。我的复现框架分三层日前调度小时级一天24个时段或96个时段基于短期预测的负荷、光伏、电价数据决定燃气轮机启停、蓄冰槽蓄冰计划、电网购电计划这些粗决策。日内滚动15分钟级滚动时域优化基于超短期预测每15分钟滚动一次只优化未来几小时的出力细节修正日前计划与实际的偏差。实时调整分钟级处理秒级到分钟级的波动通过蓄电池和蓄冰槽的快响应特性保证功率实时平衡。三层结构各有各的职责日前层管大体格局日内层管偏差修正实时层管兜底平衡。每一层只修正上一层留下的偏差而不是把整个问题从头算一遍。这种分层处理的好处是计算速度快、鲁棒性强代价是层与层之间需要一套合理的变量传递规则这正是复现中最容易出问题的地方。1.4 方案选型为什么用Matlab加YALMIP复现这个课题我一开始也考虑过用Python的Pyomo或者直接用商业求解器接口。最后选了Matlab加YALMIP组合原因很实际YALMIP的建模语法非常接近数学公式。论文里的一大堆求和式、不等式写进YALMIP基本是一一对应不容易在公式翻译成代码这一步出错。相比之下用Pyomo虽然也不算难但很多习惯Matlab的同行在初期切换时总会有点别扭。另一个原因是我需要频繁画逐时的电平衡图、冷平衡图、SOC曲线图。Matlab的绘图生态在这一类科研可视化里确实方便批处理循环跑算例也不慢。至于求解器我用的组合是YALMIP调用CPLEX备选Gurobi。两者都是成熟的商业MILP求解器处理几千个二进制变量的混合整数线性规划问题没有太大压力。如果追求极端求解速度可以考虑手写约束矩阵并直接调用求解器API但那是工程落地阶段的事。学术验证和算法研究阶段用YALMIP这种建模语言快速迭代性价比高得多。2. 核心细节解析与实操要点2.1 冰蓄冷空调建模的三个核心环节冰蓄冷空调的建模是整个题目的灵魂。我第一次复现的时候直接把它当成一台普通电制冷机加一个蓄电池结果冷量平衡怎么都对不上。后来老老实实拆成三个子模型第一是制冷主机模型。冰蓄冷空调里的制冷主机有双工况能力制冷工况下直接提供冷水给末端制冰工况下产生的冷量用于制冰。两个工况的能效比COP不同通常制冰工况COP比制冷工况低一些因为制冰需要的蒸发温度更低。数学上写成制冷工况冷量 COP_c × 耗电功率 制冰工况冷量 COP_ice × 耗电功率这两个功率之间存在模式互斥——同一时刻主机要么直供要么制冰不能又供冷又制冰。第二是蓄冰槽模型。蓄冰槽的状态用蓄冰量S_ice来表示单位是kWh冷量。能量平衡方程是S_ice(t1) S_ice(t) (制冰功率 - 融冰供冷功率) × 时段长度也就是说这一时段存进去的冰量减去融出去的冰量等于蓄冰槽冷量的变化量。融冰功率有上限约束不能无限制地快速融冰否则供水温度波动会很大蓄冰量也有上、下限约束槽内不可能空也不可能满到溢出来。第三是末端联合供冷模型。用户侧冷负荷需要由制冷主机直供冷量、融冰冷量和吸收式制冷机冷量共同满足冷负荷 直供冷量 融冰冷量 吸收式制冷量这看起来像简单加法实际运行中却是三种冷源比拼成本的过程。夜间电价低制冰便宜蓄冰槽把冷量存起来白天电价高融冰就成了最经济的冷源吸收式制冷机用的是燃气轮机余热边际成本几乎为零应该优先满发。实操中有三个关键注意点蓄冰槽的末态约束必须加。调度周期结束时蓄冰量要回到初始水平或允许一个小的偏差范围。如果不加求解器会在一天结束时把槽里的冰全部耗尽第二天早上蓄冰槽就是空的跨天运行完全不成立。融冰速率上限比蓄冰速率上限更值得花心思。蓄冰在夜间慢慢蓄没问题白天融冰供冷如果速率上限设太小会出现有冰却供不出冷的尴尬情况冷负荷平衡被约束卡死。制冰模式和直供模式的互斥约束一定要建模。我试过不加互斥约束时模型会给出同一台主机同时制冰和直供的结果数值上满足等式物理上却是胡闹。后面在4.2节会讲具体怎么处理。2.2 冷热电联供设备建模的核心参数燃气轮机是整个系统的发动机它的模型决定了冷热电三条能量流的耦合强度。建模只需要三个关键参数发电效率η_e、热电比r、余热回收利用率η_h。发电效率把天然气输入能量转化为电功率发电功率 η_e × 天然气输入功率其中天然气输入功率等于天然气耗量乘以低位热值。热电比描述的是发一度电的同时产生多少余热余热回收功率 发电功率 × 热电比。余热回收利用率回答回收的余热里有多少能被实际利用——因为烟气温度、换热损失等因素不可能100%利用。回收的余热进入两个下游设备一路走热交换器直接供热满足热负荷。热交换器模型简单输入热功率乘以效率就是输出热功率。另一路走溴化锂吸收式制冷机把热能变成冷能。吸收式制冷机没有大功率压缩机主要耗电是溶液泵和冷却塔风机相比电制冷机省电得多但它的COP热制冷系数不高通常在0.7到1.4之间也就是说1kW热量只能换0.7到1.4kW冷量。而电制冷机的COP普遍在3到51kW电能可以换3到5kW冷量。这两者相互配合形成了电制冷效率高但耗电贵吸收式制冷耗电少但要烧余热的经典取舍。还要补一台燃气锅炉作为热源补充用来覆盖热负荷峰值或燃气轮机停机时的供热缺口。没有这个补充热源系统在热负荷高峰时很可能出现热平衡无解的困境。2.3 多时间尺度调度框架的搭建思路三层调度框架我推荐分层建模加变量传递的思路而不是在一个模型里堆所有时间尺度。第一层日前优化。时间分辨率取1小时一个调度周期24个点也可以取96个点即15分钟分辨率但计算量会大不少。决策变量是燃气轮机启停、各机组启停、蓄冰槽全天蓄冰融冰计划、蓄电池充放电计划、购电售电计划。目标函数是全天总运行成本最小。第二层日内滚动。时间分辨率取15分钟滚动窗口通常取4小时或6小时。每15分钟触发一次优化重新预测未来窗口内的负荷和光伏出力调整连续变量的出力。日内层不再碰启停变量——机组开没开、蓄冰槽能不能用都继承日前层的决策结果最多做小幅修正。第三层实时调整。时间分辨率1到5分钟我通常用一个简化的模型预测控制来做或者干脆写一个反馈校正脚本实时检查功率越限情况如果越限按优先级依次调节蓄电池出力、融冰速率、购电功率。实时层不需要求解大规模优化问题否则计算延迟无法接受。在Matlab里复现时我强烈建议先把单时间尺度下的所有模型跑通再复制到日内层最后加实时层。直接一次写成三层变量传递逻辑一旦出错排查起来非常痛苦。2.4 目标函数与约束条件的完整梳理目标函数我选择最小化系统总运行成本具体展开是四项购电成本由上级电网购电的电量乘以实时电价售电收入则是负成本。天然气成本燃气轮机和燃气锅炉消耗的天然气量乘以天然气价格。设备运维成本各设备出力乘以对应的单位运维成本系数。启停成本机组启停一次产生的附加费用用二进制变量乘一个大系数来实现。目标函数写成数学形式是min Σ_t [ 购电价格×购电功率×Δt - 售电价格×售电功率×Δt 天然气价格×天然气耗量×Δt Σ_i 运维成本系数×设备出力×Δt 启停成本×启停标志 ]约束条件要覆盖五个方面电平衡约束各电源出力加购电加蓄电池放电等于电负荷加各用电设备耗电加购电加蓄电池充电。最容易漏的是电制冷机和制冰机的耗电这两台都是用电大户漏一个等式直接不守恒。热平衡约束余热供热量加锅炉补燃热量等于热负荷。冷平衡约束直供冷量加融冰冷量加吸收式制冷量等于冷负荷。设备出力约束每台设备的出力有上下限且上下限与二进制启停变量相乘——停机时出力必须是0。储能约束蓄电池和蓄冰槽都要满足SOC动态方程、容量上下限、充放电功率上限以及调度末期的SOC回位约束。电网交互约束也很重要。从上级电网购电不能无上限实际工程中受变压器容量限制需要设一个购电功率上限否则优化器会在电价便宜时无限购电、大量蓄能结果严重脱离实际。3. 实操过程与核心环节实现3.1 代码架构设计让每一层都能单独调试代码组织上我采用模块化文件夹结构CCHP_Microgrid/ ├── data/ 负荷、风光、电价等输入数据 ├── models/ 设备参数定义 ├── schedules/ 日前、日内、实时三个调度层 ├── utils/ 数据读取、结果输出、画图工具 └── main.m 主程序main.m里放几个开关变量run_day_ahead、run_intraday、run_realtime。调试时只开其中一层跑通之后再层层叠加。每个调度层文件夹下再拆成build_model.m、solve_optimization.m、save_results.m三个脚本。这个结构的最大好处是改参数不用四处找换算例只需要换data文件夹里的数据文件各层级能独立验证正确性。我见过很多同学的复现代码是一个巨型脚本跑到底改一个参数要滚动半个小时才能看到结果那种体验我是不推荐的。3.2 模型实现从数学公式到YALMIP约束下面直接看蓄冰槽相关的YALMIP实现片段这是一个简化版但足够说明核心逻辑% 决策变量 P_ice sdpvar(1, T); % 制冰电功率kW Q_melt sdpvar(1, T); % 融冰供冷功率kW S_ice sdpvar(1, T1); % 蓄冰量kWh % 二进制变量 u_ice binvar(1, T); % 制冰模式指示 % 蓄冰槽SOC动态方程 for t 1:T Constraints [Constraints, S_ice(t1) S_ice(t) (P_ice(t) * COP_ice - Q_melt(t)) * dt]; end % 边界约束 Constraints [Constraints, S_ice(1) S_ice_initial]; Constraints [Constraints, S_ice(T1) S_ice_initial]; Constraints [Constraints, 0 S_ice S_ice_max]; Constraints [Constraints, 0 Q_melt Q_melt_max]; Constraints [Constraints, 0 P_ice P_ice_max * u_ice];这里有一个我踩过的坑如果不把制冰模式和直供模式做互斥模型会在同一时段既制冰又直供大量冷量看似满足冷平衡实际物理上不成立。解决方法是把主机的直供模式也建模成一个二元变量加一条直供状态加制冰状态小于等于1的互斥约束。代价是多了一倍的二进制变量求解时间会上升但在可接受范围内。3.3 求解器配置与性能调优求解器设置上我推荐options sdpsettings(solver, cplex, verbose, 2); options.cplex.mip.tolerances.mipgap 0.001; % MIP gap设为0.1% options.cplex.mip.limits.timelimit 300; % 求解时限300秒 options.cplex.mip.strategy.search 4; % 深度优先搜索MIP gap这个参数值得多说两句。很多新手为了追求极致精度把gap设成0结果模型稍复杂一点就几小时跑不完。我实测下来日前调度这类场景0.1%的gap完全够用——输入数据本身就有预测误差再高的求解精度也是白费。同样的算例gap从0.001放宽到0.01求解时间从20分钟降到3分钟目标函数值差异不到0.3%。对于更复杂的算例试试热启动先求解一个不考虑整数变量的松弛问题把连续解作为整数求解的初始点喂给求解器能显著加速求解。再不行就考虑把同类型多台机组聚合成一台等效机组整数变量数量直接减半。3.4 算例设计参数从哪来、结果怎么看复现过程中最头疼的就是参数散落在各篇文献的表格里很容易抄错。我整理了一份常用参数速查表数值可以根据实际场景调整设备参数数值燃气轮机额定发电功率1000 kW燃气轮机发电效率0.35燃气轮机热电比1.2吸收式制冷机热制冷系数1.1电制冷机COP4.0冰蓄冷主机制冷COP3.5冰蓄冷主机制冰COP3.0蓄冰槽最大蓄冰量1200 kWh蓄冰槽最大融冰速率300 kW蓄电池容量500 kWh蓄电池最大充放电功率200 kW设计算例时冷热电负荷的比例要和设备容量匹配。燃气轮机热电比1.2意味着发1000kW电的同时产生约1200kW余热如果热负荷没有那么高多出来的余热只能靠吸收式制冷机制冷消化或者直接散掉。负荷曲线设计不合理会出现热过剩、冷不足或者反过来模型结果一看就是病态的。结果验证一定靠画图。我固定的三张图是电功率平衡堆叠图、冷功率平衡堆叠图、蓄冰槽和蓄电池SOC曲线。如果SOC曲线在白天出现莫名的剧烈波动大概率是约束或参数有问题不是求解器发疯。4. 常见问题与排查技巧实录4.1 无可行解先用松弛变量定位问题无可行解是遇到最多的报错。我的经验是不要盯着报错干瞪眼直接在约束里加松弛变量来探测问题出在哪。做法是在每个关键等式约束右端加一个非负松弛变量目标函数里加一个很大的惩罚项。求解之后看哪些时段、哪条约束的松弛变量非零问题就定位了。常见的无可行解原因有四个蓄冰槽末态约束太紧。一天的冷量被用得太狠最后回不到初始状态。解决方法是放宽末态约束为允许一定偏差或者扩大蓄冰槽容量。电平衡约束漏了用电设备。常见的是漏掉电制冷机或制冰机耗电导致电量凭空消失。燃气轮机最小出力约束与负荷不匹配。比如夜间热负荷很小时燃气轮机的最低出力对应的余热却无处消纳需要加余热排放变量来模拟实际运行中的散热。购电上限设得太小。系统在高峰期想多买电却买不到导致负荷无法满足。用松弛变量定位后通常只需要调整几个参数就能跑通。4.2 蓄冰槽SOC对不上账多时间尺度复现中最隐蔽的问题是日前层和日内层对蓄冰槽SOC的计算对不上。日前层用1小时步长日内层用15分钟步长两层对同一个物理时刻的S_ice值定义必须严格对齐。我建议在变量传递时单独写一个convert_time_index函数把日前层的时段索引映射到日内层的时段索引。不要直接拿变量赋值因为Matlab数组下标从1开始而文献公式里常常从0开始一个偏移就能让所有SOC错位一个时段排查起来极其痛苦。另外日内层执行完优化之后应该把实际运行的蓄冰量回代到日前层的下一轮优化中形成一个闭环反馈而不是每轮都从日前层的预测值出发。4.3 日前日内变量衔接错位日前层决策了机组启停和蓄冰计划日内层应该怎么处理这些决策我踩过的坑是把日前层结果当成硬约束日内层完全不能改变结果预测误差稍大一点日内优化就无解。正确的做法是用软约束启停状态必须继承这是硬约束因为机组开关机有物理时间门槛但连续出力可以允许在小范围内调整代价是目标函数里加一个偏离日前计划的惩罚项。具体实现% 日内层启停强约束 Constraints [Constraints, u_gt_ID u_gt_DA]; % 日内层出力软约束 Constraints [Constraints, abs(P_gt_ID - P_gt_DA) delta_gt];delta_gt不建议设太小理想数值是日前预测误差的2到3倍。留足调整空间日内层才有实际意义。4.4 整数变量太多导致求解缓慢多时间尺度模型最大的性能瓶颈就是整数变量数量。日前层96个时段、每时段十几个设备如果每个设备有两个模式整数变量数量轻松破几千。CPLEX处理3000个二进制变量没问题但再往上增长求解时间会指数级上涨。我的排查思路是先缩减时段做模型验证。把96时段缩到24时段模型跑通且结果合理后再恢复。设置合理的MIP gap和时限不要死磕最优解。考虑机组聚合。多台同类型机组聚合成一台等效机组整数变量数量直接减半。检查是否有冗余变量。比如某个设备在某个时段根本不需要启停决策可以用固定值替代。4.5 调试三板斧能量守恒对账、单设备单场景测试、基准场景对照整个复现过程中最后沉淀出来一套调试三板斧第一板斧能量守恒对账。把逐时的电平衡、热平衡、冷平衡等式两侧分别求和任何一个差值超过0.01kWh说明约束有问题。这个方法能快速定位平衡约束写错方向的低级错误。第二板斧单设备单场景测试。把系统简化为一台燃气轮机加一个固定负荷目标函数简化成只统计这台设备的发电量验证设备模型的输入输出关系是否正确。设备模型错了后面所有优化结果都是空中楼阁。第三板斧基准场景对照。设置一个零光伏、零蓄冰、固定电价的基准算例。这种情况下优化结果应该非常直观——购电量等于负荷减去燃气轮机发电量。如果结果不符合直觉要么模型有bug要么参数有抄错。这三板斧配合起来我解决过的问题包括制冰机的COP写反、冷负荷平衡符号写错、蓄冰槽SOC的dt没有乘上时段长度、日前和日内层时间索引移位……每一个都是看起来没毛病、结果就是不对的坑。写在最后我个人在实际操作中的体会是复现这类多时间尺度优化调度真正的价值不在跑出一个漂亮的目标函数数值而在于把能量流、信息流、时间流三层关系彻底理顺。做完这个项目之后我对储能是系统灵活性核心这句话的理解深了一层——无论是蓄冰槽还是蓄电池它们真正的作用是把能量从时间维度上搬移把刚性系统变成柔性系统。最后再分享一个小建议写代码之前先把冷、热、电三条平衡方程手写在纸上标清楚每一个变量的单位、取值范围和所属层级再动键盘。我前两周返工的大多数问题都是因为模型草图没画清楚就急着敲YALMIP。先把模型伺候明白了代码只是一个翻译过程。