☰
火电机组储热改造与低碳经济调度:建模、约束与Matlab实现
2026/10/10 4:42:18 网站建设 项目流程

1. 火电机组储热改造和低碳经济调度到底在解决什么问题

“火电机组储热改造”这几年在电力系统调度的圈子里出现频率特别高,原因其实不复杂:北方供暖季,热电联产机组(CHP)被热负荷死死摁住,“以热定电”的耦合关系让机组几乎没有调峰空间,风电光伏大发的时段它反而满发,弃风率高、碳排放也压不下去。低碳经济调度要做的,就是把储热改造带来的“热电解耦自由度”写进优化模型,在24小时甚至更长的时间窗口里同时权衡燃料成本、碳交易成本、新能源消纳和供热安全,最终输出一套每个时段的机组出力、储热充放策略和风电接纳功率。

我最早接触这个题目,是在一个风电接入比例很高的区域算例里:白天电负荷高、热负荷平,晚上电负荷掉下去,热负荷反而上来。没储热的时候,夜间CHP为了供热必须维持高电出力,风电想上网都上不去,白白弃掉。加了储热罐之后,问题变成了“晚上多烧热存起来、白天少烧热放出来”,机组夜间电出力可以压到很低,风电消纳空间一下就打开了。这篇文章就想把整个建模过程、目标函数、约束条件、Matlab实现逻辑和我在调算例时踩过的坑完整拆开讲一遍。适合正在写电力系统优化调度程序的硕士生、刚入行的调度工程师,以及所有想从“看得懂公式”过渡到“跑得出结果”的读者。

1.1 热电联产机组的“以热定电”困境

抽汽式CHP机组的本质是:进入汽轮机的蒸汽一边做功发电,一边抽出部分蒸汽去加热供暖水。抽出去的热蒸汽越多,能去汽轮机低压缸做功的蒸汽就越少,所以热出力会直接挤压电出力的上限。反过来,为了让机组稳定运行,电出力也不能无限低,供热越高,这个“最低电出力”的约束越紧。把这层关系画出来,机组的可行域不是一个方方正正的矩形,而是一个多边形。

这个多边形在调度模型里就是一组线性不等式。很多刚入门的同学习惯把电出力和热出力当成两个独立变量,各自上下限一拍就完事,结果算出来的方案在工程上根本不可行——冬天最冷的那几天,热负荷高的时候你让机组电出力降到纯凝工况下的最小值,蒸汽量根本不够抽,机组直接运行不安全。

更麻烦的是时间尺度。热负荷是逐时变化的,夜间外界温度低,供热需求反而高;电网的负荷低谷也出现在夜间。换句话说,最需要风电顶上来的时段,恰好是CHP最不能降低出力的时候。这种“电和热在时间上错配”的矛盾,是储热改造能发挥作用的前提。

1.2 储热改造改变了什么

储热改造的物理形态很朴素:在热力站或电厂侧加一个大容量的热水罐(也有相变储热、熔盐储热等方案,工程上常压热水罐最成熟),充热时把供热管网的富裕热量存进去,放热时再补到热网上。从调度模型的角度看,储热罐等于给“热出力”加了一个时间平移器:CHP机组的热出力不必在每个时段都和热负荷严格相等,只要“历史累计存入的热量 + 当前热出力”总能满足当前热负荷就行。

这样一来,夜间热负荷高的时候,储热罐可以代替CHP承担一部分供热,机组电出力顺势压下去;白天电负荷高的时候,机组多发电,热出力超过热负荷的部分存进罐里,留给晚上用。风电大发、煤电该让路的时候,储热罐就是那个“让煤电喘口气”的缓冲垫。

这也就是为什么低碳经济调度和储热改造天然绑在一起:不改造,CHP在供暖季几乎没有削峰填谷能力,风电消纳和碳减排都无从谈起;改造之后,调度模型多了一组连续状态变量(罐内储热量),多了一组充放功率变量,优化空间明显变大。

