☰
两阶段鲁棒优化在微电网经济调度中的MATLAB完整实现与CCG算法解析
2026/10/31 5:44:20 网站建设 项目流程

我最近把一个微电网经济调度项目从零到一完整跑通了,核心方法是两阶段鲁棒优化,所有建模、算法迭代和结果可视化都在MATLAB里完成。项目本身不算特别复杂,但从前期的模型设计、不确定集合选取,到CCG算法的落地实现、求解器配置,再到最后调出一组能用的结果,中间每个环节都有不少细节值得单独写一写。这篇文章就是我的完整实现记录,包含问题建模、算法原理、MATLAB代码框架、参数调试和坑点排查。如果你正准备复现两阶段鲁棒优化经济调度方向的论文,或者正在用MATLAB做微电网类优化调度,可以直接拿这套思路当参考,少走一些我在调试阶段走过的弯路。

我先把概念理清楚,再一步步展示模型和代码。鲁棒优化这个领域有个特点——论文里往往两三页就把模型和算法写完了,但真正拿到MATLAB里跑的时候,约束怎么组织、子问题怎么对偶、迭代怎么收敛,全是细节活。这篇文章不打算重复教科书式的推导,重点放在“怎么把它在MATLAB里写出来并跑通”这件事上。

1. 微电网经济调度为什么需要两阶段鲁棒优化

1.1 确定性经济调度的问题出在哪

传统的微电网经济调度,本质上是一个确定性优化问题:给定光伏、风电、负荷的预测曲线,求解燃气轮机出力和储能充放电策略,让系统总运行成本最低。这个模型在预测精度高的时候效果很好,一旦碰到天气剧烈变化、云层突然遮挡光伏板,或者负荷出现短时尖峰,预测值和实际值之间就会出现明显偏差。

我在项目初期先搭了一版确定性调度模型,仿真下来发现一个很直接的问题:如果严格按照预测值安排出力,实际运行时功率平衡很容易被打破,要么需要临时从主网购更多的电,要么被迫切负荷。这两种情况都会带来额外成本,甚至影响系统安全性。于是我开始思考怎么把不确定性显式地放进优化模型里。

解决不确定性的思路大致有三条:一是加备用容量,靠工程经验预留余量,简单但不够精细;二是随机规划,给每个场景一个概率分布,期望成本最小化,但分布很难准确估计;三是鲁棒优化,用一个不确定集合覆盖所有可能场景,保证方案在最恶劣场景下也可行。三者各有定位,我最终选鲁棒优化,主要还是看中它对概率分布没有强依赖,而且能给出一个明确的“最坏情况成本”,这对调度决策来说非常重要。

1.2 鲁棒优化的核心思想:用集合代替分布

鲁棒优化的核心思想是:不再假设不确定参数服从某个精确概率分布,而是人为定义一个不确定集合U,把所有可能出现的场景都“框”在这个集合里。优化的时候不追求所有场景下的平均最好,而是要求解在最恶劣的场景下依然可行,或者最恶劣场景下的成本可控。

这个思想在工程上的意义很直接。电力系统调度最怕的不是“平均情况”,而是“极端情况”——光伏骤降、负荷突增、机组跳机。如果我设计的调度方案在最坏情况下都能保证功率平衡,那正常运行场景下大概率也能稳定运行,只是需要为此多付一点成本。这部分多付的成本,在鲁棒优化里叫“鲁棒代价”或“保守性代价”,可以通过调整不确定集合的大小来控制。

注意:鲁棒优化的保守性不是越强越好。如果不确定集合设得太大,优化出的方案会极端“防御”,运行成本高得离谱;如果太小,又保护不了真实场景。后面我会专门讲不确定预算Γ的选取经验。

1.3 为什么必须是“两阶段”

实际调度里有一个很自然的决策时序问题。有些决策必须在知道实际风光出力之前就定下来,比如燃气轮机的启停、储能的充放电状态(充/放/停这种离散状态),这类属于“现在就要决定”的决策;而有些决策可以等实测数据出来之后再做调整,比如机组的具体出力大小、和主网交换的实时功率,这类属于“看着实际情况再调整”的决策。

