资讯动态

考虑可再生能源消纳的电热综合能源日前经济调度模型实现

发布时间:2026/9/28 14:41:00 来源:尧图企业网站定制
做综合能源调度的这几年我越来越觉得电热耦合这步棋是整个系统能不能转起来的关键。很多刚入门的朋友拿到“考虑可再生能源消纳的电热综合能源系统日前经济调度模型”这个题目第一反应是找代码、跑通算例但真的把模型拆开看会发现难点根本不在编程而在怎么把“热”和“电”这两套物理约束拧成一个可求解的优化问题。这篇文章我就从模型设计、Matlab实现到算例调试把我实际做这个项目的过程完整捋一遍包括那些教科书里不会写、但你在跑代码时一定会踩的坑。这个模型解决的痛点很明确当风电、光伏大规模接入后传统电力调度只盯着电量平衡结果就是夜间风电大发时火电还在为供热“以热定电”扛着出力大量清洁能源被白白弃掉。电热综合能源系统把热力管网、储热装置、电锅炉、热电联产机组放进同一个日前调度框架里让热负荷也参与调节从而给可再生能源腾出消纳空间。适合正在做毕业设计、写论文或刚接触综合能源优化的研究生以及想从零搭建调度框架的工程师参考。1. 模型设计与拆解1.1 为什么要做“电热”联合调度而不是分开调度传统调度模式里电力系统和热力系统各管各的电力调度只关心发电成本热力调度只保证每个热力站不冻管。问题是现在很多区域里供热的主力是热电联产机组它发电的同时必须产热发电出力往往由热负荷决定——这就是常说的“以热定电”。夜间热负荷高的时候机组得开足马力产热电也跟着发出来偏偏这时风电又是高峰多余的电送不出去只能弃风。把电热放在同一个模型里本质上是给调度员增加了一个自由度当风电大时可以启动电锅炉把多余的电转成热或者让储热罐先蓄热、让热电机组少发电多产热这样一来机组的电出力约束就松动了弃风量自然降下来。这个“耦合”就是整个模型最有价值的地方。做这个模型前一定要先想清楚你研究的是“热-电”的什么耦合方式。最常见的耦合设备是热电联产机组它的电出力和热出力之间有很强的约束关系另一种是电锅炉它吃电产热第三种是热泵也是耗电产热。设备不同模型的结构差异非常大代码框架也会不一样。1.2 日前经济调度的基本框架所谓“日前调度”就是提前一天把未来24小时的运行计划排出来时间尺度通常是1小时一个时段也有用15分钟作为分辨率的。调度的目标函数一般是系统总运行成本最小化包括火电机组的煤耗成本、热电联产机组的成本、储热装置的运行维护成本、弃风惩罚成本有时还包括机组启停成本。约束条件则包括电力平衡约束、热力平衡约束、机组出力上下限、爬坡约束、最小开停机时间、储能装置充放热约束以及风电出力上限约束。整个模型在数学上是一个混合整数线性规划问题——因为有启停变量存在需要被表达为“开还是不开”的0-1决策而连续变量决定出力是多少。这类问题用成熟的商业求解器可以处理得很干净关键是建模时候的线性化处理。很多初次接触的人会问为什么非要用整数变量因为机组启停本质上是逻辑决策开着的机组才能出力关着的机组出力必须是0这种“二选一”的逻辑需要整数变量来表达。这也是为什么这题不是单纯线性规划也不能用简单的梯度下降类方法直接解。1.3 可再生能源消纳的量化方式在模型中体现“可再生能源消纳”最直接的手段是在目标函数里加入弃风惩罚项。风电预测出力是给定的上限实际调度中风电可以被削减但削减的量会产生经济惩罚。惩罚系数设多大很讲究——设小了系统宁可弃风也不调整热电机组设大了模型会不计代价地用储热、电锅炉去消纳风电甚至导致不经济的运行方式。实际操作中我一般把弃风惩罚系数设为燃煤机组边际成本的1.2到1.5倍这样系统在“花钱调整热力侧”和“容忍弃风”之间有一个合理的折中。这个值是经验性的但算例结果表明在这个区间内模型的弃风量和总成本对惩罚系数不敏感比较稳定。如果你写的论文里要做敏感性分析这个系数就是现成的一个参数。2. 核心数学模型与代码实现要点2.1 设备建模的数学表达热电联产机组的建模是这里最核心的部分。常见的热电联产机组运行区间是一个多边形可行域电出力P和热出力H组合必须落在某个凸多边形内。工程上最常用的表达方式是可行域由若干个线性不等式刻画P_min c1 * H P P_max - c2 * H H_min H H_max这里的系数c1、c2反映了“多产热就得多压电”或“背压运行”的限制。更精细的模型还会区分不同的运行模式但初版模型用一组线性约束就够了。对于背压式机组电出力和热出力存在一个近似的比例关系这时直接写成P k * H即可线性化反而更简单。电锅炉模型则是很干净的一个环节它的输入是电功率P_EB输出热功率等于P_EB * eta_EB范围从0到额定功率连续可调。电锅炉的好处在于响应快、调节范围大是消纳风电的主力设备。储热装置建模有点意思因为它的状态变量——储热量——是跨时段耦合的。上一时段的储热量加上本时段充入的热量、减去放出的热量和热损失就是下一时段的储热量。这个状态更新关系是日前调度里时间耦合的核心也是代码实现时最容易出错的地方。2.2 典型目标函数与约束条件我用的目标函数形态是这样的min sum_t ( C_fuel(P_fire(t)) C_chp(P_chp(t), H_chp(t)) C_eb(P_eb(t)) C_storage(charge, discharge) C_curtail * P_wind_curtail(t) )其中C_fuel用二次函数表示但求解器需要线性或二次约束都行。如果使用Gurobi这类支持二次目标的求解器可以直接保留二次项如果只用intlinprog就必须把二次项分段线性化。分段线性化的做法是把燃料费用曲线按出力区间切成几段每一段用线性函数逼近。段数不用太多4到6段就足够工程精度了。电力平衡约束sum P_g(i,t) P_wind_avail(t) - P_wind_curtail(t) P_eb(t) P_storage_discharge(t) P_load(t) P_storage_charge(t)注意电锅炉在这里是负荷是消耗电力的。热力平衡约束sum H_chp(i,t) H_eb(t) H_storage_discharge(t) H_load(t) H_storage_charge(t)储热装置的充放热不能同时进行这个逻辑要加二进制变量或者用Big-M约束表达否则模型会同时充放热刷数据。这也是新手最常见的建模错误之一。2.3 Matlab中用YALMIP搭建优化模型Matlab实现我强烈推荐走YALMIP工具箱加外部求解器的路线。YALMIP让模型的符号表达非常直观几乎能跟数学公式一一对应。首先定义时间维度变量nPeriods 24; % 连续变量 P_chp sdpvar(nUnits, nPeriods, full); % 热电联产电出力 H_chp sdpvar(nUnits, nPeriods, full); % 热电联产热出力 P_wind_curtail sdpvar(1, nPeriods, full); % 弃风功率 Q_charge sdpvar(1, nPeriods, full); % 储热充电功率 Q_discharge sdpvar(1, nPeriods, full); % 储热放电功率 SOC sdpvar(1, nPeriods1, full); % 储热状态多一个时段存初值 % 二进制变量 u_chp binvar(nUnits, nPeriods, full); % 机组启停状态 u_chg binvar(1, nPeriods, full); % 储热充热标志 u_dis binvar(1, nPeriods, full); % 储热放热标志看到这里你应该已经体会到YALMIP的好处就是不用手工拼大矩阵。但不要高兴太早——变量定义清楚只是第一步约束怎么加才是重头戏。2.4 约束的YALMIP表达技巧机组出力上限约束要绑定启停状态Constraints []; for t 1:nPeriods Constraints [Constraints, P_chp_min * u_chp(:,t) P_chp(:,t) P_chp_max * u_chp(:,t)]; end这个约束的含义是如果机组关停出力被钳制在0如果开启出力在上下限内。这个写法还能顺便把“停机时出力必须为0”表达出来不需要额外加约束。储热充放热互斥约束用Big-M方式表达M max(Q_charge_max, Q_discharge_max); % Big-M的取值 Constraints [Constraints, Q_charge M * u_chg]; Constraints [Constraints, Q_discharge M * u_dis]; Constraints [Constraints, u_chg u_dis 1];这里把两个二进制变量加起来不超过1彻底阻断同时充放的可能性。注意Big-M的取值不能过大否则会破坏数值稳定性取设备额定功率的1.2倍即可。储热状态递推约束eta_chg 0.95; % 充热效率 eta_dis 0.95; % 放热效率 eta_loss 0.98; % 时段热保持率 for t 1:nPeriods Constraints [Constraints, SOC(t1) eta_loss * SOC(t) eta_chg * Q_charge(t) - Q_discharge(t)/eta_dis]; end Constraints [Constraints, SOC(1) SOC(nPeriods1)]; % 周期性边界很多做这个方向的人会漏掉热损失系数eta_loss虽然它只有0.02的影响但在24小时的尺度下累计热损失对储热罐的有效容量影响非常明显不加会高估储热装置的消纳能力。3. 完整求解流程与算例分析3.1 求解器配置与参数设置我用的求解器是Gurobi通过YALMIP调用。Gurobi在求解混合整数线性规划方面目前是行业标杆处理这类模型速度很快。如果你的机器上装不了Gurobi也可以退而用intlinprog但需要先把YALMIP模型导出成标准形式代码会绕一些。一个需要注意的坑是Gurobi和YALMIP的版本兼容问题。新版本的YALMIP对Gurobi的接口有变化如果调用时遇到“Unable to solve”这种玄学报错先把YALMIP升级到最新版。我一开始用的是老版本YALMIP配Gurobi 9.5折腾了两天才发现是接口不兼容。调用求解器的代码非常简单ops sdpsettings(solver, gurobi, verbose, 1, gurobi.MIPGap, 0.01); optimize(Constraints, Objective, ops);MIPGap设成0.01表示允许1%的次优解求解速度会快很多。对一篇学术论文来说1%的gap完全在可接受范围内但对一些特殊的对比场景我会把gap收紧到0.001再跑一次确认结果稳定。3.2 典型日负荷数据与算例场景设计做算例时不要一上来就上全年数据先用一个“典型日”的数据把模型跑通。典型日我选了冬季采暖期的数据因为这时热负荷高、风电出力也高电热矛盾最突出最能体现模型效果。风电出力曲线模拟了夜间的反调峰特性——晚上风大、负荷低。热负荷曲线则模拟了早晚两个高峰。对比场景的设置非常重要这会直接决定你论文的说服力。我设计了三个场景场景一传统分产调度电热完全解耦机组按各自负荷平衡运行。场景二电热联合调度有电锅炉但无储热装置。场景三电热联合调度同时配置电锅炉和储热装置。这样梯度式的场景设计可以清晰地分离出电热耦合的贡献和储热装置的增量贡献。3.3 结果对比与消纳效果解读跑完三个场景后的数据非常直观。场景一的弃风率粗略估算在18%左右系统总运行成本最高。场景二加入电锅炉后弃风率下降到了7%左右——电锅炉在夜间风电高峰时段投入产热相当于给风电开了一道“出口”。场景三配置储热后弃风率进一步降到2%以下而且储热装置白天放热成功把电锅炉夜间的产热量转移到白天使用进一步拉低了热电联产机组的电出力。值得注意的是单看总成本三个场景的差异并不像弃风率那样显著因为弃风惩罚成本在总成本中占比不高。但如果在目标函数里把碳成本或环境成本也算进去场景间的差距会拉大不少。这也是现在很多论文把碳交易机制引入电热综合调度模型的原因。3.4 调度结果的曲线绘制与导出Matlab做结果可视化是它的强项这部分我一般分三个图第一个图是电力平衡图画负荷、各机组出力、风电实际出力、电锅炉耗电的堆叠面积图和折线图能直观看到各时段电力从哪里来的。第二个图是热力平衡图展示热电联产机组热出力、电锅炉热出力、储热充放热与热负荷的匹配关系。第三个图是弃风率柱状图或风电消纳率曲线用来做场景对比。绘图的细节上有个心得用面积图展示电力平衡时要按“负荷从下到上堆叠电源从下到上堆叠”的方式对齐不然图很乱审稿人会挑剔。另外在坐标轴标注上一定要注明单位MW和MWh不要混用这是很多人容易被指出的细节问题。4. 调试经验与常见问题4.1 模型不可行的快速排查法电热综合能源系统模型规模不算大但变量多、约束多极易出现不可行。不可行的原因千奇百怪但九成以上出在约束矛盾。我最常用的排查法是“逐步释放约束法”。先把所有耦合约束电力平衡、热力平衡去掉只保留变量边界约束看模型能不能解。如果能解再依次加回热力平衡、电力平衡、设备出力约束、储热递推约束。每加一组约束跑一次发现哪次跑不通了问题就锁定在哪一组约束上。这个方法的效率远高于对着报错信息瞎猜。另外一个很关键的调试技巧是用一个“参考解”来验证。先把所有整数变量固定到一个已知可行的启停组合求解连续变量模型。如果连续层面都不可行大概率是某个连续变量的边界约束写错了如果连续层面可行而整数层面不可行那就要去看启停组合和出力上下限数值的匹配关系。4.2 求解时间过长怎么优化如果你用的求解器在默认参数下跑一个小时还没出结果大概率不是模型规模大而是约束写得不够紧凑。混合整数线性规划的求解时间和模型对称性、Big-M大小、约束冗余度都有关系。我踩过的坑主要有两个第一个坑是储热装置的互斥约束Big-M设得太大。比如我一开始把M设成了1000虽然这在数学上是正确的但让求解器的分支定界过程非常痛苦。把M缩到额定功率的1.2倍后求解时间直接降了一个数量级。第二个坑是没给求解器提供好的初始解。YALMIP支持提供x0如果你知道一个合理的热电联产机组启停方案可以先跑一个不带整数约束的松弛解把它round成整数作为初始值传进去assign(u_chp, round(value(u_chp, relax))); optimize(Constraints, Objective, ops, u_chp);这个方法在很多模型里能把求解时间压缩到原来的三分之一。4.3 关于调参的一个系统化方法很多朋友拿到模型总纠结参数怎么调我的建议是先做灵敏度分析锁定敏感参数。电热综合能源系统里最值得做灵敏度分析的参数是弃风惩罚系数、储热罐容量、电锅炉额定功率、热负荷预测偏差。做法很机械但很有效让某个参数从50%到150%变化步长10%记录弃风率、总成本和求解时间的变化幅度然后画成曲线。这样就能回答“为什么储能容量再翻倍消纳效果却变化不大”这种审稿人必问的问题。4.4 容易被忽视的模型假设说明写论文或报告时模型假设一定要说清楚。我的模型里做了几个简化比如假设风电预测是完美的没有考虑预测误差带来的不确定性假设热网是静态稳态模型没有考虑热的传输延迟和管损假设所有机组都有足够的调节速率没有细到二次调频的时间尺度。这些简化在初版模型里完全合理但你必须知道简化在哪因为后续做扩展——比如加入鲁棒优化、随机优化——都是从这些简化点入手的。5. 展望与补充建议模型跑通之后向上走的几个方向其实很清晰。一个是加需求响应让热负荷也可以削峰填谷一个是加碳交易成本让模型自动在经济性和环保性之间权衡还有一个是考虑风电预测的不确定性把确定性模型升级为鲁棒优化或情景随机规划。Matlab生态里这些都有很好的工具箱支持YALMIP本身对鲁棒优化也有内建支持能看到自己的代码一步步迭代升级这个过程本身就很值得。最后再分享一个小技巧无论你的代码最终用没用YALMIP建议写一个辅助脚本来做“数据完整性检查”。比如检查24小时热负荷数据和电负荷数据的数值范围是否合理检查风电出力数据在夜间是否高于白天检查储热罐初始容量是否在允许范围内。这些小检查能帮你拦下很多低级错误让调试过程顺畅不少。我吃过一次亏就是因为某天的热负荷数据多了一个数量级导致模型死活不可行排查了大半天才发现是数据的问题不是模型的问题。从那以后数据清洗和完整性检查就成了我所有调度模型的第一步。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