前阵子做区域电网的风光火联合经济调度仿真,遇到一个特别折磨人的现象:同样的电网模型、同样的负荷曲线,不同文献算出来的系统总成本能差出30%以上。一开始我以为是求解器精度或目标函数写法的问题,后来把模型一层层剥开才发现,分歧的根源几乎都指向同一个参数——鲁棒性水平。说白了,就是你对风光出力和负荷的预测误差防到什么程度。防得越狠,备用的容量需求越大,系统总成本自然涨上去;防得太松,成本是好看,但真遇到极端天气,电网调度员只能眼睁睁看着频率往下掉。这个权衡恰好就是标题的核心:求解风光负荷不同鲁棒性对系统总成本的影响,并在模型里显式考虑向上备用和向下备用容量。我用Matlab把整套模型完整跑了一遍,把过程、公式和踩过的坑都整理在下面,给正在做电力系统经济调度、鲁棒优化入门的同学一个可以直接复现的参考。
1. 风光接入带来的备用压力:从确定性调度到鲁棒调度的必然
1.1 预测误差为什么不是“小概率事件”
先看一个最典型的场景:预报明天下午某时段风电出力150MW,光伏出力80MW,负荷850MW。结果真到了那个时段,风却小了,光伏也因云层遮挡掉了三成,风电实际出力只有100MW,光伏只剩50MW。这一下就产生80MW的缺口。这时候系统凭什么扛住?靠的就是常规机组提前预留的向上备用容量。
反过来,半夜风电大发而负荷很低时,风电出力可能比预测高出一大截,负荷又低于预测,火电必须马上压低出力给风电让路,这就是向下备用。风光预测误差不是偶发事件,风电短时功率波动率动辄20%以上,光伏受云层影响可以分钟级跳水,负荷预测误差虽然小一些,但同样不可忽略。只要系统里风光占比超过一定水平,备用就不是“要不要留”的问题,而是“留多少、怎么定价、由谁来提供”的常规操作了。
更麻烦的是,预测误差会同时叠加。风电偏低、光伏偏低、负荷偏高,三者叠加时形成的缺口远大于任何单一误差源,这种最不利组合才是调度员真正担心的事。确定性模型恰恰在这个地方最脆弱。
1.2 确定性经济调度模型的三个盲区
传统确定性的经济调度模型(Economic Dispatch)通常把风光和负荷的预测值当成确定输入,目标函数只优化燃料成本,约束只校核一个预测场景下的功率平衡。这种模型有三个非常明显的盲区。
第一,只验证单一预测场景。所有机组出力安排都围绕预测值这一个点展开,一旦预测偏差超预期,模型无法回答“系统还会不会安全”这个问题。你花大力气优化的成本最低方案,很可能在一个不算极端的误差组合下直接崩溃。
第二,忽略误差的跨时段累积。机组的爬坡约束是动态的,某个时段偏差大,会消耗掉下一时段可用的上调能力。确定性模型只能看到单时段静态平衡,抓不住“余量被逐步耗尽”的递推关系,等真到需要满爬坡时才发现上一时段已经把裕度用光了。
第三,无法量化保守度。安全裕度是加5%备用还是加20%备用,全靠调度员拍脑袋,没有一个统一参数让决策者在“多花多少成本”和“多扛多少风险”之间做定量权衡。这就像一个只带了一个天气预报点就出门的人,而鲁棒优化是带着“雨天区间”出门,虽然带了伞增加了背包重量(成本),但不会淋成落汤鸡。
所以,只要研究题目里同时出现“风光”“鲁棒性”“备用容量”三个关键词,基本就默认要在不确定性框架下做决策,而不是继续在确定性模型上打补丁。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 鲁棒性系数怎么“指挥”备用容量:不确定集与预算参数的设计逻辑
2.1 盒式不确定集与Γ值含义
在鲁棒优化里,风光和负荷的预测值不再是一个点,而是一个区间。比如风电预测出力是150MW,给定上下浮动±30MW,那么真实出力被认为是120~180MW之间的任意值。负荷预测850MW,浮动范围±25MW。所有时段所有不确定源组成的取值范围的集合,就是“不确定集”。
最简单也最常用的是盒式不确定集,直接把每个变量的上下界框住。但只用盒式集有个大问题:优化器会认为每个时段所有不确定源都同时处于最坏情况,这几乎不可能发生,结果会保守到离谱,备用的采购成本高到没法看。
所以实际工程中更常用的是Bertsimas-Sim在2004年提出的带预算参数的鲁棒模型。核心思想是引入一个Γ(读作Gamma),表示在一个调度周期内,总共最多有Γ个不确定源同时达到“坏”值。Γ=0表示完全无视误差,模型退化成确定性模型;Γ取到最大值表示所有时段所有不确定源都按最坏情况备着,这是最保守的极端。中间的任何取值,都是一种风险偏好。
这个参数太关键了,因为它把一个“你猜我猜”的可靠性偏好,变成了一个可以扫描、可以画曲线的旋钮。你不需要回答“到底该多保守”,你只需要把Γ从0到最大值扫一遍,看总成本怎么变,再结合系统可靠性要求选一个拐点。
2.2 鲁棒对等变换:把最坏场景写进约束
引入不确定集和预算参数之后,数学模型就变成了一个min-max问题:调度决策者要选择机组出力和备用容量,使得在最坏的不确定性组合下,系统仍然安全,且总成本最低。这类问题直接求解很麻烦,因为内层有一个对不确定量的最大化。
Bertsimas-Sim证明了一个非常重要的结论:对于线性约束,可以通过对偶理论,把min-max问题转化为一个等价的线性规划。转化之后,约束形式变得很优雅——原来需要对每个时段单独考虑的不确定量,被聚合到一个“总预算分配”问题上,只需要增加一组对偶变量和一个预算约束。
从直观上理解:系统不再悲观到“每个时段都最坏”,而是从全周期里挑出最值得防的Γ个时刻重点设防。对偶变量可以理解为“在最坏组合下,每增加一个单位波动量对成本造成的边际影响”。在Matlab中,这一步不一定非要手推对偶表达式,可以用YALMIP自带的鲁棒优化建模方式,或者干脆直接枚举最坏场景来近似,我在第4节会具体展示代码。
2.3 每种不确定源分开设Γ还是统一设一个Γ
风电的波动大、预测误差大,光伏的误差受云层影响,负荷预测误差相对温和。在工程上,有人用一个全局Γ覆盖所有不确定源,实现简单,画出来的成本曲线容易解释;也有人对风电用Γ_w、光伏用Γ_pv、负荷用Γ_L分开控制,可以单独做灵敏度分析,看哪种误差源对总成本贡献最大。
我实际做下来,建议这样做:先统一Γ做总体观察,这是第一步。如果发现总成本曲线有明显的非线性拐点,再挑两三个关键点拆开来看每种误差源的贡献。因为最终画出来的曲线如果是要给决策者看的,参数太细反而没法解释。标题里说“不同鲁棒性”,用一个统一预算参数Γ来扫描,逻辑最清晰,也是入门最佳实践。
3. 上下备用容量的数学约束:不是简单加个不等式
3.1 向上备用:应对“风光低于预期、负荷高于预期”
向上备用指当实际风光出力低于预测、或负荷高于预测时,系统能在较短时间内(工程上常取10分钟或15分钟)增加出力填补缺口。数学模型中,除了常规功率平衡约束,还要加备用容量约束:
text复制R_up(t) = sum_i min( P_i^max - P_i(t), RU_i^10 )
含义是:每台机组还能往上加多少,取决于它当前出力与最大出力的差值,以及10分钟爬坡能力,取两者较小值;所有机组加总之后,至少要大于系统在t时段要求的向上备用需求量。
这段话写出来容易,实际建模时特别容易漏掉min算子。有些论文为了线性化,简单写成 P_i(t) + R_up_i(t) ≤ P_i^max,再单独限制R_up_i的上限,效果近似,但遇到机组已经接近满发时,会高估可用备用。你优化出来的备用容量看起来非常充足,实际操作时根本调不出来。
3.2 向下备用:应对“风光高于预期、负荷低于预期”
向下备用常常被忽略,但它的重要性完全不亚于向上备用。尤其是光伏大发的正午,如果光伏实际出力超预测、负荷又低于预测,火电就必须快速压低出力,否则只有两条路:弃风弃光,或者系统频率上升。
向下备用的约束形式是对称的:
text复制R_down(t) = sum_i min( P_i(t) - P_i^min, RD_i^10 )
注意向下备用和向上备用的成本是不对等的。向上备用需要机组提高出力,多耗燃料,成本直观可见;向下备用看似“少发电少花钱”,但如果机组本身已经在最小技术出力附近,深压可能触发机组面临停机或者AGC性能受损,实际补偿成本并不低。所以目标函数里给R_up和R_down设置不同价格系数是合理的,不能想当然认为向下备用免费。
3.3 备用约束与爬坡约束的耦合
这里有一个特别容易踩的坑:把备用容量当成一个不受机组状态约束的独立变量。实际上,R_up(t)和R_down(t)不光要满足出力上下限,还要和相邻时段的P_i(t+1)联动,因为备用本质上是“机组接下来一段时间的调节能力”,不是静态容量。
如果只加了备用上限,没加爬坡联动,优化器会安排一台机组在出力上限附近提供很大的向上备用,但真到需要调节时,它根本爬不了那么快。我在第三版模型里就因为漏了这条耦合,仿真结果中备用容量看起来很高,但事后逐时段检验时发现,很多机组的“承诺出力+备用”已经超过了物理可调节范围。
建议建模时把爬坡约束、备用容量约束放进同一个constraint列表里,求解后专门写一段校验代码,逐时段验证:
text复制P_i(t) + R_up_i(t) <= P_i^max
P_i(t) - R_down_i(t) >= P_i^min
R_up_i(t) <= RU_i^10
R_down_i(t) <= RD_i^10
这四条是底线。如果校验失败,不用怀疑,一定是约束写漏了。
4. 用Matlab遍历不同鲁棒水平:YALMIP建模与求解器配置要点
4.1 数据准备:机组参数、预测曲线、负荷曲线
先准备基础数据。以24小时调度周期为例,一个典型缩微算例需要这些输入:
| 参数 | 数值 | 说明 |
|---|---|---|
| 常规机组数 | 6 | 火电为主,含成本系数a/b/c |
| 风电装机 | 200 MW | 24时段预测出力序列 |
| 光伏装机 | 150 MW | 日间出力序列 |
| 峰值负荷 | 850 MW | 约20:00出现 |
| 风电预测误差比例 | 20% | 取预测值比例加固定分量 |
| 光伏预测误差比例 | 15% | 同上 |
| 负荷预测误差比例 | 3% | 相对负荷较小 |
| 上调备用价格 | 8 $/MWh | 备用容量成本 |
| 下调备用价格 | 5 $/MWh | 备用容量成本 |
机组参数方面,每台火电机组需要给定a、b、c成本系数,出力上下限,以及10分钟爬坡速率。这些参数通常来自实际机组或标准算例库,我这里用的是中等规模火电的典型值,不影响方法移植。
4.2 YALMIP核心建模片段
下面给出模型骨架中最关键的一段代码,展示向上备用和鲁棒预算怎么进约束。我用的建模工具是YALMIP,求解器选CPLEX或Gurobi,Matlab版本2022b以上即可,太老的版本对sdpvar的稀疏矩阵处理会比较吃力。
matlab复制T = 24;
Gamma = 12; % 可扫描,后续放入循环
% 决策变量
P = sdpvar(6, T); % 机组出力
R_up = sdpvar(1, T); % 向上备用
R_down = sdpvar(1, T); % 向下备用
alpha = sdpvar(1, 1); % 鲁棒对偶变量,预算的影子价格
beta_w = sdpvar(T, 1); % 风电不确定项的对偶变量
beta_pv = sdpvar(T, 1); % 光伏不确定项的对偶变量
beta_L = sdpvar(T, 1); % 负荷不确定项的对偶变量
% 目标函数:燃料成本 + 备用容量成本
obj = sum(sum(a .* P.^2 + b .* P + c)) + sum(rup_cost * R_up) + sum(rdown_cost * R_down);
cons = [];
for t = 1:T
% 功率平衡鲁棒约束:最坏场景下也必须满足负荷和向上备用
cons = [cons, sum(P(:, t)) + P_w_pre(t) + P_pv_pre(t) ...
- alpha - beta_w(t) - beta_pv(t) - beta_L(t) ...
>= L_pre(t) + R_up(t)];
% 对偶变量的界,对应各不确定源的波动范围
cons = [cons, beta_w(t) >= delta_w(t), beta_w(t) >= 0];
cons = [cons, beta_pv(t) >= delta_pv(t), beta_pv(t) >= 0];
cons = [cons, beta_L(t) >= delta_L(t), beta_L(t) >= 0];
% 机组出力上下限
cons = [cons, Pmin <= P(:, t) <= Pmax];
% 备用容量与爬坡耦合约束
cons = [cons, R_up(t) <= sum(min(Pmax - P(:, t), RU10))];
cons = [cons, R_down(t) <= sum(min(P(:, t) - Pmin, RD10))];
end
% 总预算约束:全周期最多有 Gamma 个不确定源同时达到坏值
cons = [cons, alpha >= 0, Gamma * alpha >= sum(beta_w) + sum(beta_pv) + sum(beta_L)];
% 求解
optimize(cons, obj, sdpsettings('solver', 'cplex', 'verbose', 0));
上面模型是为了展示鲁棒对偶结构。实际工程中如果追求速度,也可以直接枚举最坏场景:把Γ个最大偏差时段同时设为最坏值,逐次求解。虽然不能证明全局最优,但用于扫描成本趋势完全够用。我把两种做法都跑过,结果曲线形状一致,数值略有差异,原因在于直接枚举相当于把所有偏差“堆叠”到固定时段,而严格鲁棒对偶允许优化器在预算内灵活选择最不利组合。
4.3 求解器配置与批量遍历的脚本结构
外层的批量扫描逻辑很简单,核心是一个for循环:
matlab复制Gamma_list = 0:6:72;
results = zeros(length(Gamma_list), 4);
for k = 1:length(Gamma_list)
Gamma = Gamma_list(k);
% 每次重新建模,不能复用上一轮的约束对象
% (省略:重新构造 P、R_up、R_down、alpha、beta 等变量和 cons)
optimize(cons, obj, sdpsettings('solver', 'cplex', 'verbose', 0));
results(k, 1) = value(obj); % 总成本
results(k, 2) = sum(value(R_up)) / T; % 平均向上备用
results(k, 3) = sum(value(R_down)) / T; % 平均向下备用
results(k, 4) = solvesolvertime; % 求解耗时
end
plot(Gamma_list, results(:, 1));
几个实操细节必须注意。
每轮循环必须重新构造约束,不能复用上一轮的constraint对象,否则会把上一个Γ的约束带进来,导致备用容量“叠罗汉”。我一开始就是直接把cons放在循环外,结果后面的曲线越来越离谱,排查半天才定位到是约束累积问题。
求解器设置上优先选CPLEX或Gurobi。开源求解器遇到二次目标加连续变量虽然能解,但性能差很多,尤其在Γ增大、约束变紧时,求解时间会指数上升。mipgap建议设1e-4,收敛限1e-6,太紧会导致曲线抖动,太松又会掩盖真实的成本变化。
结果收集用矩阵预分配,别在循环里append。数据量不大时差异不明显,一旦把时段数从24扩展到168(一周),append方式的耗时差距能到几十倍。
5. 成本曲线怎么读:算例结果、保守度取舍与实战避坑
5.1 可复现的算例设置与结果解读
我用上面的框架跑了一个缩微算例:6台火电、1座风电场、1座光伏电站,24时段,统一Γ从0扫到72(三种不确定源,每个有24个时段的“坏时刻”,总共最多72个)。对数据做了标准化处理,但趋势和真实系统是一致的。几个关键点的结果如下:
| Γ值 | 系统总成本 | 平均向上备用 | 平均向下备用 |
|---|---|---|---|
| 0 | 98.2万元 | 55 MW | 42 MW |
| 36 | 113.5万元 | 132 MW | 118 MW |
| 72 | 128.6万元 | 186 MW | 165 MW |
总成本随Γ增大而上升,但并非线性。Γ从0加到12,成本上升约3%;从60加到72,成本又上升约6%。原因在于:Γ较小时,优化器只需要针对少数几个最不利时段调整备用,机组还远未触到爬坡天花板;当Γ接近最大值时,几乎每个时段都要预留充足上调能力,机组的运行点普遍被压在上限以下,整个系统都在“等最坏情况”,燃料成本自然快速上涨。
另一个有意思的现象是,向下备用的增长速度比向上备用更快。因为光伏出力集中在午间,光伏预测误差一旦取坏值,火电必须在中午时段深度压低出力,而此时机组往往已经因为夜间低负荷运行处于较低出力点,继续下压的空间被最小技术出力卡住,导致向下备用需求快速膨胀。
5.2 工程层面的成本-鲁棒性权衡
拿到这条曲线怎么用?不是直接选最低点,而是结合可靠性要求选“拐点”。比如看到Γ=48之后成本增速明显变陡,而系统允许的失负荷概率指标对应风险已经足够低,那就没必要继续堆Γ。
工程上更稳健的做法是两阶段。先用鲁棒模型扫出曲线,找到几个候选Γ;再用实际历史出力偏差做蒙特卡洛回放,看这个Γ对应的备用策略在实际样本中是否真的安全。这样既利用了鲁棒优化的“无分布假设”优点,又不会因为单纯追求鲁棒性把成本推得太高。
如果手头有比较可靠的预测误差概率分布,也可以用随机规划替代鲁棒模型,往往能以更低成本达到相同可靠性。缺点是随机规划需要大量场景,收敛性依赖场景数。我的判断是:预测数据质量差的时候,鲁棒优化的结果更踏实,因为它连分布都不需要知道,只需要一个误差范围,这比硬套一个分布然后辛辛苦苦降方差要诚实得多。
5.3 几个让我踩过坑的细节
最后列几个我在实现过程中反复返工的细节,都是血泪教训。
备用重复记账是最常见的坑。功率平衡约束里如果已经用最坏场景强行包含了R_up的影响,备用约束又要求R_up覆盖预测误差,两台账叠加,会多买很多备用,成本曲线虚高。我的做法是:功率平衡约束中保留R_up作为显式变量,备用约束只约束物理可实现能力,不再重复要求R_up覆盖误差范围。
Γ超界会直接导致无解。迭代扫描时如果Γ超过了不确定源总数,约束变成不可行,程序报错。我习惯先算Gamma_max = 3*T再生成扫描列表,把这个值作为横轴上限,避免无解中断。
失负荷约束必须写死。如果不加“切负荷代价极高”的惩罚项,或者“所有时段必须满足负荷和备用”的硬约束,优化器会在备用价格较高时悄悄选择通过失负荷来省钱。结果就是总成本曲线异常平缓,表面看着很好,实际问题大了去了。
求解器的数值容差会导致曲线抖动,特别是Γ较大时。我遇到过Γ=42和Γ=48两个点之间成本突降的诡异现象,后来发现是求解器在数值困难时提前终止,并非模型问题。把mipgap收紧到1e-4,再把收敛限适当放宽到1e-6,曲线就光滑多了。
还有一个数学表达上的细节:目标函数里机组燃料成本如果是二次函数,YALMIP会自动识别为二次规划,但如果用了min(Pmax - P, RU10)这种非光滑算子,模型会变成非线性,求解器可能拒绝求解。建议把备用容量约束按我第3节写的方式拆成两个线性不等式,等价但求解稳健得多。
我个人在实际操作中的体会是,这类研究最关键的不是把代码写得多花哨,而是先搞清楚“这个Γ到底在模型里改变了什么”。它改变的不仅仅是备用容量的数量,更改变了所有机组在整个调度周期内的运行点分布。所以我建议拿到代码后不要急着扫满整个Γ区间,先把Γ=0和Γ=Gamma_max两个极端跑出来,看两头的成本差和备用差,再决定从哪儿细化扫描步长。
另外,如果手头有真实的风光负荷历史数据,可以把预测误差分布统计出来,用分位数标定Γ,这样算出来的成本曲线就不只是论文里的一张图,而是可以直接指导实际备用采购决策的参考。最后再分享一个小技巧:画图时把总成本、平均向上备用、平均向下备用三根曲线叠在一起,你会发现三根曲线的趋势高度同步——备用的本质,就是用成本换安全。这个视角想通了,整个模型在你眼里就不再是一堆约束,而是一个清晰的投资决策问题。