1.3 低碳目标为什么必须写进调度模型

很多人会问:碳排放是环境指标,调度模型把燃料成本最低当目标不就行了?但碳交易机制一旦生效,碳排放就变成了一项真实的运行成本:排放超过免费配额的部分要按照碳价购买,排放低于配额的部分可以把配额卖出去。于是“减排”不再是空泛的口号,而是一笔可以算的账——每发一兆瓦时电要多花多少碳钱,每少发一兆瓦时煤电又能省多少碳钱。

低碳经济调度的核心,就是在目标函数里把碳成本显式地放进去,让优化器自己去权衡“多烧煤发电 vs 少发电多买风电 vs 储热平移供热”这三条路。这里面最关键的建模细节是碳配额怎么给、碳价是固定的还是阶梯的,以及排放量和机组出力之间什么关系。下面这一节专门讲目标函数的拆解。

2. 目标函数:怎么把碳排放写成能优化的账

2.1 燃料成本:CHP机组的出力-煤耗关系

目标函数里最常见的一块是燃料成本。纯凝火电机组的成本函数是典型的二次曲线,C = aP² + bP + c,P是电出力。CHP机组要更复杂一点,因为热出力也会改变煤耗,工程上常用带交叉项的二次函数来近似,例如把煤耗写成电出力P和热出力H的二次函数,再加上一项线性交叉项P·H。

但是在线性规划框架里,这种二次成本函数没法直接用,必须分段线性化:把出力范围切成若干个区间,每个区间用一个线性斜率去逼近原曲线。分段点越多精度越高,代价是变量数变多。实际写代码时,我一般先看算例规模:T=24的日前调度,分3~5段足够;如果是96个时段甚至更细的实时调度,段数太多会让矩阵规模膨胀,求解速度下降,这时候用线性近似就够了,误差控制在1%以内影响不大。

2.2 碳排放量与免费配额的计算方式

碳排放量要和出力挂上钩才有意义。最常见的做法是给每台机组设定排放强度系数,单位是tCO2/MWh。纯凝机组直接用 e·P·Δt 累加;CHP机组则要把电出力和热出力分开算,分别乘以对应的排放强度,再加总。系数从哪里来?通常按机组容量、煤质、运行方式给一个经验值,燃煤机组大致在0.8~0.9 tCO2/MWh这个量级。

配额这块,命令式的思路是给每台机组一个基准排放强度δ,也就是每发一度电“免费”配给多少碳排放额度。于是每台机组每时段的净碳成本就是:

λ × (e - δ) × 出力

如果e > δ,发电是在“花碳钱”;如果e < δ(比如燃烧生物质或者高效机组),发电反而能赚钱。代码实现时,这个(λ×(e-δ))可以直接折算进目标函数的系数里,不用额外加变量,特别简洁。

2.3 阶梯碳价的分段处理

固定碳价是单一线性的,优化器会在所有时段统一权衡碳成本。但实际碳交易往往采用阶梯碳价:排放超过配额越多,超出部分的单价越贵。比如配额量Q,实际排放E,超过Q的部分0~2000吨按50元/吨,2000~4000吨按80元/吨,再往上按120元/吨。

这个阶梯结构是分段线性的,而且因为单价递增,目标函数保持凸性。建模的时候要为超排量拆出几个区间变量:

ΔE = E - Q = x1 + x2 + x3
碳成本 = λ1·x1 + λ2·x2 + λ3·x3
0 ≤ x1 ≤ L1,0 ≤ x2 ≤ L2,x3 ≥ 0

由于单价递增,优化器永远不会傻到先把高价段的x2填满而不填低价段的x1,所以不需要额外加整数约束,自然满足阶梯逻辑。这一点在Matlab里实现非常方便,只要在目标函数向量里给这几个区间变量配上对应的λ,再在约束矩阵里把它们的加和等于超排量就行。

