ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

热电联产机组储热改造与低碳经济调度:Matlab+Yalmip建模实践

热电联产机组储热改造与低碳经济调度:Matlab+Yalmip建模实践 这几年做电力系统调度优化你很难不碰到“火电机组储热改造”这个方向。热电联产机组因为“以热定电”的运行特性采暖季调峰能力被热负荷锁死风电一来就得弃碳排放指标也压不下来给机组配上储热罐之后热出力可以跨时段转移机组电出力有了腾挪空间整个电力系统的低碳经济调度才真正有的玩。我最近一直在Matlab里倒腾这套模型从目标函数、约束矩阵到YalmipGurobi求解、结果分析踩过不少坑也积累了一些可复用的经验。这篇笔记就按我的实现路径展开适合正在做火电灵活性改造、储热参与调峰、低碳经济调度这类课题的研究生和工程师参考。我不讲太虚的背景直接讲建模怎么建、代码怎么写、问题怎么排。1. 储热改造到底解决了什么问题1.1 热电联产机组“以热定电”的困局先看没改造的情况。抽凝式热电联产机组的工作原理是锅炉产蒸汽一部分蒸汽进入汽轮机做功发电另一部分从中压缸抽出送去供热。抽汽量越大供热越多但能用来做功发电的蒸汽就越少机组的电出力上限会跟着降低反过来为了供热而保留的蒸汽流量也抬高了机组的最小电出力。这就是熟知的“电热耦合”特性热出力几乎决定了电出力可运行的区间。实际运行中热负荷又是硬性的供暖季夜间恰恰是热需求高峰机组为了满足供热电出力被压在区间的中高位没法真正降到最低系统的调峰能力因此被砍掉一大块。典型参数是怎么被影响的一套330MW的抽凝机组纯凝工况下最小电出力可以做到35%额定容量左右但供热抽汽一上来最小电出力可能被抬到60%以上。我用一组冬季典型日数据算过深夜负荷低谷段风电大发热负荷却正好处于峰值没有储热时只能弃风弃风率直接冲到10%以上。冬季很多区域“热电比”很高热负荷曲线和电负荷曲线还经常错峰深夜趁热打铁反而弃风这个“困局”就是储热改造要处理的核心矛盾。1.2 储热改造怎么实现热电解耦储热改造的本质是给供热系统加一个热量的“蓄水池”。趁机组还可以高负荷运行时把一部分抽汽热能存在储热罐里等热负荷上升、或者机组需要压低电出力时再从罐里放出来代替机组本体承担供热。这样一来热负荷在任何时刻都不必完全由汽轮机抽汽来满足机组本体和热负荷之间那条硬绑定的线就被解开了。工程上常见的方案是大型常压热水储热罐利用水的显热储热结构简单、成本相对低适合火电厂的规模。也有用压力储热或相变材料的方案但调度建模时我们通常不关心储热罐内部怎么分层、用什么介质只关心三个参数额定蓄热功率、额定放热功率、储热容量。再加一个蓄放热效率一般取0.9到0.95我常用的算例里取0.92。可以类比成家里的热水器水用完之前一直是热的但热水器的水箱容量就是储热罐的SOC你洗澡热负荷时如果没有热水就要提前把水烧上蓄热。1.3 调度模型里怎么描述改造后的机组调度模型层面储热改造没有改变机组的物理模型它改变的是热平衡关系。没改造时系统的热负荷由机组供热量逐时平衡改造后要加一个储热罐状态变量机组热出力加上储热罐放热量减去蓄热量等于热负荷。这时机组的电出力和热出力的耦合关系还在但热需求的一部分可以由储热罐承担机组在低谷时段可以把抽汽量降到较低水平电出力跟着下降“热电解耦”落实到模型里就是多了一个自由度。更重要的是储热罐引入了跨时段耦合这一时刻蓄的热可以留到下一时刻放。调度模型里要有一个SOC递推方程把相邻时段的状态量串起来。这个“状态量”概念是模型从静态优化变成动态优化的关键也是最容易写错的地方。T个时段意味着SOC有T1个点初值和末值通常要设为相等保证调度方案能周期性滚动不然最后一个时段储热罐可能被耗空解出来的结果没法直接用于实际运行。2. 低碳经济调度的建模思路2.1 目标函数碳排和成本怎么放进一个式子里低碳经济调度目标函数必然是两个分量经济性和低碳性。经济性的主体是煤耗成本机组的煤耗一般用二次函数 C(P)aP²bPc 描述。但二次函数会让优化模型变成二次规划后面再沾上0-1变量就变成MIQP求解器选择变少速度也慢。我之前试过MIQP算24时段三台机组还行规模一大就不太稳。后来代码里把煤耗曲线分段线性化把整个模型转成MILP求解效率和稳定性都上来了。低碳性怎么进入目标最直接的做法是碳排放交易机制给系统一个免费碳配额实际排放量超过配额的部分按碳价购买低于配额的部分可以卖出获利。这样一来碳排放不再是独立指标而是货币化的成本项和煤耗成本一起求和。碳价就是低碳和经济之间的桥。我在不同碳价下跑过的结果差异很大50元/吨和200元/吨下系统选用的运行点完全不同所以做低碳调度前先想清楚讨论的碳价水平对应什么情景。除了这两块通常还会加一个弃风弃光惩罚项目的不是真的“罚”而是迫使模型尽量消纳新能源。数值上把惩罚系数设得明显高于边际煤耗成本即可我常用的弃风惩罚系数是500元/MWh。2.2 核心约束电功率、热功率与SOC都要卡住约束条件我分成四组。第一组是电功率平衡所有机组电出力加上风电出力减去弃风等于电负荷。风电功率不能直接硬塞进平衡里超过消纳能力的部分必须作为弃风变量存在这个变量一定要定义成非负否则模型会为了省成本“凭空造电”。第二组是热平衡机组热出力加储热放热减蓄热等于系统热负荷。注意符号约定有的文献把蓄热记为正、放热记为负代码里注释要写清楚不然后期看代码很容易绕晕。第三组是机组运行约束电出力上下限、爬坡约束以及抽凝机组的电热耦合约束。耦合约束可以写成线性不等式比如用两条边界限制P和H的组合落在可行多边形内。第四组是储热罐约束SOC递推、SOC上下限、蓄放热功率上限、初末SOC相等。SOC递推我自己习惯写成 SOC_{t1} SOC_t η_c·C_t - D_t/η_d蓄热效率乘在蓄热侧放热效率除在放热侧效率损耗就这么自然落进去。如果只想用一个总效率也可以写成 SOC_{t1} SOC_t η·C_t - D_t/η效果差别不大但要保持全文统一。2.3 容易出现问题的非线性项储热罐建模里有一个典型非线性同一时刻不能既蓄热又放热。严格处理需要0-1变量写成 C_t ≤ M·z_tD_t ≤ M·(1-z_t)z_t表示蓄热/放热模式。理论上只要目标函数合理模型会自动避免同时蓄放因为效率损耗白白浪费掉。但为了防止求解器中间迭代乱走建议还是把互斥约束显式加上反正一个二进制变量不贵。另一个容易被忽略的点是抽凝机组可行域可能非凸。纯凝和抽汽是两个工况需要两个0-1变量分别激活对应约束这比单纯加一条线性边界麻烦。我一开始没处理非凸可行域结果就是某些出力组合虽然满足所有边界实际却落在不可行区域结果看着合理拿去对比时完全对不上。所以这一块不能省一定要按工况激活。二次煤耗的分段线性化也同理用SOS2或二进制变量实现最终整体变成MILPGurobi处理起来很舒服。3. Matlab代码实现的关键环节3.1 场景数据怎么设置才贴近实际很多初学者上来就找大系统数据我的建议正好相反先在3台机组、24时段的系统上跑通再考虑扩展。我常用算例配置是两台抽凝式热电联产机组、一台纯凝火电机组、一个200MW风电场系统最大负荷600MW左右热负荷取冬季典型日曲线特点是夜间高、白天略低。主要参数表如下机组P_min(MW)P_max(MW)H_max(MW)爬坡(MW/h)煤耗系数(a,b,c)CHP14030022060(0.0004, 0.28, 8)CHP23025018050(0.0003, 0.25, 6)纯凝50200—40(0.0005, 0.31, 5)煤耗系数里c的单位是吨每小时量级我这里给出的是示意值关键在相对量级合理。风电出力序列可以取一个典型日夜间0到6点风电满发中午低。负荷序列用冬峰形状峰谷差约30%。开工之前先把负荷和风电曲线画出来看一眼单位统一到MW热负荷也用MW始终用同一个基准后面所有公式才不会乱。这个准备步骤看起来不起眼但数据单位不一致是模型“无解”的一大来源。3.2 YalmipGurobi建模流程我在Matlab里用Yalmip建模再调Gurobi求解。选Yalmip而不是直接用求解器的Matlab接口最大原因是语法接近数学模型变量、约束、目标几乎能一比一翻译排查问题时可以用display(constraint)直接看约束长什么样。流程五步定义决策变量定义约束集合定义目标函数调用optimize提取结果。决策变量用sdpvar定义连续量binvar定义0-1量约束用循环拼进一个Constraints数组目标函数把各项写成sum形式optimize的第三个参数是sdpsettings里面指定求解器、精度、时间限制求解完用value()取出各变量数值。有一个非常容易踩的坑Yalmip默认变量是连续的如果不小心把0-1变量定义成sdpvar整个模型变成LP算出来的结果从数学上“能用”但工况激活关系全丢了必须时刻留意变量类型。3.3 核心代码片段下面给一段简化后的核心建模片段变量维度和约束尽量贴合我的模型实际机组参数请按自己的算例调整T 24; P sdpvar(3, T); % 机组电出力 H sdpvar(2, T); % 两台CHP的热出力 C sdpvar(1, T); % 储热罐蓄热功率 D sdpvar(1, T); % 储热罐放热功率 SOC sdpvar(1, T1); % 储热罐状态量 z binvar(1, T); % 蓄热/放热互斥标志 Constraints []; % 电功率平衡风电 机组 - 弃风 负荷形状要对齐 Constraints [Constraints, sum(P,1) P_wind - P_curtail P_load]; % 热平衡机组热出力 放热 - 蓄热 热负荷 Constraints [Constraints, H(1,:) H(2,:) D - C H_load]; % 储热罐递推注意SOC维度比时段多一个 Constraints [Constraints, SOC(2:T1) SOC(1:T) eta_c*C - D/eta_d]; % 储热罐边界与周期约束 Constraints [Constraints, SOC(1) SocInit, SOC(T1) SocInit]; Constraints [Constraints, 0 SOC Cap]; Constraints [Constraints, C Cmax*z, D Dmax*(1-z)]; % 机组耦合约束示意两条线性边界 Constraints [Constraints, P(1,:) 40 0.2*H(1,:)]; Constraints [Constraints, P(1,:) 300 - 0.15*H(1,:)]; Objective sum(Cost) sum(CarbonPenalty) 500*sum(P_curtail); ops sdpsettings(solver,gurobi,verbose,0,mipgap,1e-4); sol optimize(Constraints, Objective, ops);代码最核心的就三件事SOC索引别错位、P_curtail定义非负、互斥约束把C和D分开。如果你把SOC(2:T1)和SOC(1:T)写反递推方向就反了储热罐会在夜间疯狂放热结果一眼看上去还“挺合理”拿工程实际一对照就露馅。3.4 结果怎么看改造前后对比求解完成后最重要的不是盯目标函数值而是把改造前和改造后的结果摆在一起对比。我算例里的结果大致如下方案运行成本(万元)碳排放量(t)弃风率(%)CHP最小电出力(MW)无储热改造128.6324012.8190有储热改造118.330852.1155解释一下这个结果的内生逻辑深夜热负荷高、电负荷低没有储热时两台CHP为了供热电出力压不下来风电被迫弃掉。有储热后深夜机组降低抽汽把富裕热量存进罐里电出力降下来后半夜风电几乎全消纳白天热负荷下降时再把罐里的热放出来机组不用额外提高出力。成本下降主要来自替代掉的弃风电量碳排放下降来自煤耗下降。要特别提醒的是储热罐不是纯收益来源蓄放热有损耗如果算例设计得不好可能出现储热容量过大、成本不降反升的情况这时候要多看几个容量方案而不是只跑一个。4. 常见问题与调试排查实录4.1 模型无解怎么排查我刚写这套模型时几乎每天面对“Infeasible problem”。排查顺序基本固定先把维度查一遍Yalmip里运维错误最常见于变量矩阵和负荷矩阵形状不匹配比如P_load是24x1列向量而sum(P,1)是1x24行向量两者相等时维度对不上要统一方向。再逐步排除把储热罐的SOC递推和热平衡暂时去掉跑一次纯电调度能解说明电平衡和机组约束没问题再把热平衡加回来如果挂了大概率是热负荷数值超了机组热出力上限或者储热罐参数没配对。一个非常有用的技巧求解后输出约束残差Yalmip里的check(Constraints)会逐条列出最大约束越限量残差最大的那条就是嫌疑对象。不要靠肉眼瞪代码几十条约束在眼前刷过去任何人的注意力都撑不住直接用工具把责任约束指出来最省时间。我还遇到过一种情况SOC初值和末值设成相等但储热容量太小24小时内的热量转移路径根本转不回来这时把末端约束去掉能解但结果不可用说明要么扩罐要么松初值。4.2 求解速度慢怎么办MILP模型在机组超过5台、时段扩展到96个之后会明显变慢。我常用的加速度手段有几个。一是砍二进制变量很多论文里用0-1变量模拟启停如果你的场景不关心机组启停就别加只保留工况激活必需的变量变量数量直接决定分支定界的搜索空间。二是给求解器设mipgap和时限工程上没必要追求最优性间隙为0做到1e-3以内就可以接受。三是把大M系数调小M太大会影响数值稳定性Gurobi有时候报Numerical issues本质是约束矩阵条件数太差。算例从24时段扩展到96时段时我一般先把风电、负荷曲线按4时段聚合缩成24段快速验证模型逻辑确认没问题后再跑完整时长。这个对比跑出来的结果曲线形状基本一致但计算时间能差一个数量级用来排查模型问题非常高效。4.3 结果出现反常识几种常见的反常识结果我基本都遇到过。储热罐明明加了弃风率反而更高先查互斥约束和SOC递推的符号我犯过一次把D和C写反的低级错误结果储热罐等于变成了“反储热”蓄热时段对应热负荷高峰放热时段对应热负荷低谷相当于给系统添乱。改造后总成本反而上升很可能是弃风惩罚系数偏低模型宁愿弃风也不愿意用储热罐储热罐纯损耗成本自然上升把惩罚系数调到高于边际煤耗再看。SOC曲线全天为0检查SOC初值末值条件以及储热罐容量是否错了一个数量级。容量100MWh但放热功率设成200MW两小时就空了曲线自然不合理。蓄热和放热数值相等多半是互斥约束没加或者z没用binvar定义变量被当成连续量处理用value看一眼z_t输出就能确认。4.4 复现文献结果要注意的细节复现类的经验最折腾人。期刊论文的算例参数往往给得不够完整特别是热负荷曲线的基准、机组的电热耦合系数、碳配额的计算方式这三样缺一处结果就差很远。我的做法是先把参数表整理成一个Excel参数输入页所有系数从同一个文件读入避免代码改到一半忘了还有一处参数没更新。热负荷单位是MW还是GJ/h、时间基准是秒还是小时、调度时段是15分钟还是1小时这些不起眼的单位直接决定约束系数的量级。论文复现时最好先挑一个最简单场景和文献给出的结果逐项对一下成本、碳排、SOC曲线对齐之后再扩大算例。如果某个模块对不上就把范围缩到该模块单独测试比如只测试储热罐的充放热往返效率单独跑一个“蓄满再放空”的小优化看SOC初末值是否一致。这种拆分定位的方式比从头到尾检查几十条约束靠谱得多。这套模型我跑了很多轮最大的体会是“储热罐不是越大越好也不是装上就一定有效”它能不能发挥作用取决于机组的电热耦合曲线和负荷曲线的形状是否匹配。热负荷峰谷差大的系统储热罐效果会非常明显热负荷平稳的系统里装大罐子只会增加损耗和投资。后续我的计划是把这套确定性的低碳经济调度扩展成考虑风电预测误差的鲁棒优化再加一层日内滚动让储热罐的调度策略更贴近实际运行。如果你正在做类似的课题建议先从三机组系统跑通再把机组规模往上加。
返回列表