在电力系统分析领域待久了你会发现一个现象:系统里真实的成本,往往藏在那些没人愿意核算的“隐性代价”里。我去年参与一个区域电网的新能源并网评估项目,调度同事拿着净负荷曲线问我:“风电半夜满发的时候,火电得压到50%以下出力,多耗的煤、多磨损的机组、早上再爬坡的损耗,谁来认账?”这个问题直接催生了这套《高比例可再生能源电力系统的调峰成本量化与分摊模型(Matlab代码实现)》。今天这篇文章,就是把这套模型的思路、公式、Matlab实现路线和调试中踩过的坑全部梳理出来,供做电力系统规划、运行分析或者写论文的同学参考。
这套东西能解决什么具体问题?简单说:当风电光伏占比升高以后,系统为了平衡净负荷(负荷减去新能源出力)的剧烈波动,需要火电频繁启停、深度压出力、快速爬坡,这些动作都会产生额外成本。传统电力市场或调度核算里,这部分成本要么被摊进平均电价,要么直接没人算。模型要做两件事——先量化出这部分成本到底有多少,再用一个可解释的分摊规则把成本分配到风电、光伏、负荷、火电各主体头上。代码层面基于Matlab实现,核心求解用到linprog/intlinprog,适合电力专业研究生、新能源企业分析工程师、设计院规划人员参考。
1. 调峰成本从哪来:高比例可再生能源改变了系统“调峰”的底层逻辑
想准确量化一个东西,先得搞清楚它产生的机理。调峰成本不是新能源接入以后才有的,但确实是新能源比例高了以后才变得不可忽略的。这一节把底层逻辑理清楚,后面照着公式建模才不会跑偏。
1.1 传统电力系统怎么调峰:边际成本排序与显性成本
在传统火电为主、负荷曲线相对平滑的系统里,调峰其实就是“跟着负荷走”。负荷白天高、夜间低,调度员安排机组出力,峰荷时段让效率高的机组多发,谷荷时段让机组压低出力。这种调节产生的成本,是燃料消耗的变化,而燃料消耗本身可以通过煤耗特性曲线算出来——煤耗曲线上每一点的斜率就是边际煤耗率,调度优化本质上是按边际成本由低到高去排机组带负荷。这套逻辑下,调峰成本是显性的,跟着燃料价格走,谁多发谁多承担,争议不大。
但传统调峰有一个隐含前提:峰谷差在系统可调能力范围内,火电机组即便压低出力,也还维持在一个经济工况附近。常规煤电机组的最小技术出力一般在40%~50%额定容量,也就是说你让它压到50%出力,它还能保持不太离谱的煤耗率。这时候的调峰成本,大体可以用单位煤耗的升高来估算,量级很小,常常被归入“运行成本”而不单独核算。
1.2 新能源接入后的“鸭子曲线”:调峰需求从峰谷问题变成爬坡与低出力问题
高比例风电光伏接入以后,调峰问题的性质完全变了。净负荷曲线不再是一条平滑的“白天高、晚上低”,而是出现典型的“鸭子曲线”:白天光伏大发时净负荷被压出一个深谷,傍晚光伏骤减、负荷攀升,净负荷又急速拉高,形成非常陡的爬坡段。
这意味着系统需要的不再是“缓慢跟随负荷”的能力,而是两种更苛刻的能力:
一是深度调峰能力。午间光伏大发时段,净负荷可能跌到很低,火电必须压到最小技术出力以下,甚至进入不经济的低负荷运行区间。很多机组的深度调峰技术出力下限是30%左右,低于这个值要么投油稳燃,要么停机。
二是快速爬坡能力。傍晚净负荷在2~3小时内可能陡增几千兆瓦,常规火电爬坡速率往往跟不上,调度只能提前多开几台机组“空转”备用,这些机组在等待时段几乎不发电却仍然耗能。
所以我一直跟人强调:高比例可再生能源下的调峰,本质上是“净负荷曲线的极端化”——峰谷差更大、爬坡更陡、不确定性更高。成本就藏在这些“更”字里。
1.3 调峰成本的本质:一项长期被隐性化、如今必须显性化的系统成本
为什么说调峰成本必须单独量化?因为它长期混在系统总运行成本里,没人说得清新能源每发一度电,到底给系统带来了多少额外调峰负担。
举一个直观的例子:某电网原本10台火电机组带负荷,每台都在60%以上出力运行,系统整体煤耗率很低。光伏接入后,午间净负荷低到只需要6台机组出力,另外4台要么停机,要么压到深调状态——停机再启动有启停成本,深度压出力时煤耗率急剧升高,早高峰再让它们爬坡回来又产生爬坡损耗和寿命损耗。这些成本,如果只算“系统总燃料费用”,根本没法看出来是“谁”造成的;一旦要分摊,就必须把每一类的机理、每一笔的钱数拆开算。
把这件事想明白以后,量化模型的设计目标就很明确了:把总运行成本里属于“调峰相关”的组成部分识别出来,逐项公式化,再通过一个公平的规则分摊到各个引起调峰需求的主体身上。下面两节分别讲这两步的具体做法。
2. 调峰成本的量化模型:四个成本项与两条实现路径
量化模型的核心是“拆项”。我把调峰成本拆成四个主要组成部分,每一部分都有明确的物理含义和计算公式。实际算例中可以按需选择计入哪些项,但为了让结果有说服力,建议四项都包含。
2.1 四类必须计入的成本及其公式
**第一类:机组启停成本。**新能源出力波动导致的机组频繁启停,是调峰成本里最直观的一块。计算公式为: [ C_{su} = \sum_{t} \sum_{i} (SC_i \cdot y_{i,t}) ] 其中 (SC_i) 是机组i的单次启动成本,(y_{i,t}) 是0-1变量,表示机组i在时段t是否发生了“由停转启”的状态切换。停机成本同理,用 (SD_i) 和切换变量计算。这里注意,启停成本往往不是一个固定值,冷态、温态、热态启动成本差别很大,工程上多数模型会简化成与停机时长相关的分段函数,但初版代码用固定值就够跑通流程。
**第二类:深度调峰运行成本。**机组压到最小技术出力以下运行时,煤耗率显著上升,甚至需要投入助燃燃料。简化计算是设定一个“经济出力下限”,低于该下限的出力部分,单位发电成本乘以一个惩罚系数。公式: [ C_{deep} = \sum_{t}\sum_{i} \beta_i \cdot (P_{i,t}^{eco} - P_{i,t}) \cdot \Delta t, \quad P_{i,t} < P_{i,t}^{eco} ] (\beta_i) 是深度调峰的单位惩罚成本(元/MWh),需要根据机组煤耗特性曲线拟合。
**第三类:爬坡损耗成本。**机组频繁大幅爬坡会加剧热应力,影响寿命。工程上常用“爬坡里程”折算成本,也就是每个时段出力变化的绝对值乘以一个单位爬坡损耗系数: [ C_{ramp} = \sum_{t}\sum_{i} \lambda_i \cdot |P_{i,t} - P_{i,t-1}| ] 这个系数不容易从教科书上查到,实际项目里多半参考厂家提供的寿命损耗曲线折算。没有资料时,可以先按燃煤成本的2%~5%估算,后面做敏感性分析时再看结果对系数敏不敏感。
**第四类:弃风弃光机会成本。**当系统调峰能力用尽时,只能弃掉一部分新能源电量。这部分电量的“机会成本”可以按新能源上网电价扣除运行成本后的净值估算: [ C_{curtail} = \sum_{t} (P_{curtail,t} \cdot c_{new}) ] 弃电本身不是“花钱”,是“少赚钱”,但在系统总成本视角下,它是调峰能力不足的真实代价,必须计入。
2.2 净负荷调节需求量化:从曲线到系统参数
量化成本之前,先要把“调峰需求”翻译成可计算的系统参数。我做这一步时用净负荷曲线 (P_{net,t} = P_{load,t} - P_{wind,t} - P_{pv,t}) 作为基础输入,然后计算几个关键指标:
- 净负荷峰谷差:(\max(P_{net}) - \min(P_{net})),衡量系统需要应对的最大调节幅度。
- 最大爬坡需求:(\max(|P_{net,t} - P_{net,t-1}|)),衡量系统需要的最快爬坡速率。
- 低出力持续时间:净负荷低于某阈值的连续时段数,决定火电需要压出力的深度和时长。
这些指标直接决定了机组组合优化的边界条件。例如,净负荷峰谷差超过系统可调容量时,必须允许机组启停而不是只调出力;最大爬坡需求超过单台机组爬坡速率时,必须预开多台机组分摊爬坡。
2.3 量化路径选择:先复现实际调度,再做全局最小成本优化
量化调峰成本有两条实现路径,我的代码里提供了两种模式,但默认推荐第二种。
**路径A:模拟实际调度过程。**按调度员实际采取的操作(给定机组组合、给定运行方式)做时序仿真,统计各项成本。优点是不用求解优化问题,速度快、贴近现实;缺点是“实际调度”未必经济最优,算出的成本可能偏高,而且机组组合一变,结果就得重算。
**路径B:机组组合优化。**以系统总运行成本最小为目标,求解一个混合整数规划问题,得到最优的机组启停计划和出力计划,再从中拆分调峰相关成本。优点是结果具备“最小成本”标杆意义,可解释性强;缺点是建模复杂,求解耗时。
工程上,我建议以路径B为主、路径A做交叉验证。两者结果差距如果很大,说明实际调度偏离经济最优太远,调度优化本身就有改进空间;如果差距很小,说明当前运行方式已经比较接近最优,量化结果可以直接用来做成本分摊。
3. 分摊模型设计:责任追溯法与Shapley值法的取舍
成本算出来以后,最难的不是技术,而是“谁来承担”。分摊模型设计得好不好,直接决定这个工具能不能在实际项目里落地。我试过两种主流思路,各有优劣,下面展开讲。
3.1 责任追溯法:按净负荷边际贡献分摊,简单但容易引来争议
责任追溯法的思路是:净负荷曲线的每一次变化,都是由负荷变化、风电出力变化、光伏出力变化共同叠加出来的。那么某类电源对调峰成本的责任,就是它出力变化对净负荷波动的“贡献份额”。
具体做法:先按时间点把净负荷变化量分解:(\Delta P_{net,t} = \Delta P_{load,t} - \Delta P_{wind,t} - \Delta P_{pv,t})。对每一个时段,把系统总调峰成本按三类主体的调峰需求量(用各自的出力变化绝对值度量)占比来分摊。
这个方法的优点是直观、好算、可解释性强,Excel都能复算。缺点是它把一个系统性的问题(所有主体共同造成的系统波动)当作线性叠加来分摊,忽视了机组组合的耦合效应。实际做项目时遇到过一个经典争议:光伏在午间大发,客观上造成了火电深度压出力,追责时光伏要承担很大一块成本——但光伏本身是清洁能源,被要求承担高额调峰费用,在商务上很难被接受。
3.2 合作博弈视角:Shapley值分摊的公平性与计算代价
责任追溯法的争议,促使我认真研究合作博弈分摊。Shapley值的核心思想是:把风电、光伏、负荷、甚至火电都看作合作博弈的“参与人”,总调峰成本是各参与人共同作用的结果。每个参与人应分摊的成本,等于它对所有可能联盟组合的“边际贡献期望值”。
公式形式为: [ \phi_i(v) = \sum_{S \subseteq N \setminus {i}} \frac{|S|! (n-|S|-1)!}{n!} \left( v(S \cup {i}) - v(S) \right) ] 其中 (v(S)) 是联盟S的系统总调峰成本函数,需要为每个联盟重新运行一次优化或仿真才能得到。它满足三个公理:有效性(所有分摊的和等于总成本)、对称性(相同贡献者分摊相同)、零贡献者不分摊。理论上是最“公平”的分摊方案。
但代价也很明显:计算复杂度随参与人数量指数增长,(2^n) 次联盟成本计算在参与人稍多时根本跑不动。我的做法是:第一,把同类机组聚合为少量“联盟参与人”,比如所有火电作为一个参与人,风电算一个,光伏算一个,负荷算一个,这样联盟数大幅减少;第二,用蒙特卡洛采样近似Shapley值,对参与人排列随机抽样,用几百上千次抽样逼近精确值。实测下来,结果稳定性和精确度对工程定价足够了。
3.3 工程推荐的两段式分摊流程
单用责任追溯法或Shapley值法,都有各自的硬伤。实际项目里我推荐一个折中的两段式分摊流程:
**第一段:系统级分摊。**把总调峰成本在“波动性资源(风电+光伏+负荷波动)”与“常规电源(火电)”之间划分。怎么划?看总调峰成本与系统不装新能源时的基准调峰成本之差,差额部分归因于新能源接入,由风电和光伏承担;基准部分由负荷侧承担。
**第二段:新能源内部分摊。**在第一段确定风电和光伏合起来承担的总金额后,再在风电与光伏之间细分。细分依据可以是各自的净负荷贡献率(责任追溯法)、Shapley值、或者实际弃电率——按项目谈判最容易达成共识的口径来选。
这套流程的好处:总盘子用“增量成本”思路定,话说得清楚;细分规则灵活,商务谈判空间大。代码实现上,只需要在成本计算模块之外另写一个分摊计算模块,两种算法都预留接口就行。
4. Matlab实现路线:数据准备、优化建模、结果输出
理论框架讲完之后,进入代码实现部分。很多同学拿到这类题目,最容易卡住的地方不是算法本身,而是“数据怎么组织、约束怎么写成矩阵、结果怎么拆出来”。下面按我的实现习惯,一步步说清楚。
4.1 数据准备与参数对象设计
我习惯用结构体数组管理所有机组参数,不用凌散的变量堆满workspace。一个典型的机组参数结构如下:
% 机组参数:10台火电机组 gen = struct(); gen.name = {'G1','G2','G3','G4','G5','G6','G7','G8','G9','G10'}; gen.Pmax = [800, 800, 600, 600, 400, 400, 300, 300, 200, 200]; % 最大出力 MW gen.Pmin = [320, 320, 240, 240, 160, 160, 120, 120, 80, 80]; % 最小技术出力 MW gen.ramp = [100, 100, 80, 80, 60, 60, 40, 40, 30, 30]; % 爬坡速率 MW/h gen.SC = [10, 10, 8, 8, 5, 5, 3, 3, 2, 2] * 1e4; % 启动成本 元/次 gen.SD = [8, 8, 6, 6, 4, 4, 2, 2, 1.5, 1.5] * 1e4; % 停机成本 元/次 gen.coal = [0.22, 0.22, 0.24, 0.24, 0.26, 0.26, 0.28, 0.28, 0.30, 0.30]; % 煤耗 t/MWh关于时间尺度,强烈建议用15分钟一个时段、一天96个点做基本算例。15分钟能反映爬坡过程,又不至于像5分钟粒度那样把优化问题撑得太大。第一版代码不要直接上全年8760小时,先跑通一天96点的算例,结果合理再扩展。
负荷曲线和新能源出力曲线可以用readtable从Excel读入,也可以先用Matlab内置函数生成模拟曲线。初学者注意:新能源出力曲线一定要做归一化处理,用装机容量乘以归一化出力序列,避免单位和量纲混乱。我习惯把所有数据统一成“MW”和“元”两个单位,前后一致,排查错误时能省一半时间。
4.2 用intlinprog求解机组组合:目标函数、约束与关键代码骨架
机组组合问题是一个混合整数线性规划(MILP),Matlab里对应intlinprog求解器。为什么不用linprog?因为机组启停状态是0-1整数变量,linprog只支持连续变量。
核心变量定义方式:
- (P_{i,t}):连续变量,机组i在时段t的出力(MW)。
- (u_{i,t}):0-1变量,机组i在时段t是否开机。
- (z_{i,t}):0-1变量,机组i在时段t是否发生启动(从0变1)。
- (w_{i,t}):0-1变量,机组i在时段t是否发生停机(从1变0)。
目标函数写成Matlab向量形式时,需要把二维变量展成一维决策变量x。我的做法是用reshape把矩阵按列展开,然后组装目标系数向量f,顺序保持一致:
nG = length(gen.Pmax); T = 96; % 时段数 % 决策变量顺序: [P(1..nG,1..T), u(1..nG,1..T), z(1..nG,1..T), w(1..nG,1..T)] nVar = nG * T * 4; f = zeros(1, nVar); % 填入出力成本系数(煤耗 × 煤价) % 依次填 z 的启动成本、 w 的停机成本、以及深度调峰惩罚项约束条件里,功率平衡约束是等式约束,写成Aeq*x = beq;机组出力上下限、爬坡约束、启停逻辑约束是不等式约束,写成A*x <= b。最关键的约束之一是启停逻辑约束:(z_{i,t} - w_{i,t} = u_{i,t} - u_{i,t-1}),这个约束把“状态切换”和“启停动作”联系起来,没有它,模型里会出现“启停了但不花钱”的错误结果。
爬坡约束的写法也要当心。正确的数学逻辑是: [ P_{i,t} - P_{i,t-1} \leq R_i \cdot u_{i,t-1} + P_{i}^{max} \cdot (1 - u_{i,t-1}) ] 这个约束表达的是:机组从开机状态爬坡时受爬坡速率限制;如果上一时段本来停机,那本时段开机可以满出力启动(忽略热启动初期出力限制时)。初学者最容易踩的坑是写成 (P_{i,t} - P_{i,t-1} \leq R_i),这样会让停机后启动的机组也受爬坡限制,导致模型无解或结果保守。
调用求解器的骨架:
options = optimoptions('intlinprog', 'Display', 'iter', ... 'RelativeGapTolerance', 1e-3, 'MaxTime', 600); [x, fval, exitflag] = intlinprog(f, intcon, A, b, Aeq, beq, lb, ub, options);其中intcon指定哪些变量是整数(z、w和u变量对应编号全部列入),lb/ub设置变量上下限,连续变量出力范围按gen.Pmin和gen.Pmax设置,0-1变量范围设0到1。
4.3 从优化结果中剥离“调峰相关成本”
求解完成以后,fval是系统总运行成本,但调峰相关成本需要从结果里分离出来。我的做法是写一个独立函数splitCost(x, gen, T),按时间维度和出力水平做判断。
剥离逻辑分三层:
- 第一层:把启动成本、停机成本直接从目标函数系数里提取——每个启动和停机动作都是一个固定金额,累加即得。
- 第二层:深度调峰成本,遍历每个机组每个时段,判断出力是否低于经济出力下限
Peco,低于部分乘以惩罚系数。 - 第三层:爬坡损耗成本,遍历相邻时段,用出力变化绝对值乘以单位爬坡损耗系数。
这里有个容易被忽略的细节:如果启停成本和爬坡成本都已经包含在总燃料成本里(因为目标函数整体最小化),那拆分时必须先去重,避免重复计算。我的做法是:优化时目标函数里就区分好“常规运行成本”和“调峰附加成本”两组系数,求解完成后分别汇总。也就是说,目标函数写成 (f_{total} = f_{base} + f_{peak}),其中f_peak部分专门对应上面四类调峰成本项,这样拆出来的数天然是对得上的。
4.4 Shapley值分摊模块与可视化输出
Shapley值计算模块,核心是一个联盟价值函数v(S)。对每一组参与人联盟,需要重新设定“哪些参与者存在、其出力归零或保留”,再调用优化求解器算一次联盟成本。参与人合并以后,联盟数控制在8~16之间,暴力枚举或者蒙特卡洛都能接受。
解析解的代码思路,蒙特卡洛采样版更简单:
function phi = shapleyBySampling(v_func, nPlayer, nSample) phi = zeros(1, nPlayer); for s = 1:nSample perm = randperm(nPlayer); for i = 1:nPlayer idx = perm(1:i); idx_prev = perm(1:i-1); phi(perm(i)) = phi(perm(i)) + v_func(idx) - v_func(idx_prev); end end phi = phi / nSample; end可视化输出部分,我标配三张图:第一张是净负荷曲线+各机组出力堆叠图,展示机组组合的时序演化;第二张是四类调峰成本的堆叠柱状图,按时段展示成本分布;第三张是各类主体分摊金额的饼图或条形图。作图时注意统一色系,我用parula色图,出图比较专业。
5. 仿真实验与调参避坑记录
代码写完之后,真正决定成果质量的是实验设计和调试经验。这一节把我实际跑算例的过程、结果规律和踩过的坑完整记录下来,方便你直接参考。
5.1 三组典型场景的实验结果规律
我用同一套负荷曲线,只改变新能源渗透率(风光装机占比分别为10%、30%、50%),做了三组96时段算例。结果规律非常清晰:
**新能源渗透率越高,总调峰成本增长是非线性的。**10%渗透率时,系统总调峰成本约占总运行成本的3%~5%;50%渗透率时,这个比例跳到12%~18%。原因在于一旦净负荷深谷跌破火电最小技术出力总和,系统就从“多压一点出力”变成“必须整台停机”,启停成本台阶式上升。
**爬坡损耗成本在傍晚时段集中爆发。**下午16点到20点,净负荷陡增,所有火电同时爬坡,这一段的爬坡损耗成本能占到全天爬坡成本的70%以上。这个规律提醒你:如果做季度或年度分析,重点盯住傍晚这个“魔鬼时段”。
**Shapley值分摊和线性追责法的结果差异明显。**在50%渗透率场景里,线性追责法会分给光伏约40%的调峰成本(因为午间深谷主要是光伏造成的),而Shapley值只分给光伏约26%,风电扛了更多。原因并不复杂——光伏出力集中在午间,午间恰好是系统调节压力最大的时段,但它和负荷高峰是错开的,单看“谁改变了净负荷”会低估这种错峰效益。
5.2 intlinprog求解中常见的坑与解决方案
这部分的坑我都是一步步踩出来的,每个都值得单独提醒。
第一个坑:模型无解却不知道约束哪里冲突。intlinprog返回exitflag为负值时,先别急着改参数,用linprog先跑一个放松整数变量的版本,看连续松弛是否可行。如果松弛后仍然不可行,说明约束矩阵本身有问题;如果松弛可行但整数解不可行,多数是启停逻辑约束写错了。
**第二个坑:爬坡约束导致启动机组无法满出力。**前面讲过,爬坡约束必须区分“连续运行”和“启动”两种状态。我见过太多人把爬坡约束写成纯差分形式,结果模型永远无解——因为一台停着的机组你要让它启动,如果不加(u_{i,t-1}=0)的豁免逻辑,它每时段只能爬(R_i)MW,根本开不起来。
**第三个坑:求解时间太长。**96时段、10台机组、4类变量耦合,intlinprog硬跑可能要十几分钟甚至更久。我的经验是按顺序做三件事:一是把机组聚合,相似的机组合并成等效机组;二是时间尺度先粗后细——先用24时段跑通,确认结果合理再切到96时段;三是设置RelativeGapTolerance到1e-3,对于工程分析这个精度完全够用,能显著缩短求解时间。
**第四个坑:结果里出现“启停抖动”。**相邻时段机组反复启停,这在物理上不现实,但模型为了微小的成本优势可能这么做。解决办法是给启停成本加一个最小运行/最小停机时间约束,或者干脆给启停次数设置上限。工程上建议加入最小停机时间约束,因为新能源波动下热态机组频繁启停对寿命的影响不可忽视。
5.3 判断结果合理性的几个经验指标
模型算完以后,不要急着把数字写进报告。先对照几个经验指标做合理性校验,能挡掉90%的低级错误:
**指标一:单位电量调峰成本。**把总调峰成本除以新能源发电量,得到的单位值一般在几元/MWh到几十元/MWh范围。如果你算出几百元/MWh,基本可以断定有成本重复计算或者机组参数设置不合理。
**指标二:启停成本与机组利用小时数的匹配度。**如果模型优化结果里某台机组一天启停3次以上,而其启动成本又特别高,那大概率是约束条件缺失(比如没加最小运行时间),需要回查建模逻辑。
**指标三:深度调峰时段与净负荷低谷时段的对应关系。**深度调峰必然发生在净负荷低位时段,如果结果里出现净负荷很高时仍有大量机组深调出力,说明经济出力下限或目标函数权重设置有问题。
这三个指标都不需要额外数据,直接从结果矩阵里统计就能算出来。养成每次跑完先做校验的习惯,比反复调参数有效得多。
做这套模型最深的体会是:调峰成本分摊这个问题的难点,大部分不在数学和Matlab代码里,而在你对系统物理过程的理解和对“公平”的判断上。我劝所有要拿这个模型做项目或写论文的朋友——第一,先花三天把净负荷曲线的“形状”看透,比直接写代码重要得多;第二,分摊规则的选型要预留可解释性,选的方案要能对不懂优化的人讲明白;第三,结果出来以后,一定要拿实际调度数据做一次交叉验证,哪怕只是粗略对比总量,都能帮你发现很多隐藏的建模偏差。后期想扩展,还可以在这个框架上叠加储能调峰的动态过程、需求响应的可中断时序,以及多区域联络线功率约束,调峰成本的种类和分摊维度都可以更细。