阶梯碳价的意义在于:固定碳价下,模型只要算“减排省下的碳钱 > 多花的煤钱”就会减排;阶梯碳价则让高排放变得“越来越贵”,促使模型把最激进的减排手段也用上,比如晚上进一步压低机组的出力下限、提高储热充放速率。

2.4 弃风惩罚与储热运行成本

除了燃料和碳成本,目标函数里还应该放两块小成本。第一块是弃风惩罚:风电实际接纳量低于预测值时,按弃风量乘一个惩罚单价计入成本。这个单价的量级要小心:设得太小,模型宁可弃风也不调整煤电出力,消纳目标落空;设得太大,相当于“无限度”追风,会导致系统为了多消纳1度风而让煤电频繁启停、爬坡,反而不经济。我通常取煤电边际成本的1.5~2倍左右,够用。

第二块是储热运行成本,主要是循环泵、热损补偿这些,按充放热量乘一个很小的单位成本(几块钱每兆瓦时)。它有两个作用:一是让模型不要无意义地反复充放热;二是在充放速率上限之内,成本项会帮着约束充放行为的温和性。金额虽小,但别省略,否则优化器可能为了满足末端SOC约束做出非常漂亮但不切实际的充放曲线。

3. 约束条件:热、电、储三张表拼成可行域

3.1 CHP机组的可行域怎么用不等式表达

CHP机组热-电耦合关系,我习惯用两组线性不等式来描述。一组管下限:电出力不能低于某个随热出力变化的底线,热出力越大,可接受的最低电出力可以越小;另一组管上限:电出力不能超过某个随热出力增加而减小的上限,因为抽汽挤占了发电蒸汽。写成标准形式就是:

P_min - β·H ≤ P ≤ P_max - γ·H
0 ≤ H ≤ H_max

其中β和γ是耦合系数,反映机组抽汽能力。β越大,说明这台机组越能“压低电出力供热”,灵活性越好。这个模型虽然是对工程可行域的线性逼近,但对教学和工程初筛足够了。代码里实现就是每个时段加两行不等式,把P和H的映射关系填进矩阵对应位置。

3.2 储热罐的动态模型和状态边界

储热罐是一个带时间记忆的储能设备,状态变量是罐内储热量E(t),单位是MWh。状态转移方程是最容易写错也最容易检查的一处:

E(t+1) = E(t) + [η_ch·H_ch(t) - H_dis(t)/η_dis]·Δt

H_ch是充热功率,H_dis是放热功率,η_ch和η_dis分别是充放热效率。注意充热乘效率、放热除效率——这是因为充进去的热量有损耗,放出来之前还要再损耗一道,两边符号不能搞反,反了算出来的SOC曲线会出现“越用越多”的离谱结果。

边界条件包括三组:储热容量上下限(通常还要留10%~15%的缓冲,防止罐内水层完全混合导致出热温度不稳)、充放热功率上限、以及跨日循环约束。跨日循环这个很多人会漏:日前调度的优化视野只有24小时,如果不加“调度结束时罐内热量不低于开始时”的约束,优化器会在最后几个时段把罐里的热全部放光,因为剩余热量在时间窗口之外没有价值,结果就得到一个不可持续的调度方案。加上 E(T) ≥ E(1) 或者干脆 E(T) = E(1),才算闭环。

3.3 热平衡、功率平衡和爬坡约束

热平衡是热系统的“基尔霍夫定律”:供热机组热出力之和 + 储热罐放热功率 = 热负荷 + 储热罐充热功率。这里所有热功率都统一用MWth,时间用小时,做完之后热能量自然就是MWh。

电功率平衡是另一条硬约束:全部火电出力 + 风电机组实际接纳功率 = 电负荷。风电实际上网量是变量,预测值是上限,两者之差就是弃风量,后在处理阶段统计。