两阶段鲁棒优化正好对应这个时序。第一阶段(日前计划)处理那些必须提前决定的变量,目标是最小化基础运行成本;第二阶段(实时调整)在第一阶段变量固定的前提下,针对不确定参数的实际取值做最经济的安全调整,目标是最小化最坏场景下的调整成本。两个阶段综合起来的目标函数,数学上可以写成:

第一阶段成本 + 最坏场景下的第二阶段调整成本

换句话说,第一阶段方案要经受住所有可能场景的“考验”,尤其要在最恶劣场景下保证系统仍能通过第二阶段的调整回到安全运行状态。这种“先决策、后应对”的结构,比单一阶段的鲁棒优化更贴近真实的调度流程,也是两阶段鲁棒优化近年来在电力领域大量应用的直接原因。

1.4 几种不确定性处理方法的横向对比

我在建模前把几种主流方法放在一起比过一轮,这里直接给一张对比表大家会看得更清楚:

方法不确定参数处理方式目标优点局限
确定性优化直接用预测值单阶段成本最小建模简单、求解快对误差敏感,无保护能力
随机规划离散场景+概率期望成本最小经济性较好,符合统计意义需要准确概率分布,场景多时计算量大
单阶段鲁棒优化不确定集合U最坏场景下成本最小不依赖分布,鲁棒性强所有决策都面向前期,灵活性不足
两阶段鲁棒优化不确定集合U前期成本+最坏场景调整成本符合决策时序,鲁棒且灵活建模和求解相对复杂
分布鲁棒优化模糊集(分布不确定)最坏分布下期望成本最小综合随机与鲁棒优点模糊集构造和求解难度较高

我最终选择两阶段鲁棒优化,核心是它很好平衡了建模复杂度和工程适用性。它不像随机规划那样需要精确概率,也不像单阶段鲁棒那样把所有决策都锁死,并且求解算法(CCG)在MATLAB里实现起来是可控的。如果你的研究方向涉及微电网经济调度、日前调度、实时调整这类问题,这条技术路线非常值得掌握。

2. 两阶段鲁棒优化模型搭建:目标函数、约束与不确定集合设计

2.1 变量划分:哪些放一阶段,哪些放二阶段

建模的第一步是分清变量归属。我的处理方式遵循一个总原则:能提前定的、需要时间的、涉及离散状态的变量放第一阶段;实时可调的、连续变化幅度大的变量放第二阶段。

第一阶段变量包括:燃气轮机的启停状态、储能的充放电状态、购售电状态、储能日前计划功率、以及为第二阶段预留的备用功率空间。这些变量要么是0/1整数变量,要么需要提前一天确定,把它们放第一阶段是合理且必要的。

第二阶段变量包括:燃气轮机的实际出力、储能的实际充放电功率、与主网的实际交换功率、切负荷量、弃风弃光量。这些变量是在不确定参数“揭晓”之后,系统为了保持功率平衡和安全运行而做的调整手段。它们取值连续,响应速度快,适合放在日内实时调整层面。

两类变量之间通过功率平衡约束和机组爬坡约束建立联系。第一阶段决策如果过于“满打满算”,第二阶段就没有足够的调节空间,最坏场景下就容易出现切负荷;第一阶段决策如果留了太多余量,日常运行成本又会偏高。两阶段鲁棒优化的目标函数,本质上就是在寻找这个平衡点。

2.2 目标函数怎么列:一阶段成本加二阶段最坏成本

两阶段鲁棒优化的目标函数结构是:

第一阶段成本 = 燃气轮机燃料成本 + 启停成本 + 储能运行维护成本 + 日前购电成本

第二阶段成本 = 实时调整带来的额外燃料成本 + 主网交互功率调整成本 + 切负荷惩罚成本 + 弃风弃光惩罚成本

