资讯动态

计及源荷双重不确定性的虚拟电厂日前鲁棒优化调度实践

发布时间:2026/10/21 9:11:19 来源:尧图企业网站定制
前两天帮一个做虚拟电厂聚合运营的团队梳理日前调度模型客户一句话问到我心坎里你们给的出力计划到了第二天要是光伏比我预测的低了30%负荷还比预测高了20%这计划还能不能扛得住这个问题恰好就是“计及源-荷双重不确定性的虚拟电厂日前鲁棒优化调度”这个课题想解决的事。所谓虚拟电厂就是把分散的分布式光伏、风电、储能、可调负荷乃至柴油发电机组集合起来对外统一参与市场交易和电网调度。日前调度就是提前一天把第二天各个时段一般按15分钟一个断面一天96个时段的发用电计划定下来。难点在于源侧的光伏风电靠天吃饭负荷侧的用电行为也千变万化两者叠加起来以后单纯按预测值做优化执行时必然会频繁出现偏差。这篇内容我打算从整体设计、数学模型、求解实现、工程避坑四个层面展开把鲁棒优化在虚拟电厂日前调度里到底怎么落地说清楚。不管你是刚接触鲁棒优化的研究生还是已经在做调度系统的工程师按这套思路都能跑通一版能用的模型。1. 整体设计思路为什么要把不确定性装进模型1.1 源-荷双重不确定到底是什么很多人一开始对“源-荷不确定性”的理解是光伏和风电出力预测不准或者负荷预测有误差。这当然对但只解决一半问题。真正麻烦的是源和荷同时波动形成“组合不确定性”。举例来说假设某虚拟电厂预测次日中午光伏出力20MW预测负荷是10MW如果按预测值安排储能充电5MW剩余15MW对外售电。第二天实际情况可能是光伏只有5MW同时负荷涨到15MW。这时储能如果已经按计划充满系统就只剩“从上级电网高价购电”或者“中断负荷”两条路调度计划等于失效。反过来源高荷低也会造成大量弃光。这就是为什么标题强调“双重”不确定性。单一侧不确定性的鲁棒模型容易做把双侧同时放进去以后可行域被压缩得比较厉害模型规模和求解难度都会上一个台阶。但实际运行中源侧和荷侧的偏差往往同时出现如果只考虑一边等于给调度员一个“看起来稳健、实际一触即溃”的计划。我在某虚拟电厂平台项目里见过一个很典型的现象调度员每天按点预测值出计划平时问题不大遇到多云转晴或者大用户临时加班的天气和工况叠加日考核罚款和紧急购电费用能占到当天运行成本的20%以上。这说明源-荷不确定性不是纸面上的理论问题是真金白银的运营风险。1.2 为什么选鲁棒优化而不是随机规划面对不确定性工程上还有一条常见路线叫随机规划需要给不确定性变量构造大量概率场景然后用期望值做优化。随机规划的优点是经济性更好缺点也很明显一是需要准确的概率分布实际中光伏预测误差分布、负荷预测误差分布很难精确刻画二是场景数量一大模型维度膨胀求解压力比鲁棒优化大得多。更重要的是随机规划只能保证“平均意义上最优”最坏场景下依然可能崩溃。鲁棒优化的思路则是我不需要精确分布只需要给不确定性变量限定一个取值范围只要实际值落在这个范围内我做的计划就一定可行。这种思路对调度场景特别友好——调度员要的是“无论明天怎么波动我的计划都不会翻车”而不是“大部分时候省钱了极端情况偶尔翻车”。可以类比一下日常决策天气预报说降水概率40%随机规划会算“带伞的期望损失”鲁棒优化则直接默认“要么不下要么下雨”带一把伞出门下雨不淋不下雨也无所谓。对调度系统这种强可靠性要求的场景鲁棒优化天然更合适。2. 模型怎么搭从目标函数到两阶段结构2.1 虚拟电厂的设备构成与日前调度目标标准的虚拟电厂日前调度模型通常包含这几类设备分布式光伏、分散式风电、燃气轮机或柴油发电机、储能系统、可控负荷和可中断负荷。可中断负荷指那些提前约定好、在紧急情况下可以切除并给予补偿的用户负荷。日前调度的目标函数是让系统总运行成本最低主要包括五项成本向上级电网购电的费用、燃气轮机或柴油机的燃料成本、机组启停成本、储能充放电带来的寿命损耗折算成本、可中断负荷的调度补偿成本。如果虚拟电厂允许向外部售电购售电收益也以负成本形式写到目标函数里。一个简化目标函数可以写成min Σ_{t1..T} [ C_buy(t) C_fuel(t) C_start(t) C_battery(t) C_interrupt(t) ]约束条件则是这套模型的骨架常见的有功率平衡约束所有电源出力加储能放电加购电必须等于负荷减去可中断量再加储能充电加售电。机组出力上下限约束每台发电机有最大最小出力。爬坡约束相邻时段出力变化不能超过机组爬坡速率。储能SOC递推约束下一时段电量等于上一时段电量减去放电、加上充电同时SOC必须保持在安全区间。交互功率约束与上级电网的购售电功率不能超过合同上限。不确定性变量约束这是鲁棒优化特有的部分后面单独展开。设备参数在工程上通常按15分钟一个时段建模一天96个时段每台机组都会有96个连续变量和96个整数开关变量所以模型规模增长很快。刚接触这类模型的人建议先用24时段做通再扩展96时段。2.2 盒式加预算一个不狂也不飘的不确定集合鲁棒优化最关键的环节是构造不确定性集合。最常见的是把光伏实际出力和负荷实际值写成预测值加偏差的形式P_pv_real(t) P_pv_pred(t) ΔP_pv · ξ_pv(t) P_load_real(t) P_load_pred(t) ΔP_load · ξ_load(t)其中ξ是归一化后的偏差系数落在[-1, 1]区间内。如果不加任何限制模型会认为所有时段都同时取到最坏偏差光伏每个时段都最小、负荷每个时段都最大。这种“极端全能坏”的情况在实际中几乎不会发生算出来的计划会过度保守成本高到没法看。工程上普遍采用“盒式集合 预算约束”的组合来解决这个问题在原有范围约束之外再加一条Σ_t |ξ_pv(t)| Σ_t |ξ_load(t)| ≤ ΓΓ就是预算参数它限制了整个调度周期内不确定性偏差的总量。Γ0时模型退化为确定性优化只看预测值Γ越大模型对最坏情况的考虑越充分但也越保守。实际操作中Γ一般取总不确定变量个数的30%到50%左右还需要根据预测误差的历史统计来标定。打个比方出差收拾行李时极端保守的做法是把厚外套、雨衣、棉靴全带上包会重到拖不动。带伞加一件外套就能覆盖大多数突发天气重量也可控。预算约束就是给这个“可控的保守”提供了数学化工具。2.3 两阶段决策先定“确定性计划”再留“调整空间”日前鲁棒调度本质上是一个两阶段决策问题。第一阶段变量对应“现在就必须定下来的计划”包括机组开停状态、储能充放电状态、售购电计划等。这些决策要求在日前确认日内很难快速改变。第二阶段变量则是不确定性实现之后系统为了维持平衡而采取的调整手段例如储能出力的微调、弃风弃光量、可中断负荷的调用量等。这些决策要等到第二天实际运行后才能具体确定但模型需要提前保证无论不确定变量怎么变都存在可行的调整方案。对应的数学模型是三层的min-max-min结构用式子表达就是min_x { f(x) max_{u∈U} min_{y∈F(x,u)} g(y) }第一层最小化是第一阶段的计划成本第二层max是寻找最坏不确定性场景第三层min是在该场景下的最优应急调整成本。这种结构不能直接用常规求解器求解正是要用CCG这类分解算法处理的难点所在。3. 求解实操CCG算法与工程实现细节3.1 为什么必须用CCG直接灌给求解器不行有人会想既然有商业MIP求解器能不能把全部场景建模成一个大规模混合整数规划直接丢进去理论上可以但实践中很痛苦。不确定性变量如果取极端点组合假设源侧10个时段、荷侧10个时段极端场景数量会爆炸到一个天文数字一次性建模根本不可行。列与约束生成算法CCG是两阶段鲁棒优化最主流的求解方案。核心思想是不把所有场景一次性建模而是先假设一个最坏场景求解主问题得到第一阶段的计划然后把这个计划固定住去求解子问题寻找当前计划下的最坏场景和对应调整成本如果新找到的最坏场景会让总成本超过当前上界就把这个场景对应的第二阶段变量和约束加入主问题继续迭代。直到上下界 gap 收敛到设定精度。CCG算法的典型流程初始化给一个可行的第一阶段决策上界UB设为无穷大下界LB设为负无穷大迭代次数k1。求解主问题得到第一阶段决策和LB。如果LB已大于UB减去收敛容差停止。固定第一阶段决策求解子问题得到最坏场景和第二阶段成本更新UB。若UB减去LB小于收敛容差停止否则把最坏场景对应的第二阶段决策变量及相关约束加入主问题k加1回到第2步。我实际跑下来的经验是对中等规模的虚拟电厂模型CCG一般在5到15轮内能收敛到gap小于0.5%比一次性建模所有场景的方式快很多尤其适合日内滚动调用场景。3.2 子问题强对偶与双线性项线性化CCG里最容易翻车的环节是子问题的推导。子问题内层是线性规划对不确定性变量求“最坏情况下的最小成本”标准的处理方法是利用强对偶定理把内层min问题转为对偶max问题这样整个子问题变成单层max问题。转换之后会出现新的麻烦目标函数中可能出现不确定性变量与对偶变量的乘积项也就是双线性项。如果这些不确定性变量只取离散极端点可以用大M法精确线性化。引入辅助变量w把u·λ表示成w并添加形如w ≤ M·u、w ≤ λ、w ≥ λ - M·(1-u)、w ≥ -M·u这组约束就能把双线性项改写成线性不等式组。这里的大M取值非常有讲究取太大会造成数值不稳定取太小可能把可行域切坏。我一般的做法是先看目标函数系数和约束矩阵系数的量级M取相关项系数上限的10倍左右然后在验证阶段做敏感性测试。如果发现求解器频繁报数值警告优先检查就是这些大M约束。对连续型不确定性变量建议换一种思路在盒式加预算的不确定集合下最坏场景一定落在极点上。CCG子问题每一轮求出来的最坏场景本身就是极端点组合所以实践中只需要处理离散极端点对应的双线性项这等于帮我们绕开了连续bilinear的麻烦。我在项目里明确要求只考虑±1的极端偏差值而不是把ξ当连续变量处理工程实现简单很多结果也没差别。3.3 代码骨架与求解器参数调优建模工具我习惯用Python加商业MIP求解器先写一个清晰的骨架再逐步填充数据。# 两阶段鲁棒优化的CCG骨架 max_iter 20 gap_threshold 0.005 UB float(inf) LB float(-inf) scenario_pool [] for k in range(max_iter): # 1. 求解主问题给出候选第一层决策和LB lb_k, first_stage_plan solve_master_problem(scenario_pool) LB max(LB, lb_k) # 2. 固定第一层求解子问题找最坏场景 worst_scenario, second_stage_cost solve_subproblem(first_stage_plan) # 3. 更新上界 first_stage_cost eval_first_stage_cost(first_stage_plan) UB min(UB, first_stage_cost second_stage_cost) # 4. 检查收敛 if UB - LB gap_threshold: break # 5. 将最坏场景加入主问题下次迭代重新优化 scenario_pool.append(worst_scenario)这段伪代码只展示了主干逻辑实际工程里还有几个细节。求解器参数上主问题MIP的MIPGap建议设置成0.5%到1%不要追求严格最优TimeLimit可以按模型规模设在30到60分钟每次CCG迭代后保留上一轮的第一阶段解作为下一轮主问题的初始可行解热启动效果非常明显能省掉大量分支定界时间。数据结构上建议把不确定性集合单独封装成一个对象因为后续如果要改预算参数Γ只需要改这个对象不需要动主问题结构。我第一版写的时候把不确定参数散落在各个约束里后来调Γ调了整整两天教训很深刻。4. 常见问题与避坑实录4.1 结果比确定性优化还便宜先查对偶第一个典型问题鲁棒优化跑出来的总成本居然比确定性优化还低这明显不符合物理直觉。出现这种情况几乎可以断定子问题的强对偶转换出了问题常见原因包括对偶方向反了、对偶约束漏项、或者双线性项线性化时大M取值不当导致可行域被错误放大。排查方法分两步。第一步挑一个小规模算例比如1台光伏、1台储能、1个负荷、24时段把所有极端场景穷举出来用枚举法验证模型的鲁棒最优值。如果枚举结果和CCG结果不一致问题一定在子问题。第二步随机生成上千个不确定性场景把CCG求出的第一阶段计划固定逐一检查这些场景下第二阶段是否存在可行解。只要发现任何一个场景不可行就说明主问题对某类场景考虑不足需要回溯约束条件。我自己常用的验证脚本思路是# 模拟验证第一阶段计划的鲁棒可行性和实际成本 for each scenario in random_scenarios: feasible, adjust_cost simulate_realtime(first_stage_plan, scenario) if not feasible: print(发现不可行场景, scenario) record_scenario(scenario)这个验证脚本建议做成常驻工具每次模型改动后都跑一遍。它可以很容易暴露约束写错、SOC范围写反、购售电方向定义等低级错误。4.2 Γ到底怎么取保守度与成本如何权衡预算参数Γ的选择没有绝对标准但工程上可以靠“成本-保守度曲线”来定。做法很简单把Γ从0逐步增大到最大可能值每次跑一遍模型记录总成本和后续模拟运行中的违约率。以我做过的一个算例为例结果大致是Γ取值相对成本模拟运行中极端场景违约率0100%8.5%3104%3.2%6107%0.8%12109%0%可以看到Γ增大到一定程度后成本增长趋缓违约率已经降到很低再往上加只会白白提高成本。工程上一般选择“成本上浮5%到8%以内模拟违约率低于1%”的那个Γ。此外ΔP的取值也要根据历史预测误差统计来定比如取预测误差的90%分位数太小的ΔP会让不确定性集合覆盖不住真实偏差。这里有个很容易被忽略的点源侧和荷侧的不确定预算可以分开设置。如果某个地区的历史数据表明负荷预测误差通常比较小可以把负荷侧的Γ设低一点源侧设高一点。分开设置比单一的全局Γ更精细成本也能再压一点。4.3 主问题越来越大求解时间怎么压CCG每轮迭代都会新增一组场景约束和对应的第二阶段变量主问题规模会越来越大。到了第10轮以后如果原始模型本身比较大求解时间可能从几分钟跳到几十分钟。常用解决办法有四种。第一是热启动每轮主问题求解前把上一轮得到的整数变量值作为初始解传给求解器这个操作在循环中对提速贡献最大。第二是时段聚合96时段压缩到48时段先把趋势跑出来再用全时段模型精调尤其适合调试阶段。第三是提前终止CCG收敛到0.5%到1%就可以停对调度结果影响很小但时间可能差一个量级。第四是区分MIP求解强度主问题里很多整数变量其实是在确定储能状态和机组开停给这些变量单独设置优先级引导求解器先解关键变量能显著缩短分支时间。如果模型已经很大、以上方法都压不住就要考虑场景削减或聚类了。对预算型不确定集合可以通过舍弃部分极端场景组合来缩小主问题但代价是牺牲一定的鲁棒性用之前需要谨慎评估。4.4 求解器数值稳定性与量纲问题鲁棒优化模型里容易出现数值问题根因往往不是算法而是量纲混乱。成本单位如果用元、功率单位用kW、储能量单位用kWh这些数字量级差异可以达到几千倍对求解器的数值容差是个灾难。我见过一版模型目标函数系数从0.001到100000求解器报numerical issues报了一个下午所有结果看起来都对了但又都不稳定。解决办法很简单统一量纲。功率用MW成本用万元储能SOC用0到1的归一化值这样所有非零系数基本控制在同一个数量级范围。做完这个调整后数值警告基本消失求解时间也明显缩短。另外大M约束里如果M值设得过大和旁边的正常系数相差好几个数量级同样会引发数值跳动。M的取值原则是“刚刚好”既大到能正确松弛约束又不至于淹没其他约束的精度。需要多做几次试验找到稳妥的边界不要偷懒统一设成10^6。结尾这套模型我实际做下来最大的体会是别把“理论最优”当工程目标。第一版求解时我死磕gap收敛到0.01%结果算例卡了好几个小时后来把收敛阈值放宽到0.5%结果几乎没差别时间却缩短到原来的五分之一。鲁棒优化调度真正决定收益的是Γ标定准不准、模型约束对不对、以及代码里有没有那些防止数值崩坏的细节而不是小数点后三位的最优性。还有一点个人经验鲁棒优化的计划账面成本通常比确定性计划高一点但实际执行下来总费用反而常常更低。因为日内偏差少了紧急购电、考核罚款、切断负荷赔偿这些隐性成本都降下来了。所以我给团队做方案时习惯把两条曲线放在一起对比一条是采用预测值的确定性优化一条是加了不确定性集合的鲁棒优化调度员看过模拟运行结果之后通常马上就能明白这套模型的价值。后续想扩展的话这个框架也很顺在第二阶段变量里加储能退化模型、加实时市场滚动修正甚至加上碳成本约束都不需要改动整体结构。先把基础版本跑通再逐步加复杂度和约束是比较稳妥的路径。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