爬坡约束最容易在矩阵拼装时出问题。它把相邻时段耦合在一起:G(t+1) - G(t) ≤ ramp_up,以及G(t) - G(t+1) ≤ ramp_down。写成矩阵时,这两行不等式的非零元素落在相邻时段对应的列上,千万别把下标写反。如果目标是线性规划且包含多个机组,这些爬坡不等式加起来会增加2×(T-1)×机组数行约束,T=24时还好,T=96就最好用稀疏矩阵。

3.4 要不要引入0-1变量

如果机组在调度周期内“始终在线”,且储热罐允许同时充放热不出问题,这个模型就是个纯线性规划,用lcprog就能解。但如果要做机组启停优化,或者用0-1变量强约束“不能同时充热和放热”,问题就变成混合整数线性规划,求解复杂度上一个台阶。

我个人的做法是:教学型和初步工程评估用纯LP,把机组当成全时段在线,储热罐的效率不为1,同时充放热会出现能量损耗所以优化器天然不会这么干,不需要额外的整数变量。只有到了要做“机组启停+储热联合优化”或者“多场景随机调度”的时候,才上MILP,用整数变量描述启停状态和运行区间的选择。

4. Matlab实现:从数学模型到可运行代码的四步拆解

4.1 第一步:决策变量编排,代码的地基

Matlab跑优化模型,最影响代码可读性的不是求解器,而是变量编号方案。我的习惯是每个物理量各占一块,每块内部按时间连续排列,这样一个块可以用eye(T)一次性映射到约束矩阵的多行,比满地图散点赋值清爽太多。

T = 24; % 调度时段数(小时) % 变量块:1~2号CHP电出力、纯凝火电出力、风电、1~2号CHP热出力、充热、放热、储热SOC idx.P1 = 1:T; idx.P2 = T+1:2*T; idx.G = 2*T+1:3*T; idx.W = 3*T+1:4*T; idx.H1 = 4*T+1:5*T; idx.H2 = 5*T+1:6*T; idx.Hch = 6*T+1:7*T; idx.Hdis = 7*T+1:8*T; idx.E = 8*T+1:9*T; nVars = 9*T;

这套编号方案的好处是做约束填充时,你可以在脑子里面保持一个清晰的“地图”:第几行对应什么物理含义、第几列对应什么变量。排查问题时,只要按索引把x拆回去跟原始数据比对,几乎一眼就能看出哪行约束写歪了。

4.2 第二步:目标函数向量f的拼装

线性规划要求目标函数是f‘x的形式,所以所有线性成本都折算进f的对应位置。单碳价模型尤其简单,把燃料边际成本、净碳成本、储热运行成本、弃风惩罚一股脑加进去就行。

f = zeros(nVars, 1); lambda = 50; % 碳价,元/tCO2 e_em = 0.85; % 燃煤排放强度,tCO2/MWh e_quota = 0.75; % 免费配额强度,tCO2/MWh c_st = 5; % 储热单位运行成本,元/MWh f(idx.P1) = 320 + lambda*(e_em - e_quota); % 边际燃料成本+净碳成本 f(idx.P2) = 335 + lambda*(e_em - e_quota); f(idx.G) = 300 + lambda*(e_em - e_quota); f(idx.H1) = 180 + lambda*(e_em - e_quota); % 供热边际成本 f(idx.H2) = 190 + lambda*(e_em - e_quota); f(idx.Hch) = c_st; f(idx.Hdis) = c_st;

风电那一块的f置0就行——它没有燃料成本,优化器能在平衡方程的约束下自动尽可能多用。弃风惩罚不用放进f,除非你想用惩罚项代替风电出力上限,但标准做法是在约束里给风电变量设硬上限,后处理阶段再统计弃风量。

4.3 第三步:约束矩阵的拼装,用eye(T)批量生成

电力平衡和热平衡约束是最规则的,两个eye(T)就能搞定。以热平衡为例:每个时段,热出力1加热出力2加放热功率减充热功率等于热负荷。写成矩阵就是四块eye(T)的线性组合:

