news 2026/9/9 17:01:06

考虑风光不确定性和双向备用的电力系统鲁棒优化调度

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
考虑风光不确定性和双向备用的电力系统鲁棒优化调度

1. 项目概述与问题背景

搞过电力系统优化调度的人应该都有同感:风光出力预测数据永远是“看起来很美”,实际运行起来总会被现实打脸。今天要聊的这个问题,针对的就是这个痛点——风光负荷不同鲁棒性对系统总成本的影响,同时把系统向上、向下备用容量约束一起纳入优化模型。这是个非常典型的两阶段鲁棒优化/单层鲁棒优化在电力调度中的应用场景。

先把这个题目拆开看。风光负荷三者的预测值都存在误差,传统确定性调度只按预测值安排出力,一旦实际值与预测值偏差较大,就可能出现功率失衡、切负荷或弃风弃光。鲁棒优化的思路是:不再假设预测值一定准确,而是假设不确定参数(风光出力、负荷)会在一个预先设定的不确定集合内波动,调度方案必须对集合内的所有可能场景都可行。这里的“不同鲁棒性”指的是不确定集合的大小或鲁棒调节参数(比如预算参数、保守度系数)的变化。当鲁棒性增强时,系统预留的备用容量增加,调度方案变得更保守,总成本大概率上升;但代价是系统应对不确定性的能力变强。这个“成本-鲁棒性”的权衡关系,就是这个项目要搞清楚的核心问题。

为什么要把向上、向下备用容量单独考虑进来?因为风光的波动是双向的:实际出力低于预测值时,系统需要向上备用来补功率缺口;实际出力高于预测值时,系统需要向下备用(或调峰能力)来消纳多余电量。只考虑单向备用在现实中是行不通的。把两个方向的备用需求都建模为与鲁棒性参数相关的约束,才能真实反映系统成本随鲁棒性变化的规律。

这个项目适合谁?正在做电力系统优化调度方向的研究生、做新能源并网规划的工程师、以及想学习如何用Matlab+YALMIP+求解器(CPLEX或Gurobi)求解鲁棒优化问题的入门者。看完这篇文章,你能得到一套可以直接跑的Matlab代码框架,以及关于鲁棒性参数选取、备用约束建模、结果分析的一整套实践经验。

2. 鲁棒优化建模思路与关键设计

2.1 不确定集合怎么选:盒式集合与预算约束

鲁棒优化的第一步是定义不确定参数的波动范围。最常见的做法是盒式不确定集合:每个不确定参数在预测值上下浮动一个区间。以光伏出力为例,如果预测值是100 MW,预测误差比例是20%,那么光伏实际出力p_pv就在[80, 120] MW之间任意取值。

只做盒式集合有个问题:它假设所有不确定参数同时达到最坏情况,这太保守了。实际中所有风电、光伏、负荷同时偏差到极值的概率非常低。所以工程上更常用的是带预算约束(budget)的不确定集合,也叫做Bertsimas-Sim方法。核心做法是限制所有不确定参数偏离预测值的总“数量”不能超过一个预算参数Γ。这样做的好处是:可以通过调节Γ连续地控制方案的保守程度,Γ=0退化为确定性调度,Γ取最大值时等价于最保守的盒式鲁棒。

在Matlab代码里,我是这样处理的:把风电、光伏、负荷的预测误差都归一到各自预测值的百分比区间,比如风电误差±20%,光伏误差±15%,负荷误差±5%,然后引入统一的预算参数Γ,它表示所有节点不确定参数偏离预测值之和的上限。实际代码中用0到N(不确定参数总数)之间的整数或连续值来扫描,观察总成本随Γ的变化曲线。

注意:Γ到底取整数还是连续值,取决于你的不确定参数建模方式。如果每个不确定参数的偏差是一个0-1乘上最大偏差的连续变量,那Γ可以是连续值;如果只允许出现/不出现偏差,Γ就是整数。两种方式YALMIP都能处理,但整数形式的求解速度更快。

2.2 目标函数:总成本都包含哪些项