整体目标函数为:min(第一阶段成本 + 最坏场景下的第二阶段成本)

这里有一个特别容易混淆的地方:第二阶段成本不是某个具体场景下的成本,而是所有可能场景里面最大的那个成本。也就是说,优化器会用“最坏场景的成本”来评判一个第一阶段方案好不好。数学上,最坏场景由不确定参数的取值决定,而第二阶段变量会在给定场景下被优化到成本最低。于是第二阶段问题呈现一个max-min嵌套结构,这也是两阶段鲁棒优化求解中需要处理的核心难点。

切负荷和弃风弃光惩罚系数要设置得很高。我做了几轮实验,惩罚系数如果只比正常发电成本高一点,优化器在极端场景下会倾向于直接切负荷而不是调用备用,这不符合实际调度的安全偏好。我的经验是,切负荷惩罚至少设置为正常电价的20到50倍,弃风弃光惩罚可以稍微低一些,但也应显著高于常规成本,这样才能保证优化结果优先选择主动调整而不是被动削减。

2.3 约束条件逐个梳理:平衡、机组、储能、电网交互

模型约束分为两类:第一类是第一阶段变量自身的可行域约束,第二阶段约束也必须在所有场景下满足。我把常用约束列在这里:

功率平衡约束是最基本的一条:微网内部所有发电、购电、放电之和,必须等于负荷、充电、卖电之和。在含不确定性的模型里,风机和光伏出力是区间数,功率平衡方程就变成了在不确定集合内所有取值都必须成立的鲁棒约束。

机组约束包括出力上下限约束、爬坡速率约束、最小开停机时间约束。出力上下限要区分“技术出力下限”和“最大出力”,后者在鲁棒模型中通常与不确定集合配合使用,确保最坏场景下仍有足够的旋转备用。

储能约束包括充放电功率限制、SOC递推方程、SOC上下限。最关键的是同一天内SOC不能越界,且充放电不能同时进行,后者通过第一阶段引入的0/1变量来保证,避免优化器出现“边充边放”这种无意义结果。

与主网交互约束包括购售电功率上限、购售电状态互斥约束。为了保证系统在最坏场景下的生存能力,第一阶段还会专门预留一部分联络线容量给第二阶段调整使用。

另外,如果微电网带放射状配电网结构,还要加入潮流约束。常见做法是用DistFlow潮流线性化,把节点电压幅值的平方和支路功率作为变量。我在样例里没有加入完整潮流,而是用功率平衡加联络线约束替代,如果你需要处理网架结构,可以在此基础上扩展电压和线路容量约束。

2.4 不确定集合的形状:盒式集合和预算约束的配合

两阶段鲁棒优化里,不确定集合的形式直接影响最终结果的保守性和求解难度。我测试过三类常用集合,实际效果差异明显。

第一类是盒式集合,公式上就是每个不确定参数在预测值正负偏差范围内独立取值。它的优点是建模简单,缺点是四个角上的“同时极端”场景概率极低,但会被优化器纳入考虑,导致结果非常保守。如果你发现调度成本比确定性方案高出一大截、甚至高得离谱,多半是盒式集合导致的过度保守。

第二类是预算约束集合,也叫多面体集合,它在盒式集合的基础上增加一个总偏差约束,限制所有不确定参数偏离预测值的总量不超过某个阈值Γ,这个Γ就是不确定预算。

第三类是椭球集合,对不确定参数做二阶锥约束,数学性质更平滑,保守性在各方向上更均匀,但约束变成二阶锥之后,部分求解器处理起来不如线性约束顺手。

我的建议很直接:在绝大多数微电网经济调度场景里,用“盒式集合+预算约束”的组合就够了。它既能控制保守性,又保持线性约束结构,CCG算法实现时不需要额外处理二阶锥,和Gurobi、CPLEX这类求解器的兼容性也最好。Γ的选取我在第5节单独展开。