Aeq = zeros(3*T, nVars); beq = zeros(3*T, 1); % 电力平衡:P1+P2+G+W = D_e Aeq(1:T, idx.P1) = eye(T); Aeq(1:T, idx.P2) = eye(T); Aeq(1:T, idx.G) = eye(T); Aeq(1:T, idx.W) = eye(T); beq(1:T) = D_e; % 热平衡:H1+H2+Hdis-Hch = D_h r = T+1:2*T; Aeq(r, idx.H1) = eye(T); Aeq(r, idx.H2) = eye(T); Aeq(r, idx.Hdis) = eye(T); Aeq(r, idx.Hch) = -eye(T); beq(r) = D_h; % 储热状态转移 + 跨日循环 r = 2*T+1:3*T; for t = 1:T-1 Aeq(r(t), idx.E(t+1)) = 1; Aeq(r(t), idx.E(t)) = -1; Aeq(r(t), idx.Hch(t)) = -eta_ch*dt; Aeq(r(t), idx.Hdis(t)) = (1/eta_dis)*dt; end Aeq(r(T), idx.E(T)) = 1; Aeq(r(T), idx.E(1)) = -1; % 末状态等于初状态,保证跨日循环

这段代码的节奏是:先确定等式来源,再确定行索引r,再往里填变量系数。CHP耦合约束和爬坡约束同理,只是从等式变成不等式。拼完之后,转成稀疏矩阵能让求解速度明显提升:

A = sparse(A); Aeq = sparse(Aeq);

4.4 第四步:调用求解器并做结果拆解

模型规模不大时,MATLAB优化工具箱自带的linprog就能胜任。我是这么调的:

options = optimoptions('linprog','Display','iter','Algorithm','dual-simplex'); [x, fval, exitflag] = linprog(f, A, b, Aeq, beq, lb, ub, options); if exitflag <= 0 error('求解失败,exitflag=%d', exitflag); end

求解完成后,把x按之前定义的索引拆回各物理量时间序列,然后立即做几项“体检”:电力平衡残差是否全零、热平衡残差是否全零、SOC曲线是否在上下界内。这些检查晚做不如早做,越早发现越省事。

P1 = x(idx.P1); P2 = x(idx.P2); G = x(idx.G); W = x(idx.W); H1 = x(idx.H1); H2 = x(idx.H2); E = x(idx.E); Hch = x(idx.Hch); Hdis = x(idx.Hdis); % 弃风量 curtail = max(0, W_forecast - W);

如果用了阶梯碳价,还需要把超排量区间变量单拆出来,算完总碳成本后加进fval从而得到完整运行成本。别直接拿fval当总成本——它只包含目标向量里写进去的项,有时和你想统计的口径不一致。

5. 算例对比:储热改造到底省了多少碳、花了多少钱

5.1 算例参数怎么设置

我常用的一套算例参数长这样:两台抽汽式CHP机组,额定电功率分别是500MW和400MW,最大热出力分别是300MWth和250MWth;一台纯凝火电,600MW;风电场装机800MW,预测出力曲线模拟夜间大风白天小风;电负荷曲线典型双峰,峰值1200MW落在傍晚,谷值800MW出现在凌晨3点前后;热负荷曲线则是夜间高白天低,大致在400MWth和300MWth之间波动。

储热罐容量取1000MWh,充放热功率上限200MW,充放热效率都取0.95,自损耗每小时0.5%。碳价取50元/吨,免费配额强度0.75tCO2/MWh,燃煤排放强度0.85tCO2/MWh。阶梯碳价方案则在固定碳价基础上,设置超排量0~2000吨按50元、2000~4000吨按80元、4000吨以上按120元。

5.2 三个方案的调度结果对比

我分别跑了三个方案:A是无储热、只按固定碳价;B是有储热、固定碳价;C是有储热、阶梯碳价。结果整理成表:

指标方案A(无储热)方案B(储热+固定碳价)方案C(储热+阶梯碳价)
燃料成本(万元)452.3439.1439.1
碳交易成本(万元)24.013.535.6
弃风率(%)11.83.62.7
CO2总排放(t)143001292011760
总运行成本(万元)476.3452.6474.7