系统总成本不是只算发电成本。在这个模型里,我考虑了以下四部分:

  • 常规机组(火电/燃气)的发电成本,用二次函数或分段线性函数表示,工程中常用二次函数: ai * P_i^2 + bi * P_i + ci
  • 常规机组的启停成本,单位时间示例中为简化可暂不考虑启停状态变量,但更完整的模型需要加入
  • 系统向上备用的成本,由提供向上备用的机组按备用报价结算,可以按各自机组备用容量乘以备用价格系数计算
  • 系统向下备用的成本,同理,由参与下调的机组提供

为什么备用要单独计算成本?因为备用容量占用的是机组可调容量,机组需要预留这部分能力而不能全出力发电,这相当于一种机会成本,必须体现在经济信号里。另外,向上备用的价格通常高于向下备用,因为向上备用需要机组在较低出力点运行并具备快速加出力能力,对机组性能要求更高。

对于风光和负荷侧,模型里不需要为它们单独加成本项,但通过弃风弃光约束和切负荷约束来保证不出现不合理的调度结果。如果想更精细,可以在目标函数里加入弃风弃光和切负荷的惩罚项,这样求解器在可行与不可行之间会自动权衡。本项目基础版不加惩罚项,而是严格保证所有不确定场景下都满足功率平衡和备用约束,这样鲁棒性含义更纯粹。

2.3 备用约束怎么转化为数学表达式

这是整个模型最核心也最容易写错的地方。先定义符号:

  • P_g(t):常规机组g在时刻t的计划出力(决策变量)
  • P_w(t)、P_pv(t)、P_L(t):风电、光伏、负荷的预测值
  • ΔP_w、ΔP_pv、ΔP_L:对应的不确定偏差,属于不确定集合U
  • R_up(t):系统向上备用需求(决策变量或由不确定集合推导)
  • R_down(t):系统向下备用需求

功率平衡约束的原始形式是:

sum(P_g(t)) + P_w(t) + ΔP_w + P_pv(t) + ΔP_pv = P_L(t) + ΔP_L

这里ΔP_w、ΔP_pv、ΔP_L是变量,这就导致约束是不确定的。鲁棒优化的核心就是求一个不依赖于Δ取值的调度方案,使上式对所有Δ∈U都成立。

把约束重新整理成最坏情况形式。对向上备用来说,最坏情况是风电、光伏出力最小(ΔP_w、ΔP_pv取下界负值),而负荷最大(ΔP_L取上界正值),此时需要的向上备用容量为:

R_up(t) = max_{Δ∈U} [ ΔP_L - ΔP_w - ΔP_pv ]

对向下备用来说,最坏情况是风电、光伏出力最大、负荷最小,此时需要向下备用容量为:

R_down(t) = max_{Δ∈U} [ ΔP_w + ΔP_pv - ΔP_L ]

于是机组的调节能力约束变为:

sum( P_g,max - P_g(t) ) ≥ R_up(t) // 机组上调能力 sum( P_g(t) - P_g,min ) ≥ R_down(t) // 机组下调能力

这两个约束的物理含义很直观:所有常规机组剩余可加出力之和,必须能覆盖最坏情况下的功率缺口;所有常规机组剩余可减出力之和,必须能消纳最坏情况下的超额功率。

3. 不确定性与备用的耦合处理

3.1 对偶变换:把max问题变成线性约束

上面的R_up(t)和R_down(t)是max问题,不能直接嵌进线性规划里。标准的处理办法是把它转化成对偶问题,或者直接用线性规划的对偶理论。

具体来说,风电预测偏差表示为:

ΔP_w = ξ_w * ε_w * P_w,base

其中ξ_w是0到1之间的不确定水平系数,ε_w是最大偏差比例。如果每个不确定参数都可以独立地在其区间内取最大偏差,那么 R_up(t) 的最大值可以通过对偶变换转化为一组线性约束。

以预算约束Γ为例,R_up(t)的max问题可以写成:

max Σ_i ( -ε_i * P_i,base * ξ_i ) // 对同向偏差符号做归一化 s.t. Σ_i ξ_i ≤ Γ 0 ≤ ξ_i ≤ 1