关键点:预算Γ不是一个随便拍的数字,它代表“最坏情况发生时,到底有多少个时段允许同时出现极端偏差”。Γ取0就是确定性模型,Γ取24(假设全天24个时段)就是盒式集合。实际工程中Γ通常取4~8,这个范围我已经在多个算例里验证过。

3. CCG求解思路与MATLAB实现框架

3.1 CCG和Benders分解,我为什么选CCG

两阶段鲁棒优化最常见的主流算法是Benders分解和列与约束生成(CCG,即Column-and-Constraint Generation),两者都是分解思路,把整个大问题拆成主问题和子问题交替求解,但细节上有本质区别。

Benders分解在迭代中子问题返回的是割平面,不断往主问题里加约束;CCG则不同,子问题识别出最坏场景后,直接把该场景对应的第二阶段变量和约束“原封不动”地加入主问题。CCG的直观好处是收敛很快,对两阶段鲁棒问题来说,通常在几次迭代内就能达到收敛精度,而Benders有时需要几十次甚至上百次迭代。

另一个考量是建模复杂度。CCG的迭代逻辑非常贴合“发现问题场景、补充场景约束”的直觉,在MATLAB里用YALMIP工具箱实现时,只需要维护一个不断增长的“场景约束集”,代码结构清晰,排查问题也容易。Benders需要处理割平面的对偶信息和主问题割的添加逻辑,对初学者来说更容易出错。我个人强烈建议:第一版实现先写CCG,跑通之后再根据需求考虑其他加速手段。

3.2 CCG主问题与子问题的迭代逻辑

我用文字先把CCG的迭代过程讲清楚,这也是整个项目里最核心的算法逻辑。

第一步,初始化。设置下界LB为负无穷,上界UB为正无穷,选择初始最坏场景(通常直接用预测值场景作为初始场景)。

第二步,求解主问题MP。主问题中包含所有已经被识别出来的最坏场景以及对应的第二阶段变量与约束。求解主问题得到第一阶段决策变量x和当前下界LB(主问题的目标函数值)。注意:主问题考虑的场景集合是不完整的,所以它给出的成本是真实最优成本的一个下界。

第三步,固定x,求解子问题SP。子问题是在给定x的情况下,寻找不确定参数u的一个取值,使第二阶段调整成本达到最大。求解子问题得到最坏场景u*和对应的调整成本,更新上界UB。

第四步,判断收敛。如果UB减去LB的相对误差小于预设阈值,比如1e-3,就认为已经找到最优的第一阶段决策,循环结束;否则进入第五步。

第五步,把当前子问题求解出的最坏场景u*对应的第二阶段变量和约束加入主问题,然后回到第二步。

这个流程的关键在于:主问题像一个不断长大的“场景库”,每轮迭代把最坏场景装进去,直到装进去的场景集合已经足够让第一阶段方案“无懈可击”。我在多个算例中观察到的典型现象是:第一轮迭代后上下界差距比较大,第二、三轮快速逼近,通常在5次迭代以内收敛。如果你的实现迭代了十几轮还在震荡,多半是子问题对偶处理或主问题场景集更新环节有逻辑错误。

3.3 子问题里max-min结构怎么处理

子问题本身是一个嵌套结构:外层的max是在找最坏的不确定参数,内层的min是在给定场景下找最优的调整决策。这种max-min结构无法直接交给求解器,必须先做数学变换。

标准做法是把内层的min问题取对偶,变成max问题。这样外层max和内层max就可以合并成一个max问题。理想情况下,对偶之后目标函数里会出现不确定参数u和对偶变量λ的乘积项——这是一个双线性项,直接求解会变成非凸问题,这也是两阶段鲁棒优化实现中最容易卡住的地方。

常用的处理方式有三种。第一种是用KKT条件代替内层优化,把问题整体转成混合整数线性规划,需要引入大量二进制变量,模型规模大。第二种是用强对偶+Big-M线性化处理双线性项,前提是双线性项的形式满足线性化的条件。第三种是把不确定集合离散化,直接把最坏场景的搜索限制在有限个候选场景里,虽然理论上有丢失最优场景的风险,但工程上非常实用。

