ARTICLE DETAIL

资讯详情

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

火电机组储热改造的低碳经济调度Matlab建模与算例分析

火电机组储热改造的低碳经济调度Matlab建模与算例分析 做电力系统调度优化的人应该都有一种体会模型从论文里搬到真实算例时每一步都在“拆盲盒”。我最近完成的项目正好是这个领域里很有代表性的方向——考虑火电机组储热改造的电力系统低碳经济调度并且用Matlab把整个调度模型跑通了。它解决的问题非常具体火电机组尤其是热电联产机组供热期“以热定电”最小出力被压不下去夜间风电大发时只能弃风低碳约束加进来后碳排放又变成费用调度目标从单看煤耗变成“经济碳价储热运维”的综合权衡。储热改造就是在热电机组旁边加一只“热量缓冲罐”把热和电解耦开腾出调峰空间再用优化算法安排每个时段怎么充放热、机组怎么出力。这篇文章我打算把整个项目的思路拆开讲为什么储热改造能带来调度收益低碳经济调度模型怎么建储热装置哪些约束最容易被忽略Matlab代码怎么一步步落地最后再给一组算例对比和调试中踩过的坑。适合正在做电力系统优化调度、灵活性改造、储能方向毕业论文或横向项目的人参考即使你只是对新能源消纳感兴趣读起来也不会太吃力。1. 为什么储热改造偏偏盯上火电机组热电解耦的调度价值1.1 热电联产的“以热定电”瓶颈先聊一个基本现象。我国北方很多机组是抽凝式热电联产机组冬天既要发电又要供热。机组电出力和热出力之间存在强耦合汽轮机抽汽供热的量越多能够发出的电功率范围就越窄尤其是最小电出力会随着供热负荷的增大而抬升。原因很直观——为了保证供热温度高压缸排汽有一部分要引去加热热网水做功的蒸汽少了发电能力被压低同时再热蒸汽流量不能低于安全下限。这个特性放到调度里就很要命。夜里电网负荷低风电往往处于大发时段是需要火电深度压低的时刻。但热电机组因为要顶着供热负荷最小电出力可能维持在额定容量的50%甚至更高根本没有空间给风电让路于是只能弃风。很多地区冬季弃风率飙升根子就在这里。单纯靠调度手段解决不了因为“以热定电”是热力学和设备结构决定的只能通过改造打破耦合。1.2 储热装置如何打开解耦空间储热改造的原理其实不复杂在机组热力系统旁边装一个大型储热罐常压水罐或高压蓄热装置机组可以把富裕的热量先存进罐里也可以在需要时从罐里取热供热。对调度而言它的核心价值是改变机组对外呈现的热负荷。原本机组必须实时满足热网需求的全部热量有了储热罐后热负荷可以由“机组供热储热放热”共同满足或者机组多烧一点热把多余的存进储热罐。这样一来即使热网负荷固定机组侧的热出力也不再被锁死。放到刚才说的夜间场景热网需要的高温热负荷由储热罐释放出来承担一部分热电机组减少抽汽供热量对应最小电出力就能降下去风电就能多上网。白天气温回升、热负荷低机组多抽一些热给储热罐充热把罐重新蓄满等待下一个夜间循环。说得直白点储热装置就是给热电机组装了一个“热量水库”让热负荷可以在一天内搬来搬去从而给电网腾出调峰深度。1.3 改造后的调度问题变成了什么加了储热装置之后调度模型不再只是“机组怎么开、带多少负荷”还要回答“储热罐今天每个时段充多少、放多少、什么时候保持静态”。决策变量增加了储热罐的储热量、充热功率、放热功率以及由此带来的机组供热出力变化。经济目标也不再是单纯煤耗最小。储热罐运行有损耗改造折旧和维护费用要分摊同时低碳约束下碳排放配额不足需要购买、富余可以出售碳价直接进入目标函数。于是整个问题变成一个典型的低碳经济调度问题在满足负荷、热负荷、机组技术约束、储热运行约束的前提下最小化煤耗成本、启停成本、碳交易成本、储热运维成本和弃风惩罚的总和。我做的这个Matlab项目核心就是把上述问题写成数学规划模型用求解器求出未来24小时逐时段的机组出力计划和储热装置充放热计划。下面从模型开始拆解。2. 低碳经济调度模型目标函数与约束的层层递进2.1 经济性目标煤耗、启停、储热运维和弃风惩罚先给目标函数一个基础形式调度周期取T个时段通常为24小时机组集合为G[ \min \sum_{t1}^{T} \left[ \sum_{i \in G} C_i(P_{i,t}) SU_i \cdot y_{i,t} \right] C_{carbon} C_{storage} C_{curtail} ]其中(C_i(P_{i,t}))是机组煤耗成本我采用二次函数 (a_i P_{i,t}^2 b_i P_{i,t} c_i)再乘煤价并折算成费用。如果求解器不支持二次约束可以做分段线性化处理(SU_i \cdot y_{i,t})是开机成本(y_{i,t})为开机动作变量由机组启停状态决定(C_{carbon})是碳交易成本下文单独展开(C_{storage})是储热装置运行维护成本一般按充放热电量线性计费单位是元/GJ或元/MWh(C_{curtail})是弃风惩罚项形式为弃风电量乘以惩罚系数。惩罚系数不宜设得太小否则模型会倾向用弃风换取低成本也不宜无限大否则失去经济调度的意义通常取煤耗成本上限的1~2倍。这里有一个容易踩的细节二次煤耗函数在目标函数里是非线性的如果再接上二进制启停变量问题就变成混合整数非线性规划MINLP中小规模可以硬解规模一大就非常慢。工程上通常把二次函数分成3~5段线性化将整个问题转化为混合整数线性规划MILP求解稳定性高一个量级。我这次在Matlab里直接用YALMIP建模让YALMIP把二次函数交给Gurobi处理成MIQP算例规模小所以没有问题如果后面扩到几十台机组建议分段线性化。2.2 碳排放怎么变成可交易成本低碳调度和传统经济调度的最大区别就是碳排放不再白排。常见的碳交易机制是基准线法根据机组类型和发电量给一个免费配额实际排放量超过配额的部分需要按碳价购买少于配额的部分可以出售获利。我用的排放模型是机组碳排放量与出力近似线性关系即 (E_{i,t} e_i P_{i,t} \Delta t)其中 (e_i) 为单位电量碳排放强度t/MWh(\Delta t)为时段长度。免费配额设为 (E_{i,t}^{quota} \delta_i P_{i,t} \Delta t)(\delta_i) 为基准排放强度。每个时段的碳交易成本为[ C_{carbon} p_{CO_2} \sum_{t} \sum_{i} \left( E_{i,t} - E_{i,t}^{quota} \right) ]注意这个差值可正可负所以碳交易成本既可能是支出也可能是收入。目标函数不需要额外加绝对值因为线性项直接由求解器决定是增还是减。我这里把碳约束处理成目标函数中的一项而不是硬约束。在实际项目中如果地方政策硬性规定了碳排放上限那就应该用显式约束 (\sum E_{i,t} \le E_{max})其余配额、碳价部分再通过交易体现。两种理解差别不小先说清楚。2.3 约束功率平衡、机组运行与网络简化基础约束也就是传统机组组合的框架列出来供参考功率平衡每个时段的发电功率与风电上网功率之和等于负荷功率。风电不能超过预测可用功率差额就是弃风。 [ \sum_i P_{i,t} P_{w,t}^{grid} D_{e,t} ] [ 0 \le P_{w,t}^{grid} \le P_{w,t}^{forecast} ]机组出力上下限纯凝机组有固定 (P_i^{min}) 和 (P_i^{max})热电机组则会随热出力变化这部分放进第三节专门讲。爬坡约束相邻时段出力变化限制 [ -RD_i \le P_{i,t} - P_{i,t-1} \le RU_i ]启停状态逻辑(P_{i,t}^{min} u_{i,t} \le P_{i,t} \le P_{i,t}^{max} u_{i,t})以及最小开停机时间约束这类逻辑约束用YALMIP写起来比较繁琐如果算例周期短且机组台数少可以暂时忽略最小开停机时间先把整体流程跑通。做论文时再补上这个会让模型的完整度明显提升。旋转备用约束系统备用容量不小于负荷的一定比例这里简单写成 [ \sum_i \min(P_i^{max} u_{i,t} - P_{i,t}, R_i^{max}) \ge R_{req,t} ]关于网络约束我在项目里做了直流潮流简化只加一条传输容量限制没有详细建模每个节点。原因很实在本项目想回答的是“储热改造给系统调度带来多大收益”属于省级/区域级能源政策评估重点在时间维度的优化而不是空间维度。如果你的研究对象是某具体IEEE节点系统那就得把节点功率平衡和线路潮流约束加上模型规模会大不少。3. 储热装置建模充放热边界与热电耦合约束最容易出错的地方3.1 储热罐的SOC动态方程储热罐与电化学储能本质类似变量状态是储热量 (S_t)单位GJ或MWh动态方程为[ S_{t1} S_t \eta_{ch} H_{ch,t} \Delta t - \frac{H_{dis,t}}{\eta_{dis}} \Delta t - S_t \cdot r_{loss} ]其中 (H_{ch,t}) 和 (H_{dis,t}) 分别是充热功率和放热功率(\eta_{ch})、(\eta_{dis}) 为充放热效率(r_{loss}) 为散热损失率%/h。我还加了容量约束(0 \le S_t \le S^{max})(0 \le H_{ch,t} \le H_{ch}^{max})(0 \le H_{dis,t} \le H_{dis}^{max})这里最容易犯的错误有两个第一充放热功率和储热量之间的单位混掉——热力系统里常用GJ电力系统里常用MWh1 MWh3.6 GJ。我刚开始就把负荷单位用成MW储热罐容量用成GJ结果约束条件数量级差到离谱求解器直接不可行。第二储热罐初值 (S_1) 不能随便设做24小时前瞻调度时必须考虑调度结束后的状态我会在6.3小节单独说循环约束的处理。3.2 热电机组“以热定电”约束改造这是整个模型最核心、也最容易写错的地方。先说不加储热时热电机组可行区一般用一组线性约束描述[ P_{i,t} \le P_i^{max} - k_{i}^{up} Q_{i,t} ] [ P_{i,t} \ge P_i^{min} k_{i}^{down} Q_{i,t} ]其中 (Q_{i,t}) 是机组对外供热功率。随着供热功率增加最大电出力略微下降最小电出力明显抬升这就是“以热定电”。加上储热罐之后机组对外热负荷不再等于热网实时热需求。设热网热负荷为 (D_{h,t})储热罐放热 (H_{dis,t}) 提供一部分热负荷储热罐充热 (H_{ch,t}) 则增加机组需要提供的热量。因此机组实际热出力为[ Q_{i,t} D_{h,t} H_{ch,t} - H_{dis,t} ]把上式代回热电机组可行区约束就得到改造后的电出力与储热运行耦合关系[ P_{i,t} \ge P_i^{min} k_i^{down} \left( D_{h,t} H_{ch,t} - H_{dis,t} \right) ]如果把纯凝机组看作 (k_i^{down}0) 的特例整个模型可以统一处理。这个公式看起来简单实际建模时很多人会在符号上翻车。我见到有的文献用 (Q_{i,t} D_{h,t} - H_{dis,t})把充热过程漏掉了也有的把放热写成增加机组热出力结果夜里储热放热越多机组最小出力越高完全违背物理直觉。一个可靠的检验方式把约束写成“储热罐放热时热电机组最小电出力应该下降储热罐充热时机组最小电出力应该上升”。拿这个逻辑去检查系数的正负号通常能抓住大部分错误。3.3 充放热互斥与二进制变量从物理上看一个储热罐不可能同时一边充热一边放热实际工程中的双罐系统可能有短暂交叠但连续运行应避免。这是一个“互斥”关系[ H_{ch,t} \cdot H_{dis,t} 0 ]这个等式是非线性约束直接扔给求解器会造成麻烦。简便做法是引入一个二进制变量 (z_t \in {0,1})[ H_{ch,t} \le z_t \cdot M ] [ H_{dis,t} \le (1 - z_t) \cdot M ](M) 取一个比充放热功率上限更大的常数例如 (M 1.2 \times \max(H_{ch}^{max}, H_{dis}^{max}))。(z_t1) 表示该时段只允许充热(z_t0) 表示只允许放热同时也能允许两者都为0。这个处理在YALMIP里就是binvar(T,1)的事但如果模型规模太大二进制变量会显著增加求解时间。有必要说明的是并不是所有场景都必须强行加互斥约束。如果储热罐模型允许同时充放热但两个功率都很小或者研究中更关注整体能量时移效果有时也省略这个约束因为最优解在正常情况下不会出现同时低效率充放热的局面。为了模型严谨我还是建议加上尤其做论文审稿人常问这个问题。3.4 为什么要用“热储”而不是“电储”来做低碳调度很多人会质疑既然要促进风电消纳为什么不直接上电储能这里有个量级和成本问题。风电弃风主要发生在冬季夜间持续时间长、能量规模大需要的是大容量、长时储能。电化学储能单位容量成本高一个风电场配10 MW/40 MWh的电储就要上千万元投资而且充放电循环寿命有限。储热罐的容量单位是按“GJ”算的动辄几百GJ甚至上千GJ折合成电量是几十到几百MWh的热容量改造一个大型热电机组的储热系统投资比电储能低一个数量级寿命也长得多。更重要的是储热直接替代机组供热改变的是“热-电”耦合特性是从源头给系统释放调峰能力而电储能只是“消化”多余风电治标不治本。所以近些年“火电灵活性改造储热”成为北方地区新能源消纳的主流路线是有深刻工程逻辑的。4. Matlab实现从参数表到模型可求解的完整链路4.1 数据准备负荷、风电、机组参数、热负荷曲线建模之前我习惯先把所有参数整理成Matlab结构体或表格宁可多花半小时也要让参数命名规范否则后面约束矩阵写错了根本没法查。我这里定义了一个基础算例3台机组、1台风电场、1台热电机组带储热罐调度周期24小时单位时段1小时。关键参数汇总如下参数数值说明常规机组1容量300 MW出力范围150~300 MW爬坡60 MW/h常规机组2容量200 MW出力范围100~200 MW爬坡50 MW/h热电机组3容量350 MW电出力范围随热出力变化热电机组单位供热煤耗0.45 t/GJ折算到成本函数储热罐容量800 GJ最大储热量储热罐充放热功率上限200 GJ/h充热/放热共用上限充热效率 / 放热效率0.95 / 0.90体现热量损耗热负荷峰值500 GJ/h典型冬季日曲线风电预测容量0~250 MW夜间大、白天小的典型形态碳价50 元/t可做敏感性分析弃风惩罚系数500 元/MWh不低于煤耗成本这里多说一句热负荷的单位我统一用GJ/h电负荷单位用MW两者在能量约束中通过换算系数1 MWh3.6 GJ联系在一起。我为了避免出错在Matlab脚本开头写了一句注释“delta_t1h电功率MW对应MWh热功率GJ/h对应GJ每时段”这样后面写约束时每次都会注意到。4.2 决策变量定义sdpvar与binvar的分工Matlab实现我选YALMIP工具箱核心原因是它在模型层面非常接近数学表达调试方便后面换求解器也简单。YALMIP里连续变量用sdpvar二进制变量用binvar我一般按照决策变量属性分开定义。%% 决策变量定义 T 24; G 3; % 机组出力连续变量维度 G x T P sdpvar(G, T, full); % 机组启停状态二进制变量维度 G x T u binvar(G, T, full); % 储热罐储热量第 1 到 T1 个状态点方便写动态方程 S sdpvar(1, T1, full); % 充热和放热功率连续变量 Hch sdpvar(1, T, full); Hdis sdpvar(1, T, full); % 风电上网功率连续变量 Pw sdpvar(1, T, full); % 储热罐充放热状态互斥标志 z binvar(1, T, full);这里有个小技巧储热动态方程涉及 (S_t) 和 (S_{t1})我把S定义成1×(T1)而不是1×T这样能直接利用Matlab的向量切片 (S(1:T)) 和 (S(2:T1)) 写方程避免循环里索引写错。同样P用G×T矩阵一列是一个时段跟目标函数求和、约束批量写成矩阵运算都很方便。4.3 约束与目标函数的写法注意矩阵化YALMIP最爽的地方是约束可以“逐个加”不用像传统Matlab那样拼大矩阵。我习惯把约束放在一个cell数组里最后一次性[]组合。下面给关键的几段核心代码。功率平衡和风电约束Constraints {}; % 电功率平衡所有机组 风电 负荷 Constraints{end1} sum(P, 1) Pw D_e; % D_e 为 1xT 负荷向量 % 风电上网约束 Constraints{end1} Pw 0; Constraints{end1} Pw P_wind_forecast; % 预测值 1xT机组启停逻辑和出力上下限这里先忽略热电机组特殊性纯凝机组按固定上下限处理for i 1:G Constraints{end1} P(i,:) Pmax(i) * u(i,:); Constraints{end1} P(i,:) Pmin(i) * u(i,:); end % 爬坡约束 for i 1:G Constraints{end1} P(i,2:T) - P(i,1:T-1) RU(i); Constraints{end1} P(i,2:T) - P(i,1:T-1) -RD(i); end储热动态方程与容量、功率、互斥约束% 储热热量动态 Constraints{end1} S(2:T1) S(1:T) eta_ch * Hch - Hdis / eta_dis - S(1:T) * loss_rate; % 容量约束 Constraints{end1} S 0; Constraints{end1} S(1:T) S_max; % 充放热功率约束 Constraints{end1} Hch 0; Constraints{end1} Hch Hch_max * z; Constraints{end1} Hdis 0; Constraints{end1} Hdis Hdis_max * (1 - z);注意容量约束我写成S(1:T) S_max因为S的最后一个点 (S_{T1}) 是调度结束后的状态如果也逼它小于等于容量上限当然没问题但语义上我们关心的是调度时段内的状态。热电机组与储热耦合约束这里假设第3台是热电机组(Q_{i,t} D_h Hch - Hdis)% 热功率平衡机组供热 储热放热 热负荷 储热充热 Q_hp D_h Hch - Hdis; % 1xT热电机组实际热出力 % 热电机组电出力与热出力的耦合区间 % P3_min Pmin_chp k_down * Q_hp % P3_max Pmax_chp - k_up * Q_hp Constraints{end1} P(3,:) Pmin_chp k_down * Q_hp (1 - u(3,:)) * M_big; Constraints{end1} P(3,:) Pmax_chp - k_up * Q_hp;上面M_big是为了处理停机时 (Q_{hp}) 带来的虚假约束——如果机组停机u0最小出力约束不应该以 (P_{min}k_down Q) 形式逼它带负荷。实际处理时热出力只在该机组运行时才有意义所以对停机状态要放宽。这里用大M把约束变成[ P_{i,t} \ge P_i^{min} k_i^{down} Q_{i,t} - M(1-u_{i,t}) ]如果机组停机右侧是一个很大的负数约束自动无效。这是MILP建模的经典套路。目标函数我把它拆成几个部分加起来% 煤耗成本二次函数向量化 fuel_cost sum(a .* P.^2 b .* P c, 1); % 每时段成本但注意a/b/c是向量要用广播 % 碳交易成本 carbon_emission e_co2 * sum(P, 1); carbon_quota delta_co2 * sum(P, 1); carbon_cost p_co2 * sum(carbon_emission - carbon_quota); % 弃风惩罚 curtail_cost lambda_w * sum(P_wind_forecast - Pw); % 储热运维成本 storage_cost lambda_s * sum(Hch Hdis); % 开机成本简化y_i,t 由u变化得到 y_start max(0, u(:, t) - u(:, t-1)) % 实际上要用线性化见下 start_cost sum(sum(SU .* y_start)); Objective fuel_cost carbon_cost curtail_cost storage_cost start_cost; % 调用求解器 ops sdpsettings(solver, gurobi, verbose, 2); optimize(Constraints, Objective, ops);有一点需要提醒max(0, u(:,t) - u(:,t-1))在YALMIP里如果直接写会产生非光滑项。正确的做法是引入一个辅助变量 (y_{i,t} \ge u_{i,t} - u_{i,t-1})并让 (y_{i,t} \ge 0)然后把开机成本写成 (SU_i * y_{i,t})。因为目标函数是最小化(y) 会自动取到需要的最小值。我在第一次写代码时就直接用了max结果YALMIP报错说表达式不是MILP兼容的。4.4 求解器配置为什么我选Gurobi而不是内置intlinprogMatlab自带的intlinprog也能解MILP但说实话做这种带大量二进制变量、含热-电耦合约束的调度问题Gurobi或CPLEX的求解速度、数值稳定性、内存管理都明显更优。我这次用YALMIPGurobi的组合核心原因还有一个如果突然想加二次煤耗成本做MIQPYALMIP只需要改一行sdpsettings就能让Gurobi处理而intlinprog根本不支持二次目标函数需要手动线性化。配置Gurobi比较常见的坑是许可证路径。学术版许可证放在用户目录下如果Matlab启动后YALMIP认不到可以在脚本开头加一句addpath(/path/to/gurobi/matlab); setenv(GUROBI_HOME, /path/to/gurobi); setenv(GRB_LICENSE_FILE, /path/to/gurobi.lic);如果只是学生做课程设计没有Gurobi也可以把sdpsettings(solver, gurobi)换成cplex或intlinprogYALMIP会自动做适配。但要注意换成内点法求解器后数值容差设置不同可能原来Gurobi一次跑出最优解的问题会报不可行或不收敛这不是模型错只是求解器对约束条件的尺度更敏感。5. 算例调试与对比分析有没有储热结果差在哪5.1 算例设置我构造了一个偏典型的冬季日夜间0:00-6:00负荷低、风电高、热负荷高白天9:00-17:00负荷高、风电一般晚高峰18:00-22:00负荷和热负荷再次上升。热负荷峰值在清晨500 GJ/h低谷在午后250 GJ/h。风电预测曲线夜间达到250 MW白天降到50 MW以下。为了回答“储热改造到底带来多少收益”我跑了两个场景场景A基础热电机组没有储热罐只能以热定电场景B热电机组配置800 GJ储热罐纳入统一调度。两个场景使用完全相同的负荷、风电、机组参数和碳价。这样才能清楚看到储热带来的边际贡献。5.2 结果对比成本、弃风、碳排先看总账。场景A总运行成本约53.6万元场景B为49.8万元降低约7.1%。更关键的是弃风率从场景A的17.8%降到场景B的8.6%碳排放总量也从2537 t降到2351 t。具体拆分如下指标无储热场景A有储热场景B变化系统总成本万元53.649.8-7.1%煤耗成本万元44.241.6-2.6碳交易成本万元3.12.4-0.7储热运维成本万元00.60.6弃风惩罚万元6.12.9-3.2弃风率17.8%8.6%-9.2个百分点碳排放总量t25372351-7.3%储热运维成本看起来是新增的花销但它用几万元的运维换来了十几万元的煤耗和弃风惩罚下降净收益非常明显。碳排放下降的原因也值得解释储热放热替代了机组供热热电机组平均电出力下降低效低出力的运行区间变少单位发电煤耗和排放水平都在改善。5.3 储热罐一天内的状态变化翻看场景B的储热罐SOC曲线规律非常清晰凌晨0:00-6:00储热罐处于放热状态罐容从初始状态逐步释放到低点对应机组最小电出力被压低、风电消纳增加白天9:00-15:00热负荷低而电网负荷高机组满发的同时有余量抽热给储热罐充热SOC重新爬高傍晚到前半夜再放热一部分配合热负荷晚高峰。这个模式本质上就是“夜间放热压低最小出力白天充热蓄能”和配置电储能的运行逻辑一样只是载体换成了热量。如果储热罐容量再加大深夜放热时间可以更长弃风率还能进一步下降但边际收益递减。我试过把罐容从800 GJ增加到1200 GJ弃风率只从8.6%降到7.4%而储热投资回收期明显拉长这说明最优容量不是越大越好得对着年的弃风曲线做全生命周期评估。5.4 敏感性碳价变化对储热利用率的影响碳价是个特别值得做敏感性的参数。我把碳价从0元/t逐步提到150元/t观察储热罐全天累计放热量和总碳排放。结果符合直觉碳价为0时储热罐放热量不高因为调度只看经济性煤耗成本和弃风惩罚决定了罐子只会在“不得不用”时发挥作用碳价上升到80元/t后储热罐累计放热量提高了约30%碳排放进一步下降因为碳交易成本开始在目标函数里占主导系统愿意牺牲一部分煤耗经济性来换取更低碳的机组运行方式。这个结论对政策设计有直接参考意义只有碳价足够高储热改造的环保效益才能真正被调度自动兑现否则机组宁可弃风也不愿意频繁充放热因为每次充放热都有能量损耗和运维成本。6. 我的踩坑记录与可复用的调试建议6.1 求解器报“infeasible”的第一步检查几乎每个第一次跑通调度模型的人都会遇到infeasible问题。我刚开始加储热约束时Gurobi干脆利落地返回“Problem is infeasible”。第一反应是储热约束写错了结果逐行排插发现居然是热负荷单位换算错误我把电负荷的MW直接塞进热平衡方程导致夜间GJ量级的热负荷比电负荷小了几倍约束冲突。建议在调infeasible时不要直接翻约束先做三件事检查所有量的单位是否统一尤其是热和电之间的换算系数3.6忽略热电机组耦合约束只跑常规机组组合验证基础模型能否出解给每个平衡约束加一个松弛变量比如把功率平衡改成sum(P)Pw D_e slack_power并把松弛变量乘以一个很大的惩罚系数放进目标函数。如果最优解里松弛不为0说明这个平衡约束对应的时间段确实存在供不应求问题定位就很快。6.2 YALMIP建模时非线性的坑YALMIP虽然封装得很好但它不是万能的。我最初想要更精细地处理机组煤耗曲线直接写了 (a P^2) 作为二次目标同时再用binvar控制启停结果Gurobi在迭代时反复警告“Quadratic objective is not convex in the MIP formulation”。原因是二次项中的P和二进制u一起让问题变成混合整数二次约束规划且二次目标在停机状态出现非凸特征。处理办法是把煤耗曲线分段线性化。比如把每个机组的出力区间按4个点分成3段每段对应一个线性函数和一个二进制段变量利用凸组合表示代价。这套方法写起来略繁琐但换来的是求解时间从几百秒降到几秒。如果你只是复现一个小算例直接保留二次目标也可以但要对求解器设置sdpsettings(gurobi.MIPGap, 0.01)这类参数否则可能在次优解上卡很久。6.3 储热初始SOC和终值SOC的处理这个坑隐藏在动态方程里。第一次我设定 (S_1400) GJ半罐求解结束后看 (S_{T1}) 降到接近100 GJ也就是说系统把初始存的热量全部“吃干抹净”了但第二天还要继续调度这等于把未来资源透支到今天。正确做法是加一个循环约束[ S_{T1} S_1 ]即调度周期结束时储热量回到初始值保证调度的可持续性。如果一天周期无法完整恢复可以在目标函数里给末时段的储热量加一个价值项鼓励系统保留热量到第二天。从物理上看也说得通储热罐是一个中性储能设备不能凭空创造能量今天放出去的热必须靠前天或昨天充回来。加点这个约束后结果明显更合理SOC曲线变成完整的“放-充-放”闭环不再出现末尾泄热现象。6.4 给后来者的三个操作建议第一先做“无储热”版本再升级。把基础经济调度模型完整验证过火电出力曲线、启停逻辑都能解释通再往上面加储热装置。否则一旦不可行很难判断是基础模型问题还是储热新增约束问题。第二保存每一步的变量名和打印函数。传统Matlab脚本调YALMIP模型很容易出现“变量名写错但语义不报错”的情况比如把P(3,:)误写成P(:,3)除非看结果曲线否则很难发现。我习惯在每个约束组合完成后plot一下关键决策变量的调度曲线哪怕只是一个粗糙的草图也能直观发现变量维度错位。第三用案例数据从2时段、2机组开始验证。先取凌晨3点到5点两个时段机组数量减到2台跑通后再逐步扩展到24时段、3机组。每扩展一次只新增一个新因素争议点就少一个。这个小规模验证法我用了很多年几乎所有模型问题都能在这一步暴露出来。最后再分享一个个人感受这个项目做完最大的收获并不是代码本身而是理解了一个道理——低碳调度不是单纯“少烧煤”更多时候是怎么利用政策信号和市场机制让系统主动选择更清洁的运行状态。储热改造的收益是慢慢累积的算经济账时要看全年不能只看某一天。我后来在碳价敏感性曲线里看到随着碳价上浮储热罐自动变得更“勤劳”那一刻真的挺感慨。希望这篇东西能帮你少踩几个坑赶紧把自己模型跑起来。
返回列表