其中i遍历风电、光伏、负荷三个不确定源。由于目标函数是线性的、约束是线性的,这个max问题本质上是一个线性规划。把它的对偶问题写出来,对偶变量是α(对应预算约束)和β_i(对应0≤ξ_i≤1),然后让原调度约束里带上这些对偶变量和α、β,就能得到一个等价的可解的线性约束系统。

这样处理的巧妙之处在于:原问题(max)的每个解都对应对偶问题的一个可行解,两者的目标函数值相等(强对偶成立,因为原问题是线性规划),所以对偶问题加进原模型后,不会改变最优解,但把不确定约束变成了确定线性约束。

在YALMPI+求解器环境下,你甚至不需要手动推导对偶形式,因为代码里通常会直接用YALMIP的鲁棒优化模块(uncertainuncertainty声明)。但如果你想自己手推,上面这个过程就是标准推导。

3.2 为什么向上/向下备用要一起考虑

很多人做鲁棒调度时容易忽略向下备用。实际项目里遇到的情况是:光伏在午间大发时,系统净负荷可能变成负值,如果只考虑向上备用,调度方案会在光伏大发时段大量弃光,或者让常规机组压低出力,但机组有个最小技术出力,往下调的空间有限。如果这个有限的下调空间还不够用,系统就需要额外的向下备用来源,比如储能充电、可中断负荷等。

所以完整的备用约束必须同时考虑两个方向。从模型结构上看,这两个约束会共同制约机组出力区间。举个例子,某台机组容量300 MW,最小出力150 MW,如果系统需要200 MW向上备用和100 MW向下备用,这台机组的出力必须同时满足:

300 - P_g ≥ 200 → P_g ≤ 100 P_g - 150 ≥ 100 → P_g ≥ 250

单个约束都成立,但组合起来显示这个机组自身无法同时满足两种备用需求。这就是为什么备用约束必须放到多机组的系统层面来看,而不是单台机组算完就完事。

从数学上看,向上备用约束和向下备用约束叠加在一起,定义了常规机组群的可行出力区间。鲁棒性增强时,两者都变紧,可行域收缩,系统不得不让更多机组在线运行或增加高成本机组出力,总成本随之上升。

3.3 鲁棒性参数的扫描策略

“不同鲁棒性”在代码里通常体现为对Γ或ε做参数扫描。我的经验是分两个维度看:

  • 固定不确定区间大小(如风电±20%),扫描预算参数Γ从0到最大值的等间距点,观察总成本和备用需求的变化曲线。这回答的是“系统对同时发生多个偏差的容忍度成本”。
  • 固定Γ,扫描不确定区间宽度(如风电误差从±5%到±30%),观察系统总成本的变化。这回答的是“预测精度提高能带来多少经济效益”。

两种扫描都很实用,论文里也常用。实际计算时为节省时间,可以用50个或100个扫描点,线性插值画出平滑曲线。Matlab里用for循环包住求解过程就行,每个扫描点单独调一次求解器,求解完成把结果存到数组里,最后统一画图。

4. Matlab代码实现与核心环节

4.1 系统数据设计

我在做这个项目时,参考了标准IEEE 6节点/30节点系统的数据风格,搭建了一个含6台常规机组、1个风电场、1个光伏电站和一组负荷节点的简化系统。为了让你能快速上手,下面给出一个可直接用于小规模测试的数据设计表:

机组编号容量(MW)最小出力(MW)煤耗系数a(元/MW²h)煤耗系数b(元/MWh)煤耗系数c(元/h)上调备用价格(元/MWh)下调备用价格(元/MWh)
G1300800.0015356005030
G2200600.0020384505532
G3200500.0025424005532
G4150400.0030453506035
G5150300.0035503006035
G6100200.0040552506538

风电场装机200 MW,预测出力按日曲线变化,最大预测误差设为±20%。光伏电站装机150 MW,预测出力按日曲线变化,最大预测误差设为±15%。负荷侧峰值1500 MW,预测误差设为±5%。

这一组数据不是实际电网数据,但用来做机理研究和算法演示足够了。你在用自己的数据时,只需要替换矩阵里的数值,代码框架不需要大改。