我的项目里采用的是“对偶+线性化”的组合方案。具体操作是:内层min问题是线性规划,先取对偶,目标函数变成包含对偶变量的max问题;外层max再引入不确定预算约束;目标函数里出现的u和λ乘积项,由于u的定义域是包含参考点的区间,可以通过Big-M把它们线性化。这里Big-M的取值需要反复调试,取太小会破坏约束,取太大又会导致数值病态,具体经验在第五章展开。

3.4 MATLAB代码整体框架:YALMIP和求解器怎么配合

我的MATLAB实现基于YALMIP工具箱建模,求解器使用Gurobi。YALMIP的价值在于把建模和求解分离,你不需要手动把模型转成求解器要求的矩阵形式,只要用sdpvar声明变量、用约束列表描述模型,最后调用optimize就好。

CCG主循环的伪代码框架如下:

% 初始化 LB = -inf; UB = inf; iter = 0; % 用预测场景初始化场景集 worst_scenarios{1} = nominal_scenario; while (UB - LB) / abs(UB) > epsilon && iter < max_iter % 求解主问题MP [x_opt, LB] = solve_MP(worst_scenarios); % 固定x_opt,求解子问题SP [u_worst, Q_val] = solve_SP(x_opt); % 更新上界 UB_current = first_stage_cost(x_opt) + Q_val; if UB_current < UB UB = UB_current; best_x = x_opt; end % 判断是否收敛 if (UB - LB) / abs(UB) < epsilon break; end % 将最坏场景加入场景集 worst_scenarios{end+1} = u_worst; iter = iter + 1; end

在MATLAB里实现时,我有两个教训想先提醒你。第一,主问题每次迭代后规模都会变大,变量多了之后求解时间上升很快,一定要在循环里用YALMIP的assign命令或重新构建模型,避免变量句柄冲突。第二,子问题里固定第一阶段变量的操作,不要用“重新建模+把x设成常数”这种低效方式,而是应该用YALMIP的assign函数赋初值,再配合optimize求解。这两个细节处理不好,模型规模一大就非常痛苦。

另外关于求解器的选择,我测试过Gurobi和SCIP,Gurobi在混合整数规划上明显更快。如果你没有Gurobi授权,可以用SCIP或CBC替代,YALMIP都支持;但如果模型规模较大或者迭代轮数较多,强烈建议申请Gurobi的学术授权,速度差距非常明显。

4. 完整算例复现:从参数到结果一步步来

4.1 算例系统结构与关键参数

为了把整个流程串起来,我设计了一个典型微电网算例,结构如下:一台燃气轮机、一组光伏电站、一组风电场、一组储能电池、本地负荷,以及一条与主网的联络线。所有设备都挂在一个单母线上,母线功率平衡方程就是系统的核心耦合约束。如果你想扩展成多节点网络,在这个框架上加拓扑约束即可。

燃料电池和燃气轮机的参数设置如下:燃气轮机额定功率1.5 MW,最小技术出力0.3 MW,燃料成本系数取为二次函数形式;储能额定容量2 MWh,最大充放电功率0.5 MW,充放电效率95%,SOC运行范围20%~90%;光伏和风电的预测峰值分别为0.8 MW和0.6 MW;负荷峰值1.2 MW;联线功率上限0.8 MW。时间粒度取1小时,调度周期24小时。

电价采用分时电价结构,我设置了峰、平、谷三个时段价格:峰时段(10-15点、18-21点)购电价1.2元/kWh,平时段(7-10点、15-18点、21-23点)购电价0.8元/kWh,谷时段(23点-次日7点)购电价0.4元/kWh。售电价按购电价的80%计算。

切负荷和弃风弃光惩罚系数,我分别设置为10元/kWh和3元/kWh。对比一下正常发电成本大概在0.6到0.8元/kWh,你会发现切负荷惩罚设置得非常高,这样优化器才会尽量避免切负荷这个选项。

