首页 / 资讯中心 / 文章详情

两阶段鲁棒优化与关键场景辨别算法在微网调度中的应用实践

两阶段鲁棒优化与关键场景辨别算法在微网调度中的应用实践 ★ FEATURED ARTICLE
做微网优化调度的人大概率都翻过车光伏出力突然掉一半负荷预测差出两个尖峰电价波动让日前买电计划变得像个笑话。后来大家开始用两阶段鲁棒优化处理这类不确定性但新的问题又来了——传统做法要去遍历大量可能的最坏场景求解规模大得吓人一个算例跑几个小时还未必稳妥。这两年“两阶段鲁棒 关键场景辨别算法”在微网调度里出现频率越来越高核心思路其实是把“从连续不确定空间里找最坏情况”这件事转化成“从候选场景池里快速锁定几个真正关键的恶劣场景”。我基于这套思路用Matlab复现过完整调度流程这篇文章把模型逻辑、场景辨别算法怎么和CCG迭代配合、代码模块怎么搭、参数怎么调以及我实际跑代码踩过的坑一起整理出来。适合谁看如果你正在做微网、园区综合能源或配网侧的日前调度手头有Matlab基础想从确定性优化切入鲁棒优化或者已经看过两阶段鲁棒的理论但卡在代码实现上这篇文章应该能帮你省不少时间。内容偏工程实践不堆数学公式但关键推导我会用大白话讲明白。1. 为什么微网调度绕不开不确定性从确定性模型到两阶段鲁棒1.1 确定性优化、随机规划与鲁棒优化的差距在哪先说确定性优化。它把光伏、风电、负荷、电价都当成已知曲线直接建一个线性或混合整数规划求一个最低成本调度计划。问题很明显预测永远是错的尤其光伏这种受云量影响的电源半小时前和半小时后完全是两个样。一旦实际偏差大原计划里某些时段可能缺电某些时段又被迫大幅弃风弃光。随机规划试图解决这个问题做法是给不确定性建模成大量带概率的场景然后求期望成本最低。听起来很美但有两个麻烦一是概率分布往往靠拍脑袋误差不小二是场景数量一多变量和约束规模膨胀计算量成倍增长而且最终结果还是依赖那组概率是否靠谱。鲁棒优化的思路完全不同。它不谈概率只谈“不确定集合”——也就是假设光伏、负荷这些参数会在某个范围内波动。然后把这个范围内最恶劣的情况找出来让调度方案在最恶劣情况下也能满足约束、运营成本最小。这个思路下的解不会因为某一次预测偏差过大而崩盘。1.2 两阶段鲁棒模型到底在“鲁”什么微网调度天然是两阶段的。第一阶段是日前决策比如机组启停、储能是否参与、和主网的购电协议这类“先定下来再说”的变量第二阶段是日内调整在第一阶段决策已经确定、真实的不确定参数逐渐暴露之后通过调整机组出力、储能充放电功率、购售电功率来让系统重新平衡。所以两阶段鲁棒优化的目标函数可以写成这样一个结构第一阶段决策成本 在最恶劣不确定参数下第二阶段最小调整成本的最大值翻译成人话就是我在做日前计划时会假设之后可能遇到最倒霉的光照、最离谱的负荷偏差提前就把应对措施的空间留好。目标不是赌一个“平均情况”而是保证“最坏情况也不至于亏太多”。两阶段鲁棒比单阶段鲁棒更贴合工程实际因为日内阶段本来就可以根据实测数据重新优化。把第二阶段决策也纳入模型结果会更现实不会像单阶段那样保守到能跑出离谱的备用容量。1.3 不确定集合怎么描述“最坏情况”不确定集合是两阶段鲁棒模型中一个绕不开的模块。常见的有盒式集合、多面体集合、椭球集合微网调度里最常用的是带预算约束的多面体集合长这样[ \xi_t \in [\xi_t^{min}, \xi_t^{max}], \quad \sum_{t} \frac{|\xi_t - \xi_t^{base}|}{\Delta \xi_t} \le \Gamma ]其中 (\Delta \xi_t) 是预测偏差上限(\Gamma) 是预算参数。这个公式的意思是每个时段的偏差都在某个区间内但所有时段的偏差总量不能超过预算 (\Gamma)。为什么加预算参数因为如果允许所有时段同时取极值结果会保守到没法看。现实中光伏不可能一整天都在预测值下限跑负荷也不可能每个时段都冲到上限。(\Gamma) 就是用来控制“不能所有坏事同时发生”的按钮取值越大模型越保守成本越高。2. 关键场景辨别算法让两阶段鲁棒真正跑得动2.1 为什么不能直接枚举所有场景两阶段鲁棒模型要解决的核心问题是在第二阶段给定第一阶段决策后找到使调整成本最大的那个不确定参数取值。理论上这是一个“在连续不确定空间里求最大最小”的问题。直接求解这种 max-min 问题通常会用到强对偶把内层最小化问题转成对偶最大化问题但处理起来并不轻松特别是当不确定参数是连续区间时对偶后会冒出“对偶变量 × 不确定参数”的双线性项必须做大M线性化问题一下子变成大规模混合整数规划。我在早期尝试的切肤之痛是一个小型微网系统24个时段负荷和光伏各两个不确定参数直接求一次完整子问题Gurobi要跑几十秒甚至几分钟。放到CCG迭代里一轮轮循环下来晚上睡觉前提交的任务第二天早上起来都没跑完。所以后来大家开始用场景化的思路绕过“连续最恶劣点搜索”。既然最恶劣参数大概率落在预测区间边界的某些组合上那不如把不确定性离散成一批候选场景然后从这批场景里找出对当前方案威胁最大的那几个用来驱动迭代。这就引入了关键场景辨别算法。2.2 场景池怎么生成、怎么削减、怎么辨别生成候选场景池的办法很多工程上常用历史数据抽样直接沿用过去几个月的光伏、负荷、电价历史记录整理成场景。蒙特卡洛模拟假设预测误差服从正态分布或Beta分布生成大量随机扰动序列。拉丁超立方采样在保持样本代表性的前提下用更少样本覆盖参数区间。场景池不是越大越好。几千上万个场景直接塞进模型内存和求解时间都受不了。所以要先做场景削减常用来聚类或同步回代削减把相似的场景合并成少数代表性场景。我自己的实践是初始场景池生成2000~5000个削减到20~50个代表场景保留覆盖极端情况的能力。关键场景辨别的核心逻辑是“找最痛的点”。给定第一阶段决策后对每个候选场景求解第二阶段的线性规划得到该场景下的调整成本或约束违反量然后按成本从高到低排序取排名靠前的1~3个场景作为本次迭代的“关键场景”。这些场景就是当前解最怕遇到的情况把它们加入主问题逼着第一阶段的决策去适应这些极端情况。2.3 关键场景辨别与CCG迭代配合的完整流程两阶段鲁棒最常见的求解算法是CCG列与约束生成思路是主问题与子问题交替迭代。加入关键场景辨别后整体流程变成这样初始化生成并削减候选场景池设定初始场景集可以只用确定性场景作为起点。求解主问题在当前场景集下求解两阶段模型得到第一阶段决策和当前最优目标值作为下界。固定第一阶段决策调用关键场景辨别模块对场景池中所有候选场景求解第二阶段LP找到最恶劣的若干场景。取最恶劣场景计算该场景下的总成本作为当前解产生的上界并把该场景连同对应的第二阶段决策变量加入主问题的场景集合。检查上界与下界的相对误差若小于阈值则停止否则回到第2步继续迭代。这种配合方式和标准CCG最大的差别在于标准CCG的子问题通常用对偶加线性化求连续空间里的最恶劣点而关键场景辨别法直接用有限场景池中的LP求解代替了复杂的子问题MILP求解。如果你担心场景池会漏掉更极端的参数组合可以在流程中每隔几次迭代调用一次完整的连续子问题做校验确认当前场景池确实覆盖了最恶劣区域。3. Matlab代码实现主问题、子问题与关键参数3.1 代码整体结构与模块划分这套流程用Matlab实现我习惯把代码拆成几个模块别把几十个变量和约束堆在一个文件里。结构大概是这样文件/模块职责run_demo.m主入口设置参数并启动迭代load_data.m读取负荷、光伏、风电、电价等基础数据build_scenario_pool.m生成候选场景池含蒙特卡洛采样与拉丁超立方reduce_scenarios.m场景削减聚类到指定数量的代表性场景build_mp.m构建主问题模型返回YALMIP目标与约束句柄build_sp.m构建第二阶段LP模型用于场景评估identify_key_scenarios.m对候选场景排序挑选关键场景plot_results.m绘制调度曲线与对比结果params.m集中维护所有常数系统参数、成本、惩罚系数规划时间单位为1小时共24个时段。有功功率单位建议统一成kW储能容量用kWh成本用元/kWh。别小看单位统一这件事我见过很多初学者在模型里各用各的单位结果对偶变量量纲和约束系数对不上求解器直接报不可行。3.2 主问题和子问题的建模细节主问题用YALMIP声明变量核心代码如下%% 主问题MP T 24; u_start binvar(T, N_unit); % 机组启停状态 p_gt sdpvar(T, N_unit); % 机组出力 p_buy sdpvar(T, 1); % 从上级电网购电 soc sdpvar(T1, N_store); % 储能SOC注意长度T1 p_ch sdpvar(T, N_store); % 储能充电功率 p_dis sdpvar(T, N_store); % 储能放电功率 constraints []; % 功率平衡约束注意要扣掉关键场景提供的不确定参数 % 每条约束、每个场景分别展开 for t 1:T constraints [constraints, ... sum(p_gt(t,:)) p_buy(t) sum(p_dis(t,:)) ... load_scenario(t) - pv_scenario(t) - wt_scenario(t) ... sum(p_ch(t,:)) ]; end % 储能SOC递推 for t 1:T constraints [constraints, ... soc(t1) soc(t) p_ch(t) * eta_ch - p_dis(t) / eta_dis ]; end % 机组出力上下限与启停状态逻辑 constraints [constraints, p_min .* u_start p_gt, p_gt p_max .* u_start];这里有一个比较关键的点主问题里每条涉及到不确定参数的平衡约束都要按“已经加入主问题的关键场景”去展开。也就是说主问题不是只针对一条确定曲线建模而是同时针对多个场景建模不同场景下负荷、光伏值不同但第一阶段决策变量机组启停、日前购电量是共享的第二阶段变量可以随场景不同而不同。子问题部分评估某个固定场景下的第二阶段最小调整成本实际上就是一个线性规划直接给YALMIP就行%% 子问题SP: 固定场景下第二阶段LP % 输入第一阶段决策 x_fixed, 候选场景 xi_candidate p_gt sdpvar(T, N_unit); p_ch sdpvar(T, N_store); p_dis sdpvar(T, N_store); cost ...; % 调整成本或惩罚成本 optimize(sp_constraints, cost, Ops);注意子问题里不需要再考虑机组启停的整数变量因为第一阶段已经定了第二阶段变量全是连续变量这也是两阶段鲁棒模型能高效求解的前提。3.3 预算参数、惩罚系数和收敛阈值怎么设我常用的初始参数参考值参数初始建议说明不确定预算 (\Gamma)3~624时段模型里Gamma取时间段数的1/4到1/3较稳妥光伏预测偏差±20%依据当地历史预测误差设定负荷预测偏差±5%~±10%工商业园区通常小于居民负荷风电预测偏差±25%风电不确定性高于光伏弃光弃风惩罚系数购电价或燃料成本的1.5~2倍太低会导致大量弃电CCG相对收敛阈值0.01~0.02即上下界误差控制在1%~2%最大迭代次数50超过50次还不收敛优先检查子问题(\Gamma) 对结果的影响很明显Gamma越大可波动的总偏差越大两阶段鲁棒结果越保守运行成本越高。如果Gamma取到接近时段数模型几乎等价于要求所有时段同时取极端值成本高得离谱。反过来Gamma取0就退化成了确定性模型。3.4 结果怎么看调度曲线与成本对比迭代跑完第一件事是画出几条关键曲线光伏出力、负荷、机组出力、储能SOC、购电功率。我的检查顺序是储能SOC是否在限内首末SOC是否满足设定比如都回到初始值。购电功率是否超过变压器容量有没有明显的反向除非设置了售电。机组启停状态与出力是否匹配有没有“停机但出力大于0”之类的矛盾。把每一个加入主模型的关键场景对应的不平衡量单独画出来确认削峰填谷的效果。成本对比推荐做三组确定性模型、普通两阶段鲁棒子问题用连续空间最恶劣点、两阶段鲁棒关键场景辨别。对比项包括总成本、计算时长、迭代次数。关键场景辨别法在计算时长上通常会快出一大截但成本会比“全局最恶劣点”略低一些因为它的搜索范围被限制在场景池里。只要场景池生成得当两者差距一般能控制在2%以内。4. 常见问题、参数调优与避坑实录4.1 子问题求解慢、内存爆炸最常见的原因是候选场景池太大或者主问题里加入的场景太多。每加入一个场景主问题就多一组第二阶段变量和约束场景数量从1涨到50主问题规模会变得很可观。如果每个场景的平衡约束、储能约束全部写进一个YALMIP变量矩阵内存会涨得很凶。我踩过这个坑后的习惯是先削减场景到20~50个不要用几千个原始场景直接跑。每次迭代只加入辨识出的最恶劣场景不要一次把排名前10的场景全塞进去宁可多迭代几轮。主问题里对同一时段、不同场景的约束尝试用矩阵化写法而不是for循环逐个拼约束能降低YALMIP变量开销。如果模型太大可以把Gurobi的MIPGap调大到0.5%~1%别追求精确最优。4.2 迭代不收敛、上下界gap卡死迭代不收敛有两大类原因。一类是算法层面的如果上界一直不变、下界也不动可能是场景池里反复选出同一个场景主问题加了个“新车轮”但没带来新信息。解决办法是在加入场景前做去重记录已有的关键场景编号重复的不再添加。另一类是数值层面的子问题求出的目标值忽高忽低上下界没法收敛往往是求解器数值问题导致的。这时候优先检查数据量纲功率、单价要用相近的数量级。我一开始把成本系数写成0.00043元/W波动范围在几千瓦导致约束矩阵条件数巨大Gurobi稳定性直接崩掉。把单位统一成kW、kWh、元/kWh之后数值问题立刻缓解。4.3 结果明显不对的排查清单遇到调度结果不合理先按这张表排查现象大概率原因储能SOC末端不回初始值缺少SOC终端约束或递推公式里充放电效率方向搞反购电功率出现尖峰购电上限约束没加或单位换算错误机组出力明明停机还非零启停状态与出力上下限的约束关系写错第二阶段模型不可行第二阶段变量忘记定义非负下界或功率平衡中符号方向反了迭代出来的成本比确定性模型还低场景池没覆盖足够恶劣场景上界取值不正确引入关键场景后结果与全局子问题差距过大场景生成时的偏差范围设得太小建议扩大候选场景池范围另外还有一个非常容易被忽略的点第二阶段LP做强对偶时谨慎处理等式约束对应的对偶变量。等式约束的对偶变量是自由变量不等式约束的对偶变量非负搞错符号会让对偶可行域直接翻转结果看起来合理但其实是错的。4.4 关于计算精度和数值缩放的更多经验我在跑某个园区算例时遇到过这样一个情况用默认Gurobi参数主问题MIP求解精度取默认1e-4结果上下界gap在2.3%附近怎么都压不下去。把MIPGap调到1e-2之后反而收敛得更快最终成本也只差了不到0.5%。原因很简单主问题里面第一阶段变量本身是离散的第二阶段连续变量的最优解对总成本影响很小过度追求精度纯属浪费算力。数值缩放的一个通用技巧如果约束矩阵中的系数有超过三个数量级的差异优先做归一化。把目标函数除以1000把所有功率量纲统一成kW偏差范围控制在1e-2到1e2之间Gurobi和Cplex这类求解器跑起来会稳定很多。这招在YALMIP搭建的大规模模型里几乎是必备的。最后分享一个我自己养成的习惯拿到任何一套新数据我先跑确定性模型记下总成本和调度曲线再跑两阶段鲁棒模型做对比。如果两者成本差距超过15%先怀疑Gamma取太大再检查预测偏差是不是设得离谱如果差距小于3%说明这套系统的备用裕量比较充足不确定性影响有限。这个对比习惯帮我排掉过很多模型Bug也让我对每个算例的“最坏情况代价”心里有数。两阶段鲁棒加关键场景辨别不是银弹但只要你接受“以场景池换计算速度”的折中在工程落地里它是我用过的最稳的一套解法。
阅读完成 · 觉得有帮助?
咨询建站