4.2 求解器与YALMIP设置

代码实现用的是YALMIP加外部求解器。求解器选CPLEX或Gurobi都可以,我在本机实测两者都能快速求解这个规模的优化问题(6台机组、24时段,几百个变量和约束,秒级求解)。

安装YALMIP很简单,去GitHub Releases下载,把文件夹放到Matlab路径下,然后addpath(genpath('yalmip路径'))。求解器需要单独安装:CPLEX或Gurobi都提供免费学术授权。

YALMIP里声明决策变量的方式如下:

P = sdpvar(6, 24, 'full'); % 6台机组24时段出力 R_up = sdpvar(6, 24, 'full'); % 向上备用 R_down = sdpvar(6, 24, 'full'); % 向下备用

目标函数用sumquad2lin处理二次成本函数,或者直接使用二次目标函数让求解器自行处理如果用的是Gurobi/CPLEX,都能直接求解二次规划。为了线性化方便,也可以把二次成本分段线性化。我的建议是:先用二次函数跑通,再去尝试分段线性化,两个结果应该非常接近。

4.3 核心约束代码对照

下面是一段简化但可运行的核心约束伪代码,展示功率平衡、向上/向下备用约束的实现思路:

% 不确定参数最大值修正 for t = 1:24 % 功率平衡约束(不确定形式,用鲁棒对偶后的确定等价形式) Constraints = [Constraints, sum(P(:,t)) + P_w_base(t) + P_pv_base(t) == P_L_base(t)]; % 向上备用需求不等式(最坏情况:风光低、负荷高) % 这里用R_up_total表示所有机组提供的向上备用总和 Constraints = [Constraints, sum(R_up(:,t)) >= Gamma_scale * (delta_PL_max(t) + delta_Pw_max(t) + delta_Ppv_max(t))]; % 机组出力与备用能力约束 Constraints = [Constraints, P(:,t) + R_up(:,t) <= P_max(:)]; Constraints = [Constraints, P(:,t) - R_down(:,t) >= P_min(:)]; % 向下备用需求不等式(最坏情况:风光高、负荷低) Constraints = [Constraints, sum(R_down(:,t)) >= Gamma_scale * (delta_Pw_max(t) + delta_Ppv_max(t) + delta_PL_min(t))]; end

上面代码中Gamma_scale是归一化后的鲁棒性参数,取值0到1之间。delta_Pw_max(t)表示t时刻风电预测偏差的最大值,用预测值乘以误差比例得到。这样写虽然不完全等同于Bertsimas-Sim的标准形式(那个需要引入对偶变量),但在不确定参数只有三个源、且你主要想观察趋势的场景下,这个简化形式已经够用且非常直观。

如果你要严格推导预算约束下的对偶形式,推荐参考Bertsimas-Sim 2004年的论文,代码实现上可以用YALMIP的uncertain接口,但新手容易踩坑,建议先跑通简化版再升级。

4.4 结果展示与成本曲线绘制

求解完成后的标准画图动作包括:

  • 常规机组各时段最优出力堆叠图(面积图)
  • 系统总成本随鲁棒性参数变化曲线
  • 向上/向下备用需求随鲁棒性参数变化曲线
  • 不同鲁棒性场景下的功率平衡校验图(验证方案在最坏偏差下是否依然可行)

画图用Matlab基础函数plotarea就行,注意设置FontSizeLineWidth,保证放到论文里清晰可读。以下是一个画成本曲线的示例:

Gamma_range = 0:0.1:1; cost_list = zeros(size(Gamma_range)); for k = 1:length(Gamma_range) % 在这里设置当前Gamma并求解 % ... cost_list(k) = value(Objective); end figure; plot(Gamma_range, cost_list, '-o', 'LineWidth', 1.8); xlabel('鲁棒性参数 \Gamma'); ylabel('系统总成本(元)'); grid on;

5. 实验结果与分析要点