4.2 负荷与新能源出力场景数据

我生成了24小时的预测曲线,为了让算例有区分度,专门在10点到15点之间设置了光伏高发时段,18点到21点之间设置晚高峰负荷。光伏预测在中午达到峰值0.8 MW,风电预测在夜间较大、白天较小,负荷在晚上8点左右达到峰值。

不确定偏差的设置上,我做了一个分层设定:光伏出力偏差设为预测值的±20%,风电出力偏差为±25%,负荷预测偏差为±10%。这个偏差幅度的选择不是随意的,主要参考了光伏和风电短期预测的典型误差水平。后面我会用不确定预算Γ来调节整体的偏差总量。

在做不确定性分析时,我用的是标幺化的偏差量ξ,每个时段ξ在[-1,1]区间内取值,再乘上各自的偏差幅度就是实际偏差。预算约束的形式是:所有时段|ξ|之和不超过Γ,这样模型就具备了“少数时段可能出现大偏差,但不可能24个时段同时出现最大偏差”的物理含义。

4.3 MATLAB主循环代码实现细节

我把CCG主循环里最关键的几个代码片段拆出来讲一下,方便你对照自己的工程实现。

主问题建模的核心变量声明:

% 第一阶段变量 P_g = sdpvar(1, 24); % 燃气轮机出力 u_g = binvar(1, 24); % 燃气轮机启停状态 P_ch = sdpvar(1, 24); % 储能充电功率 P_dis = sdpvar(1, 24); % 储能放电功率 SOC = sdpvar(1, 24); % 储能荷电状态 P_buy = sdpvar(1, 24); % 购电功率 P_sell = sdpvar(1, 24); % 售电功率 % 每个最坏场景对应的第二阶段变量,这里用元胞数组存放 % y{i} 代表第i个场景对应的第二阶段变量

主问题约束的构建逻辑是:先把与第一阶段变量相关的约束加入,再循环遍历所有已发现的最坏场景,为每个场景加入功率平衡约束和该场景下的第二阶段决策约束。

我在第一次实现时犯过一个错误:把所有场景的变量一次性全部提前声明,导致主问题里大量变量从未被约束使用,求解器不仅要处理冗余变量,内存占用也暴涨。后来改成“每轮迭代动态新增变量和约束”的方式,问题得到明显改善。

子问题的核心是固定第一阶段变量:

% 固定第一阶段变量的常用方式 assign(P_g, value(P_g_opt)); assign(u_g, value(u_g_opt)); % ... 其余第一阶段变量同理 % 然后求解第二阶段子问题,得到最坏场景下成本 optimize([SP_constraints, uncertain_set], -second_stage_cost, options);

子问题的目标函数要取负号,因为优化器默认最小化,而这里我们要找的是最坏场景下的最大成本。通过把目标写成“-second_stage_cost”并让求解器最小化这个负目标,等价于最大化原始成本。这个是YALMIP建模里的常用技巧,但也容易搞反,我就因为目标符号问题错过好几天。

4.4 结果分析:收敛过程与调度方案对比

在Γ=4的设置下,我的CCG算法在5次迭代内收敛,相对误差阈值设为1e-3。各轮迭代的上下界变化趋势很有意思:第一轮上下界差大约12%,第二轮缩小到3%,第三轮之后就已经在1%以内。这个收敛速度在同类问题里属于比较正常的水平,也从侧面说明CCG算法处理这类两阶段鲁棒问题的效率确实很高。

收敛后,我把两阶段鲁棒优化的调度结果和确定性优化结果做了对比,主要结论有三点。

第一,确定性优化给出的总成本大约为1.24万元,而两阶段鲁棒优化的总成本为1.46万元,成本增加约17.7%。这个增量可以理解为为应对最坏场景所支付的“保险费”。注意,这不是每一次实际运行都要多花这么多钱,而是在遇到设计的最坏场景时,系统仍有能力通过第二阶段调整来保证安全。

