恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
混合发电系统协同调度优化:风电、光热与热电联产建模实战
首页
资讯中心
/
混合发电系统协同调度优化:风电、光热与热电联产建模实战
混合发电系统协同调度优化:风电、光热与热电联产建模实战
发布时间:2026/10/12 8:24:16
凌晨两点值班室里的风功率预测曲线开始往上翻光热电站的储热罐温度却已经降到了下限附近而热电联产机组正被热网指令压着电出力——一边是风电想满发一边是热用户等着供热白天攒下来的光热余量还没放干净。这个场景基本就是混合发电系统调度室的日常。把风电、光热、热电联产放进同一套框架里统一调度听起来确实像能源界的“复仇者联盟”但真正让这三个老伙计协调起来靠的是能同时算清楚电平衡、热平衡、储热状态和燃料成本的一套代码。今天我就把做混合发电系统调度模型的过程、调试心得和踩过的坑完整拆一遍适合在综合能源、微电网、新能源场站做调度优化的朋友参考也适合想入门调度优化的开发者。1. 三种电源的“性格”差异逼着调度必须从分头管理走向协同优化1.1 风电、光热、热电联产到底谁在拖谁的后腿先说风电。风电出力最大的特点就是反调峰夜里用电负荷低的时候它往往呼呼地发白天用电高峰反而可能没风。在北方很多地区冬季大风天叠加夜间低谷负荷风电几乎必然面临弃风压力。更麻烦的是风电出力预测的误差在小时级尺度上能到百分之二三十调度计划稍微排得死一点实际运行就立刻被打脸。光热电站跟光伏最大的区别是它自带一个储热罐。聚光集热系统把太阳能转化成热能一部分去发电一部分存进储热罐夜间或者阴天可以放热发电。这个“可平移”的特性非常宝贵但也带来一个新问题储热罐不是无限大的储多少、什么时候充、什么时候放直接决定了光热电站晚上能顶多久。调度如果不关心储热罐的状态光热电站就会变成一台“看天吃饭”的机组白白浪费掉储热能力。热电联产机组的特殊之处在于“电热耦合”。它烧燃料同时产出电和热热负荷一旦被供热管网锁死电出力就不能随便降。冬季供热期热负荷越高机组的最低电出力就被抬得越高。很多风电消纳不畅的案例表面上是风电太多实际上是热电联产机组为了供热必须维持高电出力把本应留给风电的发电空间全占死了。这三台机器放到一起各自的约束互相打架风电要的是“给我腾空间”光热要的是“让我把储热节奏理顺”热电要的是“供热不能断电跟着热走”。如果还按照过去那种场站各自为政的思路排队发电最后一定有人被挤到墙角。1.2 “各自最优点”合在一起反而成了系统的最差解我见过很多刚开始做综合能源调度的人第一反应是先让每个电源分别求自己的最优出力最后再平衡。这个思路在系统耦合不深的时候勉强能用但在风电、光热、热电联产互相挤占同一张电网和热网的情况下会出大问题。举一个很典型的例子。某园区冬季夜间热负荷高企热电联产机组为了保供热电出力压不下去同时风电场风速上来预测出力大增光热电站白天储的热还够想夜间放热发电赚峰谷价差。三方如果各自“追求最优”——热电机组按热需求定电出力风电场按预测满发光热电站按电价时段放热——电网一算总平衡发电量远超负荷必须有人让路。谁让按传统调度逻辑优先压新能源于是风电先被弃光热再被弃热电厂继续以最高电出力运行。结果是热电厂多烧了燃料风电和光热被弃掉系统总运行成本反而最高。问题出在目标上。每台机组“自己的最优”并没有包含“系统需要谁让路”这个信息。混合发电系统调度的核心是把所有机组的可行域放到同一个优化问题里让系统来决定“谁降出力、降多少、什么时候降”而不是让每个机组自己在局部用不完整的约束做决策。这个思路就是协同调度的本质。1.3 调度层面的分工我们这套代码解决的是哪一层的问题在真正动手写代码之前得先弄清楚所在的位置。大型电力系统里调度通常分几层电网调度中心做全网发电计划下发到各场站执行到了园区或者综合能源系统层面通常还要有一层“本地协调优化”负责把上级下发的计划结合本地负荷、热负荷、储能状态再做一次细化调整。我今天讲的是第二层也就是园区/场站侧的本地多能源协调优化调度。这层调度有几个特点时间尺度短通常以15分钟或1小时为一个周期约束更细能拿到储热罐温度、热网流量、机组爬坡速率这些现场数据优化空间也大因为风电、光热、热电联产的调节自由度全部握在手里。代码要解决的就是在一个滚动的时间窗口里给定未来若干小时的预测数据风电出力、光热出力、负荷曲线、热负荷曲线、电价算出未来每个时刻各台机组的出力设定值使得综合运行成本最低、弃风弃光最少、供热不中断。明确了这一层的问题就可以开始建模了。2. 把真实物理系统翻译成调度约束建模环节决定代码上限2.1 光热电站不能简单地当成“会储热的光伏”很多第一次做光热建模的人会犯一个错误把光热电站当作光伏加一个大电池光电出力削峰填谷一下就行。实际差得很远。光热电站的输入是太阳直射辐射中间要经过聚光集热、储热、换热、发电四个环节每个环节都有损耗而且储热罐的充热和放热不是无级变速的有最大充放热功率限制。建模拟合的时候我习惯把光热电站简化成两个核心状态量发电功率和储热罐储热量。储热罐的动态方程写出来是储热量(t1) 储热量(t) 集热场产热功率 × Δt - 发电用热功率 × Δt - 散热损失集热场产热功率取决于当下的太阳辐射强度发电用热功率取决于电出力目标。散热损失跟罐体保温效果和外界温度有关通常按储热量的一个小比例估算比如每15分钟损失0.5%。这个方程是光热调度的灵魂只要把它写进约束调度器就知道“白天多存的热是留给晚上用的”这个道理。储热罐的容量上下限也要写清楚。罐子满了光热电站再傻乎乎地聚热就只能弃热罐子空了晚上再有峰谷价差也发不出电。所以储热量既不能超过上限也不能低于下限而且为了防止第二天晴天时储热罐没有空间存热优化里最好还能给罐留一个“目标蓄热区间”。这个目标区间就是我后面要讲的边界约束处理。2.2 热电联产机组的可行域电出力与热出力是绑在一起的热电联产机组在数学上是典型的双变量耦合问题。假设一台抽汽式机组电出力和热出力之间的关系可以简化成热出力不能超过最大供热能力电出力下界随热出力增加而抬升近似于 电出力下限 纯凝最小电出力 k × 热出力电出力上界也有限制近似于 电出力上限 最大电出力 - c × 热出力。这个“电出力下限随热负荷抬升”的约束是所有风电消纳难题的根源。调度模型如果不把它写进去算出来的风电消纳方案就是个笑话——现实中热电机组根本降不到那个电出力。还有一个容易被忽略的约束是爬坡速率。热电机组不像风电光热那样可以瞬间改变出力电出力每分钟变化有限制热出力受制于锅炉燃烧调整变化更慢。在15分钟级调度里爬坡约束的作用非常明显它限制了优化器在相邻时段之间“跳变”的冲动否则算出来的计划是一串锯齿波现场执行不了。2.3 目标函数拆解钱、热、电、弃风弃光要怎么打到一个数里调度优化的目标函数本质上是把所有“损失”折算成钱然后求总损失最小。常规的几项成本包括热电联产机组燃料成本跟电出力和热出力都相关通常用线性化处理机组的启停成本如果允许机组关机弃风弃光惩罚成本为了给新能源消纳一个明确优先级购电成本或售电收益跟电网交互时用到热负荷不足的惩罚兜底措施防止模型为了省钱把供热给牺牲掉。弃风弃光惩罚项很关键。如果只求运行费用最小优化器可能宁可弃掉一点风电也不愿调整热电机组——因为风电本身边际成本接近零但热电机组多降点出力却能省下燃料费。为了让结果符合新能源优先消纳的政策导向弃风弃光惩罚要设置得比热电机组节省的燃料成本高但又不至于高到强迫系统做不合理的操作。我在项目里一般把弃风弃光惩罚系数设为当地上网电价的一倍到两倍然后根据实际结果微调。2.4 数据准备把预测曲线、热负荷曲线、电价序列接到同一张时间表上建模之前先把数据对齐。调度优化需要四类基础数据负荷预测、风电/光热出力预测、热负荷需求、分时电价。时间分辨率必须一致我习惯统一到15分钟一个点全天96个点预测时域根据调度需求取24小时或48小时。初始化数据时如果发现时间戳对不齐很影响后续调试所以我在代码里专门加了一个重采样函数把各种来源的数据统一插值到同一个时间轴上。另外还要对异常值做清洗风电预测曲线里出现负值或者超过装机容量的值光热预测曲线在夜间不为零热负荷曲线在夏季出现冬季水平的尖峰这些都要在进模型之前处理掉。数据洁癖在调度优化里不是讲究是必须。3. 手写滚动优化调度器核心代码怎么一步步长出来3.1 选型之争为什么用线性规划而不是一堆if-else规则有人问过我为什么不用一堆if-else规则来做调度比如“风大的时候压热电”“储热多了就放热”。这个思路在简单场景下能跑但规则一多就失控几十条规则互相影响调参调到怀疑人生而且任何新约束都要重写逻辑。我更推荐把问题建成线性规划模型。风电、光热、热电联产在合理简化之后基本都是线性约束目标函数也可以线性表示。线性规划有成熟的求解器能保证在短时间内找到全局最优解而且模型可读性强每一行约束对应一个物理含义出了问题也好排查。这里我用Python的pulp库做示例它语法清晰适合入门。生产环境换用更高效的求解器接口也方便。3.2 变量定义的思路先列出“可以主动调节的东西”建模第一步把系统里所有可以主动调节的量列成变量。我习惯按时间索引定义变量比如from pulp import LpProblem, LpMinimize, LpVariable, LpStatus # 时间点数量假设96个点 T 96 # 各机组出力变量 wind_power [LpVariable(fwind_power_{t}, 0, wind_forecast[t] / 1000, catContinuous) for t in range(T)] # 弃风量实际上面已经通过上限限制体现了 csp_power [LpVariable(fcsp_power_{t}, 0, P_CSP_MAX, catContinuous) for t in range(T)] csp_charge [LpVariable(fcsp_charge_{t}, 0, CHG_MAX, catContinuous) for t in range(T)] csp_discharge [LpVariable(fcsp_discharge_{t}, 0, DIS_MAX, catContinuous) for t in range(T)] csp_storage [LpVariable(fcsp_storage_{t}, 0, STO_MAX, catContinuous) for t in range(T)] chp_power [LpVariable(fchp_power_{t}, 0, P_CHP_MAX, catContinuous) for t in range(T)] chp_heat [LpVariable(fchp_heat_{t}, 0, H_CHP_MAX, catContinuous) for t in range(T)]变量名要起得足够清楚后面调试看结果的时候不用翻约束就知道每个变量代表什么。风电的变量上限直接设成预测值相当于允许“少发”也就是弃风光热的出力上限设成装机容量但能否发挥取决于储热约束热电联产的电热出力各自设上限耦合关系在约束里单独写。3.3 约束落地功率平衡、储热动态方程、热电可行域变量定完接下来是往上放约束。首先是最核心的电功率平衡约束每一时刻风、光热、热电的发电量加上从电网购电必须等于负荷需求。同时允许一点点偏差作为松弛否则模型太容易无解。for t in range(T): prob ( wind_power[t] csp_power[t] chp_power[t] grid_buy[t] load_demand[t] - slack[t] )然后是光热储热的动态方程。注意充热和放热不能同时进行这个约束很细但物理上必须满足for t in range(T - 1): prob ( csp_storage[t 1] csp_storage[t] csp_charge[t] * EFF_CHG - csp_discharge[t] * EFF_DIS )热电联产的可行域约束是重头戏。前面说过电出力下限会随热出力增大而抬升for t in range(T): prob chp_power[t] P_CHP_MIN K_COUPLE * chp_heat[t]这条约束加进去之后热电机组在为供热需求出力的时候电出力就被强制抬高风电消纳压力随之出现。这个非线性耦合在线性规划里表达得非常简洁也正是因为简洁才能一版一版调下去。爬坡约束也不能少。热电机组相邻时段的电出力变化幅度必须受限制for t in range(T - 1): prob chp_power[t 1] - chp_power[t] RAMP_UP prob chp_power[t] - chp_power[t 1] RAMP_DOWN3.4 滚动窗口与求解循环让调度计划跟上真实天气的节奏优化模型建好之后不能只算一次就撒手。天气预测会随时间推移而变化热负荷和负荷预测也会更新所以实际调度要用滚动时域的方式运行每个时刻拿到最新预测数据重新求解未来24小时的最优计划但只执行下一个时段的设定值到了下一个时刻再重复一遍。核心循环写起来就是for step in range(steps): update_forecast(step) # 更新未来预测数据 rebuild_model(step) # 重建模型滚动窗口 prob.solve() # 求解 dispatch_plan[step] get_solution(step) # 只取当前时段的机组出力滚动周期的选择很讲究我放到第五节专门讲。这里先强调一点滚动调度虽然每个时刻都重新求解但今天的热电机组出力设定值不能大幅震荡否则现场阀门跟不上。解决办法是在目标函数里加上一项“出力变化惩罚”让优化器在调节机组时“三思而后行”。求解完后一定要检查LpStatus的状态。如果返回Infeasible八成是某条约束之间互相矛盾最常见的是冬天热负荷太高热电联产为了保供热被电出力下限抬得太高而系统总负荷又装不下这么多电。这种时候就要去做松弛处理把矛盾的硬约束变成软约束。4. 基准场景与极端工况模拟这套代码在真实数据下表现如何4.1 基准场景怎么设置参数别拍脑袋做调度代码最重要的一步是给自己建一个能反复测试的基准场景。我手里的模拟系统是某园区的综合能源系统典型参数你可以直接拿来当参考风电装机20兆瓦光热装机15兆瓦储热罐容量折算成可发电热量约30兆瓦时热电联产机组最大电出力15兆瓦最大热出力18兆瓦电热耦合系数大约0.3。冬季热负荷峰值在傍晚到夜间最高约14兆瓦电负荷全天在18到28兆瓦之间波动。分时电价按峰平谷三段设置峰时电价高引导光热储热到峰时放热。数据曲线我直接用了该园区历史冬季典型日的一版实际数据把风速、辐照度、热负荷的曲线都归一化之后填入。参数设定有一个经验储热罐容量别按理想值设计要打一个八五折的安全裕度因为实际调度里不可能把储热罐用到顶格预测偏差随时可能把计划打穿。4.2 协同调度 vs 分头调度的结果对比我把同一份数据跑了两套方案一套是协同调度就是我上面建的这个模型另一套是模拟“分头调度”逻辑是热电厂按热需求决定电出力光热按峰谷电价放热风电被动消纳剩余电力发不完就只能弃。结果差异非常明显我做成了下面这张对比表指标分头调度协同调度弃风率18.2%6.5%光热发电量41.3 MWh52.8 MWh热电联产燃料成本14.2 万元12.8 万元购电成本4.7 万元5.1 万元系统总运行成本19.6 万元16.7 万元注意系统总运行成本跟购电成本不一样。协同调度里购电成本略高是因为在某些时段选择买电而不让热电机组硬撑着发电整体看燃料成本省下来更多。弃风率从18%降到6.5%主要靠的是让热电联产在热负荷允许的窗口内多降电出力同时光热电站把发电时光调整到晚间峰价白天的富余热量不再白白存满后弃掉。这个结果很直观地说明了一点混合发电系统的价值不在单个电源发多少电而在它们之间的时间互补。光热储热把白天的热量平移到晚上风电把夜间的富余电力送进电网热电联产在供热底线以上尽量给新能源让路——三个电源各自的调节能力被调度代码拧成一股绳。4.3 两个极端工况的测试大风天和晚高峰基准场景跑顺之后我专门设计两个极端工况来测试模型的稳定性。第一个是小风夜间叠加高负荷的工况。傍晚负荷上升光伏功率归零晚上风又小同时热负荷需求被拉到14兆瓦。这时候热电联产热出力高电出力下限被抬到差不多14.5兆瓦几乎顶上光伏的缺口。再加上光热储热罐里还剩白天的余热模型给出的最优策略是让光热在17点到20点电价高峰期持续放热发电恰好顶住负荷爬坡的时段。风电虽然出力小但在凌晨阶段还是有少量弃风——这也是没办法供热底线压在那热电机组必须保持一定电出力。第二个是大风白天、正午光热充足的工况。风电光热预测出力加起来远超负荷社会负荷反而偏低。这种时候协同调度的价值体现得最充分优化器宁可让热电机组降到最低技术出力附近也要把风电和光热优先送上电网同时让光热电站尽量把热量存进储热罐而不是立刻全部发电。到傍晚光伏消失储热罐再逐步放热把一天的发电压制在较平稳的状态。两个工况测下来模型都能给出合理计划没有出现无解也没有出现明显的切负荷。不过测试也暴露出一个隐患储热罐在极端工况下容易被“用满”就是某个时段充放功率顶到上限。这说明储热罐容量才是光热参与调度的最大瓶颈加储热比加装机更值钱。5. 现场跑起来才会踩到的坑预测偏差、热力约束与调度周期陷阱5.1 预测误差把储热罐“锁死”为什么加了优化反而不可行第一版调度器上线测试后头一个坑就出在光热储热罐上。某天的模型明明在白天储备了大量热量计划在晚上峰时放热发电结果下午云层突然变厚光热实际产热远低于预测储热罐没有按计划充到应有水位。到了晚间模型还在按“理想水位”制定放热计划实际一执行储热罐放空了后续时段的约束全部连锁崩塌。这个问题在调度里叫“预测误差累积导致状态量失控”。储热罐是个积分环节今天的误差会直接影响明天的初始状态。解决思路有两个层面第一限制储热罐的可用容量不要顶格预留一部分裕度第二在每个滚动调度周期里把最新实测的储热量作为初始状态重新代入模型而不是沿用上一版计划里推算出来的数值。代码上就是那句话每一轮滚动求解前先把储热罐的当前实际值读进来作为t0时刻的固定值覆盖模型里的初始变量。这个教训对我影响很大。我现在写调度模型凡是涉及储热、储能这类积分量一律保留安全裕度并且把实测反馈放在滚动循环的最前面。调度不是预测比赛先保证可执行再谈最优。5.2 热电联产最小技术出力是个隐形地雷第二个坑很多人都栽过。热电联产机组的热电耦合约束里电出力下限那条直线我一开始设成了纯凝工况下的最小技术出力比如5兆瓦。结果冬季热负荷冲击下模型算出来热出力8兆瓦电出力下限抬到9兆瓦系统电负荷又没那么高机组被电出力下限压得死死的电功率平衡的松弛变量被拉满结果计划虽然“有解”但实际等于切了一部分非重要负荷。后来我才意识到这个电出力下限其实是随热出力动态变化的。热负荷越大下限越高。而且不同机组还有不同的背压工况抽汽量不同耦合系数也不同。正确做法是我前面约束里写的电出力下限 最小电出力 K_COUPLE × 热出力。但真要落到某台具体机组K_COUPLE这个系数得从厂家特性曲线里查或者从供热季实际运行数据里拟合。我在项目里就是用历史数据做线性回归拟合出来的效果比厂商手册给的理想值要准得多。另外热负荷本身也有波动供热管网的蓄热能力其实能容忍短时间的热出力调整。如果能利用管网的蓄热缓冲让热负荷在一两个小时尺度内做小幅波动热电机组的电出力下限就可以更灵活。这个思路我当时没来得及做深但如果你想进一步挖掘消纳空间值得一试。5.3 调度周期太长或太短都会出事从分钟级滚动说起最后一个坑是关于调度时间尺度的。一开始我把调度周期设成1小时一个点全天24个点模型特别简洁算出来的计划也好看。但实际执行时发现热电机组爬坡根本跟不上计划模型让它在某个小时内从10兆瓦爬到14兆瓦看着是可行的现场燃煤锅炉调整却需要几十分钟。到了下一个调度点模型又让它降回来来回折腾省下来的燃料费全变成了阀门磨损和热网水温波动。后来我把步长改成15分钟全天96个点并且给热电机组加了爬坡约束计划就平滑多了。但15分钟粒度也有副作用模型对预测误差更敏感负荷曲线上的一个小毛刺都会在出力计划上放大。我的最终方案是“双尺度调度”机组级计划用15分钟粒度滚动优化但是发给热电机组的执行指令做一阶滤波让它尽量保持连续只有偏差超过阈值才调整。这套双尺度思路在实操里非常管用。如果以后再遇到类似的混合发电系统调度场景不妨先从15分钟粒度、24小时时域、预留储热裕度、拟合真实热电耦合系数这四个方向入手搭建。先把模型跑通再逐步加预测误差反馈和爬坡平滑基本不会走太多弯路。调度代码这东西理论模型谁都写得出来真正拉开差距的永远是现场那点脏活儿和边缘工况怎么处理。