以我搭建的6机系统为例,跑出来的典型结果是:总成本随着鲁棒性参数Γ从0到1增大而单调上升,但曲线形态往往是先缓后陡。Γ从0到0.4时成本上升约3%-5%,从0.4到1时成本上升幅度明显加大,可能到15%以上。原因是:低鲁棒性时,备用需求增量主要由效率较高、成本较低的机组承担,边际成本上升不明显;高鲁棒性时,低成本机组的备用能力被用尽,必须调用高成本机组或增加高成本机组出力,边际成本迅速上升。

向上备用和向下备用的变化规律不完全同步。风资源好的夜间时段,向下备用需求增幅更大;光伏大发的中午时段,向下备用需求也显著增加。这说明鲁棒性对两个方向备用需求的影响存在时段差异,在分析结果时要把时段因素考虑进去,不能只给一个全天平均值。

另一个值得注意的现象:随着鲁棒性增强,某些时段的机组组合会发生质变。比如从只开4台机组变成必须开5台甚至6台机组,导致固定成本跳升,总成本曲线出现不连续的跳跃点。这种跳跃在真实系统里很常见,论文呈现时不需要刻意平滑。

如果画功率平衡校验图,你会发现在最坏偏差场景下(风光取最低、负荷取最高),常规机组出力加上备用总量刚好等于负荷上限,说明模型正确保证了鲁棒可行性。这是判断你的模型写对没写对的标志性检验。

6. 常见问题与排查技巧实录

6.1 求解器报“Infeasible Problem”怎么处理

这个项目最容易遇到的坑就是模型不可行。我调试时遇到过的情形和解决办法:

  • 电源总容量不足以覆盖最大负荷加上向上备用需求。检查发电机总容量与负荷峰值的关系,至少要留出备用裕度。如果不可行,把某些机组最小出力调低或增加机组数量。
  • 向下备用约束过紧导致机组出力区间冲突。典型场景是光伏大发时段,系统要求大量向下备用,但所有机组出力已经压到最低出力附近,没有下调空间了。解决办法是允许弃风弃光或者增加储能装置。
  • 鲁棒性参数取到最大值时任何方案都不可行。这是正常现象,说明在给定不确定集合最大值下系统无法保证所有场景可行。分析时把Γ限制在可解区间内即可,不必强求覆盖整个0-1区间。

排查顺序建议是:先把Γ设为0跑确定性调度,确认模型基础没问题;再逐步增大Γ,观察哪个约束最先被触发,把对应的约束松弛掉或用对偶形式替换。

6.2 YALMIP报错“No suitable solver”

出现这个错误通常是因为没装求解器,或者YALMIP没找到求解器路径。检查方法是在Matlab里运行yalmiptest,它会列出所有已安装求解器的状态。我实际用过CPLEX 12.10、Gurobi 9.5和Gurobi 10.0,配合YALMIP R2021版本都能正常用。

如果你的问题里有二次目标函数,确保求解器支持二次规划。Gurobi和CPLEX都支持,但如果用的是免费的linprog(只支持线性规划),就需要先把二次成本分段线性化。具体做法是把机组出力区间切成几段,每段内成本按线性函数近似,再引入0-1变量选择段。切5段左右精度就很高了,不用太贪多。

6.3 结果不随鲁棒性变化或变化异常

大多数情况是因为鲁棒性参数没有真正进入约束。比如代码里用了全局变量但求解循环里忘了更新,或者对偶变换后有简化处理导致约束变成了定值。调试方法很简单:把不同Γ值对应的备用需求值打印出来,如果完全一致,说明模型里鲁棒性参数和备用约束之间的连接断开。

还有一种可能是误差分配方式不对。如果所有误差都归到一个“总偏差”变量上,Γ的变化会被线性稀释,导致结果变化非常平缓。正确的做法是每个不确定源有独立的偏差变量,Γ通过预算约束来限制偏差的总量。

6.4 求解时间过长怎么办