第二,鲁棒优化方案下,燃气轮机在各时段的出力更接近中间水平,储能也保留了更多可调容量。这是因为第一阶段需要为第二阶段保留足够的爬坡空间和储能调节空间,而不是像确定性方案那样把机组顶到接近极限出力。

第三,在最坏场景测试中,确定性方案出现了切负荷,切负荷量约0.12 MW,而鲁棒优化方案没有切负荷。这说明设计的鲁棒方案确实能把极端情况兜住,代价是常规划行成本略微升高。

我在实际对比时还测试了不同Γ值下鲁棒方案的成本变化,这个结果在后面第5节详细展开。这里先给一个直觉:Γ越大,调度方案越保守,成本越高,但不切负荷的可靠性也越高,两者是一组需要权衡的指标。

5. 实操中的坑点与排查技巧

5.1 环境配置的坑:求解器、YALMIP和MATLAB版本

先讲最容易劝退新手的环境问题。我在项目初期花了不少时间在求解器配置上。YALMIP本身只是一个建模层,真正算数的是底层的MILP求解器。很多新手装了YALMIP之后没有下载求解器,或者下载了却忘记添加路径,导致optimize一调用就报错。

我的建议是:YALMIP可以直接在GitHub上下载并添加到MATLAB路径,这个步骤不复杂;求解器方面,优先选择Gurobi或CPLEX。Gurobi可以申请学术授权,CPLEX同样有学术版本。如果没有授权,SCIP是开源的替代品,但在大规模整数规划问题里性能会明显慢一些。

MATLAB版本方面,我用的是R2023b,YALMIP和Gurobi都兼容。建议不要追最新版MATLAB,因为新版推出初期,YALMIP和Gurobi的适配可能存在滞后,你会在“接口异常”这种莫名其妙的问题上浪费时间。选一个稳定版本,比如R2022a到R2023b之间,就够了。

排查环境问题有一个简单的做法:装好YALMIP后,在MATLAB命令行执行yalmiptest,它会自动检测哪些求解器可用。只要看到Gurobi对应的状态为OK,就说明环境配置基本没有问题;如果显示未找到,优先检查路径有没有添加成功,其次检查许可证是否生效。

5.2 Big-M设置的数值稳定性问题

本章最重要的一个技术细节是Big-M的取值。在子问题对偶线性化时,需要为各双线性项设置一个足够大的上界M。如果M取值太小,会把这个本应成立的场景错误地排除掉,导致求解结果不可行;如果M取值太大,求解器在做浮点运算时会出现数值病态,表现为:约束明明应该满足却得到“不可行”判据,或者最优解出现奇怪的振荡。

我的调试经验是:Big-M不要盲目取10000、100000这样的“大数”,而是根据物理量纲估算一个合理上界。比如,燃气轮机出力变量的对偶乘积项上界,可以按“最大出力×最大电价×时段数”来估算;不确定参数与对偶变量乘积项的上界,按“最大偏差范围×最大对偶变量范围”估算。能取到100以内就绝不用1000,能用1000就不用10000。

另外,如果数值稳定性问题反复出现,可以考虑把约束做归一化处理。比如功率平衡方程两侧同时除以基准功率100 kW,让所有量的数量级都在1到100之间。这是一个非常实用的小技巧,很多论文里不会写,但对实际求解收敛速度影响很大。

5.3 不确定预算Γ的选取经验

我在4.4节提到,Γ的取值会直接影响最终方案的保守性和成本。这里给出我测试的一组结果,供大家参考。在我的24时段算例里,Γ从0(确定性)变化到24(完全盒式集合),总成本和切负荷惩罚会发生明显变化。

Γ取值总调度成本(万元)切负荷惩罚(万元)相比确定性成本增幅
0(确定性)1.240.02基准
21.3307.3%
41.46017.7%
81.62030.6%
121.71037.9%
24(盒式集合)1.85049.2%