看这张表能读出三层信息。第一,储热改造带来的燃料成本下降和弃风率下降是立竿见影的:方案B比方案A燃料成本少了13.2万,弃风率从11.8%压到3.6%。第二,固定碳价下碳交易成本反而降低,因为风电接入多了,煤电少发了,需要购买的碳配额就少了。第三,方案C的阶梯碳价让模型进一步压排放,从12920吨降到11760吨,但碳交易成本上升到35.6万元,总成本反而高于方案B——这就是“减排的边际代价”,很真实。

5.3 用电和储热曲线看机理

把三个方案的机组出力曲线摆在一起看,机理特别清楚。方案A里,凌晨时段热负荷400MWth,两台CHP为了供热被迫保持高电出力,风电本来就大半夜里最爱大发,结果被机组占掉的发电空间挤出去,弃风率高达11.8%。方案B加了储热罐后,凌晨时段储热罐以接近200MW的功率充电,两台CHP的电出力顺势压到各自最低,风电几乎全额上网。方案C则更激进:高碳价逼着模型进一步压低高排放机组的出力,代价是白天这些机组要以更高的出力追赶负荷,爬坡更猛,但排放确实降下来了。

储热罐的SOC曲线也很有意思:夜间充热,SOC从初始值爬升到接近上限;上午热负荷上升但电负荷还没到峰,储热罐开始放热;傍晚电负荷高峰时,CHP优先保证发电,热需求靠储热罐撑着;到深夜再次充热,周而复始。这个曲线的形状直接决定了罐容选择是否合理。

5.4 储热容量和碳价的灵敏度

实操时我还会做两组灵敏度分析。第一组把储热罐容量从0扫到2000MWh,看弃风率和总成本怎么变:容量小时,弃风率下降很陡;超过1600MWh之后,弃风率基本不再变化,收益进入平台期。这说明储热不是越大越好,容量超过一定程度,夜间热负荷已经能被完全平移,再加罐容就是浪费投资。第二组把碳价从20元/吨扫到100元/吨:碳价低时,模型对减排不敏感,总成本几乎不变;碳价升高到60元以上,排放下降明显变快,因为“少发煤电买风电”的边际收益超过了燃料成本增加。这个拐点位置,恰好是储热罐最优充放策略发生变化的位置。

6. 调试过程中最容易踩的坑和实用检查清单

6.1 单位混乱是头号杀手

我看过太多人栽在这里:热负荷数据源给的是GJ/h,调度模型里却当成MWth直接用;或者储热罐容量用了GJ,状态转移方程里系数忘了除以3.6。1MWth持续1小时就是1MWh,折合约3.6GJ。整个模型里热功率全用MWth,热能量全用MWh,时间全用小时,那么状态方程里Δt的单位就是小时,充放热效率参与运算后的量纲才一致。这个错误通常在“约束总是无解”或者“SOC曲线越界”的时候暴露,排查起来相当费时间。

6.2 储热SOC初值和末值必须当成约束

还有一个隐蔽坑是SOC初值。日前调度从零点开始算,罐内初始储热量E(1)不能随便取,最好从上一日实际运行的末值拿过来。如果全模型不设E(T)=E(1),优化器会把末状态的储热当垃圾清空,最后一两个时段疯狂放热,出力的形状看起来“很聪明”,但第二天根本没热可用。我的习惯是加E(T)-E(1)=0的等式约束,或者至少加E(T)≥E(1)。前者稳妥,后者留一点灵活性,工程上常见。

6.3 效率不对称导致的同时充放热“漏洞”

如果充热效率比放热效率高很多,模型理论上可能出现先充后放“白赚”效率差的投机行为。比如充效率0.98、放效率0.95,充100放95,热平衡上看不出问题,但能量上亏了5%,实际系统不会这么干。解决思路有两个:要么给充放热功率加整

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询