6机24时段这个规模,正常求解时间应该在几秒到几十秒之间。如果求解时间超过几分钟,大概率是二元变量太多,或者约束写得不够紧凑。优化建议:

  • 机组组合(启停)变量是主要耗时点,如果只是研究备用与鲁棒性关系,可以先把启停变量固定为确定性调度结果,只优化出力与备用,这能大幅加速。
  • sdpvar声明变量时指定维度,不要用动态扩展(比如循环里不停把变量拼接进约束数组),预先分配好约束数组能提速不少。
  • 如果用了YALMIP的uncertain接口,可以手动写出对偶等价形式替代,手工对偶虽然推导繁琐,但求解器处理起来更高效。

7. 扩展方向与实际应用建议

这个基础模型本身就能回答很多工程问题。比如,当风电预测误差从20%降到10%时,系统总成本能节省多少?这个“预测精度的经济价值”是新能源并网评估里很有说服力的数据。再比如,增加储能系统后,相同鲁棒性水平下系统总成本能降低多少?这些扩展只需要调整约束和决策变量,代码框架不用推翻重来。

如果你是做毕业设计或者发小论文,建议在这个框架上叠加更复杂的场景:多时段耦合的机组爬坡约束、储能充放电模型、需求响应资源、市场出清机制。这些扩展会显著增加模型的现实意义。

我个人在实际操作中的一个习惯是:每次调整模型后都保留一个“验证场景”——固定Γ=0.3,把最坏偏差场景的功率平衡情况打印出来,确认所有等式约束在误差范围内成立。这个习惯帮我避免了很多因为约束写错而导致的隐性错误,也能在答辩或汇报时作为模型正确性的有力佐证。

最后再分享一个小技巧:跑完扫描后,把每个Γ值下各时段的备用需求和机组出力存成Excel表格。后面写报告或做敏感性分析时,不需要重新求解,直接用表格数据就能做二次分析,省时省力。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/9 16:59:27

CPU不高却延迟飙升?从线程池到连接池的线上排障实战

半夜两点&#xff0c;监控告警突然响起&#xff1a;订单接口的 P99 延迟从 50ms 一路涨到 4.2s&#xff0c;错误率也在缓慢爬升。你打开服务器面板&#xff0c;第一眼看到的是 CPU 利用率只有 15%&#xff0c;内存还剩一大半&#xff0c;load average 也不算离谱。你第一反应是…

作者头像 李华
网站建设 2026/9/9 16:58:31

基于伴随灵敏度分析的肿瘤放疗时空优化:Matlab实现与实战

最近在整理一个和肿瘤生长模型相关的 Matlab 项目时&#xff0c;我把伴随灵敏度分析&#xff08;Adjoint Sensitivity Analysis&#xff09;完整跑通了一遍。整个过程最大的感受是&#xff1a;这个技术在国内的医学物理和计算生物领域讨论得不算多&#xff0c;但它在时空放射治…

作者头像 李华
网站建设 2026/9/9 16:58:28

深入剖析ConcurrentHashMap:从JDK7到JDK8的实现与实战避坑指南

从一次线上事故说起&#xff1a;为什么并发场景必须拥抱ConcurrentHashMap大概两年前&#xff0c;我负责的一个订单服务在大促期间突然出现CPU飙升&#xff0c;紧接着一批请求超时。刚开始大家都以为又是数据库连接池被打满了&#xff0c;结果一查线程栈&#xff0c;发现大量线…

作者头像 李华
网站建设 2026/9/9 16:55:32

AD7888BRZ,8通道12位125kSPS低功耗SAR模数转换器

AD7888BRZ是ADI推出的微功耗多通道SAR型ADC&#xff0c;专为工业多通道传感巡检、便携式采集设备、电池供电测控系统、低速精密数据采集场景设计。芯片集成8路单端模拟输入、片内2.5V基准源、采样保持电路&#xff0c;支持12位精准采样、125kSPS高速吞吐&#xff0c;搭配宽电压…

作者头像 李华
网站建设 2026/9/9 16:55:04

彻底解决Cursor试用限制:1条命令重置机器码,免费额度立刻回来

彻底解决Cursor试用限制&#xff1a;1条命令重置机器码&#xff0c;免费额度立刻回来 【免费下载链接】go-cursor-help 解决Cursor在免费订阅期间出现以下提示的问题: Your request has been blocked as our system has detected suspicious activity / Youve reached your tri…

作者头像 李华