可以看到了一条明显的规律:Γ从2增加到8时成本增幅最显著,之后增长趋缓。从工程角度讲,Γ取4到8之间是比较合理的选择,它基本能覆盖大多数实际可能出现的极端偏差组合,同时成本增幅控制在20%到30%以内。当然,如果你所在地区光伏和风电的预测水平特别差,或者系统本身对安全性的要求特别高,可以适当调大Γ;如果预测水平已经很高,Γ取2到3也足够。

我自己的建议是:不要凭感觉定Γ,而是用历史实测数据和预测数据做对比,统计不同时段偏差的相对大小,然后按“覆盖95%历史偏差场景”这个标准反推Γ的取值。这个方法比拍脑袋定值要科学得多。

5.4 YALMIP建模中的常见报错与解决思路

最后整理几个我在调试中遇到的高频报错和处理思路,给你做排查速查。

第一个报错是“No suitable solver for this problem type.”,意思是YALMIP没有找到能处理该问题类型的求解器。排查方向:模型里是否引入了二阶锥或非线性约束;求解器是否被正确检测;或者你的问题变成了非凸形式(比如包含了双线性项),这时需要先做线性化或凸化处理。

第二个报错是“Index exceeds array bounds.”,通常发生在我动态添加场景约束的循环里。原因是元胞数组或索引值没有同步更新。建议在每轮迭代结束后打印当前场景数量和变量数量,确认动态扩展没有问题。

第三个报错是求解器提示“Model is infeasible”,但理论上不应该不可行。这里排查的重点是:第一阶段变量固定值是否让第二阶段问题没有了可行解;Big-M是否设置过小;或者约束里是否有冲突的上下界。我通常会先把所有等式约束打印出来,检查功率平衡方程里的常数项,看是否出现了1e-4级别的残差被约束判据误判为不可行。

第四个问题是求解时间突然指数级增长。如果迭代到某一轮后,主问题因为加入了太多场景变量而变得巨大,求解时间会骤升。解决思路是增加“轻量预筛选”步骤:在每轮迭代后,剔除那些对目标函数影响极小的历史场景,或者限制主问题中场景数量上限,只保留最近几轮的最坏场景和历史上成本最高的几个场景。

5.5 扩展方向:多微网协同和更精细的不确定集合

项目跑通基本版本后,你还可以往两个方向扩展。

第一个方向是多微网协同调度。多个微电网通过联络线互联,在鲁棒优化框架下相当于把单微网的功率平衡约束扩展成多节点系统约束,CCG算法的整体框架不用变,但对偶子问题的规模和复杂度会明显提升。这时更要注意矩阵化建模,避免逐个变量手写约束,效率太低。

第二个方向是更精细的不确定集合,比如把风光出力的时空相关性考虑进来。盒式集合加预算约束的方式确实简单,但它假定各时段偏差是独立同分布的,现实中相邻时段的风速、光照具有很强的持续性。你可以用“椭圆不确定集合”或者基于历史数据的“数据驱动不确定集合”,把相关性通过协方差矩阵编码进去,鲁棒性会更贴近实际,但求解难度也会相应增加。

我自己目前还在做第一个方向的扩展。两阶段鲁棒优化的框架比较“皮实”,核心迭代逻辑一旦跑通,大部分扩展都只是在主问题场景集和子问题约束形式上做增量修改,不需要推翻重写,这也是我推荐先掌握CCG算法的原因——它是一个可以长期复用的工具箱。

最后分享一个我在整个项目里最深的体会:做两阶段鲁棒优化,模型写得“漂亮”远不如参数调得“可跑”重要。论文里的漂亮模型,到了MATLAB里要面对数值稳定性、求解时间、场景爆炸、Big-M选择等一系列工程问题。先跑通一个简单版本,再逐步加复杂度,是最稳妥的路线。希望你读完这篇之后,能直接少踩几个我一脚一脚踩出来的坑,顺利把两阶段鲁棒优化用在自己的微电网调度项目里。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询