入行电力系统优化这些年,如果让我挑一个被问得最多的求解框架,两阶段鲁棒优化一定排进前三。特别是“多微网联合调度+容量配置”这种组合,一个题目里既包含投资规划、运行调度这些时间尺度完全不同的决策,又牵扯多个微电网之间的功率互济,还要应对光伏出力和负荷波动的双重不确定性,基本把电力系统优化里难啃的骨头全凑齐了。
这篇文章我会把整套思路完整捋一遍:先讲为什么单微网单打独斗走不通、联合调度和容量配置到底在优化什么;再分析两阶段鲁棒优化的数学本质、不确定集怎么设计、保守度怎么调;然后给出MATLAB平台上的C&CG(列与约束生成,Column-and-Constraint Generation)算法落地细节,以及容量配置与联合调度的耦合建模方案;最后给出一个能直接参考的算例框架,附上实际调试中踩过的坑和排查经验。适合正在做微电网方向毕业设计、或者刚开始接触鲁棒优化想找个完整案例下手的同学和工程师。
1. 多微网联合调度:要解决的问题是什么
1.1 单微网单打独斗的三个致命痛点
先看单个微网。一个典型的微网里有光伏、储能、本地负荷,可能还有一两台小机组,通过公共连接点(PCC)跟上级电网交换功率。很多人一开始都以为,单微网自己调度就行了,为什么要联合?真做过几年工程就知道,单微网单打独斗有三个绕不开的痛点。
第一个痛点是储能投资太大。光伏和负荷都有明显的日内波动,而且是反调峰特性——中午光伏大发时负荷不一定高,傍晚负荷尖峰时光伏已经没出力。为了平抑这个差值,每个微网都得独自配一套储能,容量按自己的最恶劣缺电场景来设计。三个微网各自为政,可能总共需要9 MWh储能,但联合调度之后,由于负荷峰值时段不完全重合、光伏出力有互补性,总装机可能只要6 MWh就够了。储能单位投资成本随容量下降有限,总量减少带来的节省非常可观。
第二个痛点是备用容量重复配置。为了保证供电可靠性,单微网通常要留出足够的热备用或旋转备用。你留一份,我也留一份,谁都不能用对方的,这对稀缺的调节资源是很大的浪费。联合调度之后,微网之间可以共享备用,比如A微网光伏突然降出力,B微网还有充裕的可调机组,通过联络线送过来,就不用每个微网都按最大缺额留备用。
第三个痛点是新能源消纳空间被割裂。微网A中午光伏富余,如果只靠自己,要么给储能充电(容易充满),要么倒送给电网(电价低甚至被限),要么弃光。与此同时,微网B可能因为阴天光照不足,还在用高价天然气机组发电。两个微网之间的功率交换通道如果能打通,A的富余光伏直接去替代B的高成本出力,系统整体经济运行成本能降一个可观的百分比。
这也是多微网联合调度最近几年在学术界和工程界都火的原因——不是把几个微网的调度模型机械地拼在一起,而是把互补性、互济性、共享性挖出来。
1.2 联合调度到底“联”的是什么
搞清楚联合调度,“联”的对象主要有三个层面。
第一是功率层面的联。各微网通过联络线互相传输功率,这个功率在潮流模型里体现为边界变量:微网i给微网j送电,对微网j来说就是受电,两端必须满足大小相等、方向相反。调度模型里要显式加一致性约束,不能各算各的。
第二是运行备用层面的联。这一层更隐蔽。备用共享意味着A微网的机组除了给自己的负荷提供备用,还要为B微网的预测误差预留容量。在模型中体现为备用容量约束里加上相邻微网的缺额项,类似于互联电网的频率控制备用协调。
第三是时间尺度上的联。容量配置是年度/多年尺度上的投资决策,联合调度是日内/小时级运行决策。严格意义上这是一个“规划-运行一体化”问题,需要用典型日法把全年8760小时聚合成若干个代表性场景,再把投资成本按等年值折算到每日运行成本里,放进同一个目标函数。
换句话说,联合调度解决的是“系统怎么开、怎么送”的问题,容量配置解决的是“系统建多大、配多少”的问题。两者不放在一个模型里求解,很可能出现的情况是:调度侧发现储能利用率太低,根源其实是容量配置阶段没考虑运行层面的不确定性;或者运行侧发现某些微网联络线容量不足,想多送也送不过去。所以现在的主流做法就是用两阶段模型把这两个层级统一起来,第一阶段定容量,第二阶段做调度,下面详细说。
2. 两阶段鲁棒优化:为什么它适合微网调度与容量配置
2.1 从“随机”到“鲁棒”:不确定性建模的路线之争
微网调度面对的不确定性主要来自光伏出力和负荷预测偏差。处理这种不确定性,行业里大致有三条路线。
第一条是随机规划(Stochastic Programming),核心是给不确定参数一个概率分布,用蒙特卡洛抽样或场景生成得到若干离散场景,目标函数改成期望成本最小。这条路线的问题是:你对分布做了假设,但如果真实分布跟假设偏差很大,优化出来的方案可能在实际场景中严重失负荷。而且为了覆盖尾部风险,往往需要成千上万个场景,求解规模非常大。
第二条是机会约束规划(Chance-Constrained),要求约束成立的概率不低于某个置信水平,比如95%。听起来比随机规划更灵活,但机会约束在含整数变量的模型里很难处理,要转成凸近似或者做采样近似,工程实现代码量不小。
第三条就是两阶段鲁棒优化。核心思路简单粗暴:不确定参数不需要分布,只要给一个“不确定集”(Uncertainty Set),保证集合内所有可能实现下系统都可行。它追求的不是期望成本最低,而是最坏情况下的成本最优。微网这种对可靠性要求高的场景,恰恰最怕极端天气导致光伏出力腰斩,鲁棒优化的保守性在这里不是缺点,而是安全冗余的保障。
从计算角度看,两阶段鲁棒优化经过近年算法发展,C&CG配合成熟的商业求解器,可解规模已经从早期的小算例扩展到实际工程级别的模型,这也是它能在MATLAB上落地的主要原因。
2.2 两阶段鲁棒优化的标准形式与数学直觉
两阶段鲁棒优化问题的标准形式可以写成:
min_{x∈X} ( c'x + max_{u∈U} min_{y∈F(x,u)} b'y )
这里每个符号对应微网工程里实实在在的决策:
x 是第一阶段变量,也叫“现在就要定”的变量(Here-and-Now)。在容量配置问题里,就是各微网储能额定容量/功率、光伏装机规模、联络线容量;在运行调度问题里,还包括机组启停状态这类0/1变量。这些变量一旦定下来,最短时间内无法更改。
u 是不确定参数向量,属于不确定集U。典型的就是各时段光伏出力预测误差、负荷预测误差。
y 是第二阶段变量,也叫“看到实际后再说”的变量(Wait-and-See)。当不确定参数实现后,调度员根据u的实际值重新安排机组出力、储能充放电、购售电功率、削减负荷量等。第二阶段的约束F(x,u)依赖第一阶段的决策x和不确定参数u,这个依赖关系正是“容量配置影响后续调度可行域”的数学表达。
整个目标函数的意思是:先确定投资和开机方案x,然后再面对不确定参数u最恶劣的实现,在这个最坏场景下做最经济的调度y,使得总投资加最坏运行成本最小。这就是所谓min-max-min三层结构。从字面上就看得出来,这个模型天然适合容量配置+联合调度的耦合问题——投资决策是第一阶段,运行调度是第二阶段,光伏/负荷不确定是中间的u。
2.3 不确定集设计:盒式场景与预算参数Γ的权衡
不确定集的设计直接决定鲁棒优化的保守程度,这是整个方法里最考验经验的环节。最常用的是带预算约束的盒式不确定集:
U = { δ_t : |δ_t| ≤ 1, Σ|δ_t| ≤ Γ }
其中P_PV,actual(t) = P_PV,forecast(t) × (1 + δ_t)。p0代表预测值。δ_t是对预测偏差的归一化,正负1对应偏差上限和下限。
这个结构的巧妙之处在于预算参数Γ。如果不加预算约束,Γ等于所有时段之和,那意味着每个时段的光伏同时都以最大偏差出现,这是极其保守的场景,实际几乎不可能。而加入Σ|δ_t| ≤ Γ之后,限定整个调度周期内,最多只有Γ个时段可以同时取到极端偏差,其余时段偏差被限制在中间状态。这样保守度就变成了一个可调旋钮:Γ越大,方案越保守;Γ越小,方案越接近确定性模型。工程上通常取Γ=8~12(对24时段系统),具体数值要对历史出力数据做统计——统计每个时段预测误差同时超过某一阈值的天数占比来反推。
除此之外,有些模型还会用1范数(Σ|δ|)和无穷范数(max|δ|)的组合来构建“预算不确定集”,这在综合能源系统里也很常见,好处是把线性约束范围控制在一个有界凸多边形内,求解时保持线性。
这里有一个关键经验:不确定集切忌拍脑袋。我看到不少论文直接把Γ设成10,理由是“有些文献这么用”。但真实工程里,光伏预测误差在不同季节、不同天气类型下差别很大,最好基于本地历史预测数据做误差分布统计,再确定边界和预算值。这一段数据工作看似繁琐,却决定了你的方案是“真鲁棒”还是“过度保守”。
3. MATLAB建模与求解:C&CG算法的落地细节
3.1 求解器选型:YALMIP+Cplex/Gurobi环境配置
MATLAB本身不自带混合整数线性规划(MILP)求解器,实际工程中通用做法是YALMIP做建模层,底层接Cplex或Gurobi。YALMIP的优势是语法和数学表达式几乎一一对应,定义sdpvar、binvar、intvar就很直观,调试速度快。
环境配置方面提醒几点:先去YALMIP官网下载对应MATLAB版本的包,添加到路径;装好Cplex后,用yalmiptest命令验证求解器是否被识别。一个高频坑是MATLAB版本和Cplex版本位数不匹配,或者Cplex的许可证环境变量没配置好,导致YALMIP返回“No suitable solver”或直接报“Solver not found”。在2023a及之后的MATLAB版本上,推荐用Cplex 20.1、Gurobi 10.0以上,兼容性更好。
另一个实用建议是设置好sdpoptions超时和容忍度参数,比如:
ops = sdpsettings('solver', 'cplex', 'verbose', 2, ... 'savesolveroutput', 1, ... 'cplex.mip.tolerances.mipgap', 1e-4, ... 'cplex.timelimit', 3600);鲁棒优化本身迭代层数较多,每层都要调一次MILP,如果没有超时控制和合适的MIP Gap,很容易出现单次求解卡死数小时的情况。
3.2 C&CG算法思想与MATLAB伪代码实现
C&CG(Column-and-Constraint Generation)是求解两阶段鲁棒优化最主流的精确算法,思路分两环:
主问题(Master Problem,MP):包含第一阶段决策x、辅助变量θ,以及已经被识别出的有限个“最坏场景”所对应的第二阶段变量y(k)和约束。主问题给出原问题的下界LB。
子问题(Subproblem,SP):固定主问题求出的x,求解内部max-min问题,得到当前x下的最坏场景u和第二阶段最优目标值,给出上界UB。然后把u对应的新变量y(k)和约束加入主问题,再重新求解主问题。循环直到UB-LB小于设定阈值。
子问题里的max-min是这个算法的核心难点,MATLAB实现时一般通过强对偶将内层min转成max:
min_{y∈F(x,u)} b'y 的对偶问题是 max_{λ∈Λ(u)} λ'g(x,u)
转完以后内层min消失,两个max可以合并,于是子问题变成一个单层max问题(LLP)。对偶变换的关键约束是KKT互补条件和大M线性化,这部分是绝大多数初学者栽跟头的地方,详细处理放在后面第5章。
C&CG主循环的MATLAB骨架大致是:
%% 两阶段鲁棒C&CG主循环骨架 MP = 构建初始主问题; % 包含x变量、θ变量、第一阶段约束 LB = -1e6; UB = 1e6; k = 1; while (UB - LB) / abs(UB) > 1e-3 % 步骤1: 求解主问题,得到x_k和θ_k optimize(MP.constraints, MP.obj, ops); x_k = value(MP.x); LB = value(MP.obj); % 步骤2: 固定x_k,求解子问题SP,得到最坏场景u_k [SP_obj, u_k] = solve_SP(x_k, U); % 对偶+线性化后的单层max问题 UB = min(UB, c'*x_k + SP_obj); % 步骤3: 如果gap不满足,把u_k对应的第二阶段变量y(k)和新约束加回MP if (UB - LB) / abs(UB) > 1e-3 MP = add_cut(MP, u_k); k = k + 1; end end实际代码里,solve_SP内部就是子问题的对偶化过程,它会返回当前最坏场景u_k。当第二阶段全是连续变量时,这个方法收敛非常快,一般迭代5~20次就能达到1e-3的gap。如果你发现迭代了几十次还在震荡,八成是子问题对偶出了问题,或者不确定集不是凸集。
3.3 容量配置与联合调度的耦合建模
容量配置和联合调度在一个模型里的耦合,主要通过目标函数和第一阶段约束体现。
目标函数可以写成年化总成本最小:
min Σ_i [ C_inv,i(z_i) + 365×C_ope,i(x_i, u*, y*) ]
C_inv,i是微网i的投资成本,对储能来说就是单位成本(元/kWh)×容量(kWh),按寿命年限和折现率做等年值折算。C_ope,i是最坏场景下的日运行成本乘以365天,包括购电成本、燃料成本、运维成本和失负荷惩罚。两阶段鲁棒优化的目标函数天然支持这种结构,因为投资决策在x里,运行成本在最坏u下评估,正好对应“投资一次性、运行天天算”的时间尺度差异。
联合调度层面,各微网的功率互济通过联络线约束耦合。集中式模型里就是所有微网变量一起优化,边界约束写作:
P_tie,ij(t) + P_tie,ji(t) = 0
功率方向规定后,大小相等方向相反。这种集中式写法简单,但微网数量多了以后主问题规模迅速膨胀。大规模场景下更推荐ADMM(交替方向乘子法)分布式求解:各微网单独求解自己的两阶段鲁棒问题,通过拉格朗日惩罚项迭代协调联络线功率:
P_tie,ij^(k+1) = Π[ (P_tie,ij^(k) + ρ/2(P_tie,ij^(k) - P_tie,ji^(k)) + λ^(k)/ρ) ]
这个式子是ADMM的核心更新公式,物理含义是:每个微网先按自己的最优解确定外送功率,再跟相邻微网交换数值,用对偶乘子和罚参数ρ把不一致的功率偏差慢慢“掰”向一致。线路上功率不平衡为零时,协同调度就完成了。ADMM的收敛速度受ρ影响很大,ρ太小震荡,ρ太大收敛慢,一般从0.5开始尝试,观察P_tie序列的收敛曲线再调节。
4. 典型算例与关键参数设置
4.1 一个可复现的三微网测试系统
为了让大家能直接对照复现,我给一个经典的三微网测试系统配置。系统里三个微网通过一条公共联络母线互联,同时每个微网都有独立的PCC接上级电网。
微网A:光伏装机5 MW,峰值负荷4.5 MW,自带一台1.5 MW燃气轮机。 微网B:光伏装机7 MW,峰值负荷6 MW,无本地机组,完全依赖储能和联络线。 微网C:光伏装机3 MW,峰值负荷3.5 MW,有一台0.8 MW柴油机。
这个配置刻意做出差异化:A和B互补性强(A负荷白天高,B负荷傍晚高),C本身光伏小、负荷大,是天然的受端。这样的算例最能体现联合调度的价值。
数据准备上,不建议直接编一套随机数。可以用IEEE RTS-24节点系统的负荷数据做基准,再乘以不同系数匹配峰值;光伏曲线用典型晴天的beta分布拟合,或者直接用NREL在某个中纬度城市测量的光伏数据,归一化后乘到装机容量上。全天24时段,时间分辨率1小时,这是微网论文里的标准做法。
还要提一下典型日选取。容量配置需要考虑全年运行成本,但直接跑8760小时调度会非常慢。工程上常用K-means聚类从光伏/负荷历史数据中提取4~6个典型日,每个典型日乘上其发生天数作为加权系数。聚类之后,容量配置结果跟全年8760h连续优化的误差能控制在3%以内,求解时间降两个数量级。这一步几乎是我做所有容量配置算例的必备前处理。
4.2 不确定集、投资成本与调度约束的数值设置
下面给出我实际常用的参数设置,直接填进模型就能跑。
光伏预测误差界取±20%,即|δ|≤0.2。这是保守但合理的假设——大多数短期预测工具算法在好天气下能做到10%以内误差,晴天偏弱天气到晚上接近20%并不少见。预算参数Γ取8,意味着24个时段里最多8个时段同时出现20%偏差,其余时段偏差被限制在较小值。如果对比不同保守度,可以跑Γ=0(确定性)、4、8、12四个档位对比曲线。
储能容量配置上,假设单位容量投资成本1500元/kWh,单位功率投资成本800元/kW,充放电效率0.95,循环寿命8000次,使用寿命10年,折现率8%,残值率为5%。折算到日成本,一套额定容量E、功率P的储能等年值就是:
C_inv,day = (E×1500 + P×800) × CRF / 365
其中CRF = r(1+r)^T / ((1+r)^T - 1),r=0.08,T=10,算下来CRF约0.149。除以365之后,每kWh容量的日分摊成本大约0.61元,每kW功率的日分摊成本约0.33元。这个数值可以用来判断“多配1 kWh储能能否在日运行成本上省回0.61元”——如果省不回来,配置就是过度的。
运行侧的分时电价设置:峰时(10:00-15:00、18:00-21:00)购电价0.9元/kWh,平时0.55元/kWh,谷时0.25元/kWh。失负荷惩罚取10元/kWh,保留切负荷变量但让优化尽量不碰它。燃气机组发电成本按线性函数1.2元/kWh,机组最小出力30%,爬坡速率限制在20%额定功率/小时。这些参数决定了模型在“多配储能”和“多从电网买电”之间做经济权衡,不同电价结构下的容量配置结果会完全不同。
4.3 结果解读:鲁棒方案与确定性方案的对比
模型跑完之后,不要只看一个成本数字,要做三组对比。
第一组对比是确定性方案(直接把光伏预测值当确定参数)和鲁棒方案(Γ=8)的容量配置差异。确定性方案往往给出的储能容量偏小,比如三微网合计6 MWh;鲁棒方案因为要为最坏光伏场景预留调节能力,储能容量会上升到8~9 MWh,气电开机的备用也会增加。这意味着确定性方案表面上省钱,但实际运行中一旦碰到连续阴天或光伏骤降,只能大量切负荷或高价购电。
第二组对比是联合调度与否对容量配置的影响。单独调度时三个微网各自满足本地平衡,储能总容量可能10 MWh;联合调度后储能总容量可能只到7 MWh,且联络线功率有明显互济。这就是前面说的容量共享价值——在成本表里体现为储能投资项下降、购电成本项也下降。
第三组对比是不同Γ取值下的成本-可靠性曲线。画出Γ从0到24对应的总成本变化曲线,以及最坏场景下的失负荷量变化曲线。你会看到:Γ从0增加到8时,总成本上涨可能只有3%~5%,但最坏场景失负荷量大幅下降;Γ从8继续增大到12,成本涨幅变陡但可靠性改善趋于平缓。这个拐点就是合理保守度的选择依据。
输出分析时建议画这样几个图:三维微网联络线功率时序图、储能充放电状态图、不同Γ下的容量配置对比柱状图、UB/LB收敛曲线。收敛曲线在论文里几乎是必放图,裁判一眼就能看出你的C&CG是否有效收敛。
5. 常见问题与调试实录
5.1 子问题对偶变换后出现双线性项怎么办
这是两阶段鲁棒优化MATLAB实现里最常见也最头疼的关卡。当内层min对偶化之后,目标函数变成:
max_{u∈U, λ∈Λ} f(u, λ)
其中可能出现u×λ的乘积项。因为u是连续变量,λ也是连续变量,两个连续变量相乘就是非凸双线性项,Cplex/Gurobi解决不了。
处理思路取决于不确定集和标量化的形式。如果U是盒式+预算约束,那么对于线性目标函数,最优u一定落在某个极端点(对应偏差取±1那类顶点)。这时候可以对所有可能的极端场景做枚举,把枚举出来的u*逐个固定,再求解对应的线性子问题,取最大值,问题就从“双线性”退化成了有限个LP的枚举。Γ=8且24时段时,极端场景数量是C(24,8),大概73万,全枚举不现实,但工程上可以用一个启发式:先用对偶最优解对应的λ方向找最不利u,再固定这个u去解λ,交替迭代收敛到局部最优,或者用大M法引入0/1辅助变量线性化u×λ。
我的实践经验是:如果第二阶段全是连续变量且不确定集是多面体,可以借助YALMIP里对偶问题的自动转换,用yalmip('clear')重新定义对偶变量,让YALMIP内部帮我们做KKT或dualize,然后只把线性化部分手工处理。不要自己手推大规模对偶,矩阵形式很容易出错,亲测过推导3个节点的潮流约束就漏了对偶变量的边界条件。
如果第二阶段包含0/1变量,千万别直接对偶化——0/1变量的集合非凸,强对偶不成立。正确的落地方案有两个:一是把0/1决策变量(比如机组启停、储能开关)全部提到第一阶段,第二阶段只保留连续变量,这是最稳妥的做法;二是用KKT条件把子问题写成带互补松弛的MIP,再用大M线性化,这种方式模型维度大很多,求解也更慢。
5.2 C&CG不收敛或震荡的排查
C&CG是个“理论上收敛、实践里偶尔闹情绪”的算法。我遇到过三次“跑了几十轮gap还在抖”的情况,总结下来主要三类根因。
第一类是子问题求的不是真正的全局最优。如果子问题用了启发式或者枚举不全,返回的u*不是最坏场景,主问题加进去的割平面就会失真,造成上下界gap反复横跳。排查方法是固定几个不同的x初值,看子问题返回的u和SP_obj是否一致;如果不一致,说明子问题求解出了问题,优先回到对偶线性化那段代码。
第二类是主问题割平面加的时机不对。C&CG中每轮迭代应该把新发现的u*作为一个新“列”加进主问题,同时把对应的y(k)变量和约束也加进去。有些实现只加了目标约束θ ≥ ...,把y(k)变量漏掉,导致主问题永远无法真正评估那个场景的完整成本,UB和LB自然对不上。检查点:主问题里θ的约束数量是否等于迭代轮次,每个θ约束对应的y变量是否在主问题中被定义和约束。
第三类是数值病态。成本单位和电价单位差别太大时,比如投资成本上千万、运行成本几千块,Gurobi/Cplex的数值稳定性会变差。解决办法是用标幺值或者把目标函数统一除以一个基准值,让所有系数数量级落在1~1e4区间。
5.3 多微网规模大导致求解变慢的加速经验
三微网还好,如果做到十几个微网、上百个节点的模型,每轮主问题的MILP规模会很大,迭代轮次也会增加。我在实际项目里常用的加速手段有三个。
第一个是热启动(Warm Start)。每轮迭代结束后,把上一轮主问题解出的x值作为下一轮主问题的初值传给求解器,能显著减少MILP的分支定界搜索时间。YALMIP里可以通过assign(x, x_k)和solvesdp后的init机制实现,Gurobi对MIP start支持得尤其好。
第二个是“先松弛后整定”两阶段求解。先跑一轮所有整数变量松弛的LP版C&CG,得到x的大致区间和有效场景集合,然后固定这些场景,再求解完整MILP。这相当于用LP确定性发现“哪些场景是关键的”,再去精细化求整数解。注意这种方法只能作为初值或启发式,最终结果还要用完整模型校验。
第三个是减少不确定集维度。如果不确定参数是“光伏+负荷”双维度,可以只把两者之差ΔP(t)作为单一不确定变量,而不是分别建模,维度直接砍半。这在物理上也说得通——对系统调度来说,真正影响净负荷的是光伏和负荷的净偏差,分别建模反而引入了不必要的保守度。
5.4 六条经验值总结
调试两阶段鲁棒优化久了,有几条经验几乎每次都能用上,我直接列出来供参考。
第一,不确定集边界和预算参数一定要做敏感性分析,别只给一组参数就下结论。审稿人和工程验收方大概率会问“如果你的预测误差变了,方案还成立吗”,提前准备Γ=4、8、12三组对比能让报告很有说服力。
第二,储能容量配置结果对折现率和寿命非常敏感。很多小白算出来的储能配置特别大,然后发现成本离谱,回头一查,往往是等年值公式里的CRF算错了,或者忘记把残值率写进公式。强烈建议单独写一个函数算CRF,并打印原始参数自查。
第三,鲁棒优化不是越保守越好。有些同学为了“可靠”,把Γ设到20,结果储能容量大了近一倍,总成本上升20%以上,但实际可靠性收益微乎其微。判断保守度是否合理的标准,是最坏场景下失负荷量是否降到可接受水平,而不是成本越小越好或者越保守越好。
第四,MATLAB内存管理要注意。C&CG每迭代一轮,主问题就会新增一组y变量和一批约束,迭代20轮后模型规模可能比初版大20倍。建议在每个循环末尾用clear MP无关的历史变量,并定期用whos检查内存占用。我见过有同学迭代到15轮时MATLAB直接Out of Memory,前功尽弃。
第五,结果可复现性要提前做好。随机生成场景时固定随机种子(rng(42)),典型日聚类时固定初始中心点,确保任何人在同一份数据上复现你的结果。这一点在实际工程项目里甚至比论文里更重要——换个人跑出不同结果,后期对接成本极高。
第六,也是被很多教程忽略的一点——子问题里联络线功率的上下界不能拍脑袋设太大。有些微网之间联络线容量在规划期还没定,但子问题里P_tie约束的上界如果给太大,C&CG迭代出来最坏场景会往外送大量功率,扭曲解的结果。经验做法是先把联络线容量也列为第一阶段变量,在子问题里固定它的值,这样就不存在“联络线容量未知”的问题。
我在实际项目里用这套两阶段鲁棒优化框架跑过多微网联合调度与容量配置的工程案例,从最开始手推对偶推导到后来形成一套标准化的MATLAB模板,最大的体会是:这套方法在学术上是主流,在工程上也可落地。难点不在算法原理本身,而在不确定集的合理设置、子问题对偶变换的细心处理、以及C&CG迭代时的耐心调试。只要把这三个环节一步步走通,整套代码是可以沉淀成个人技术资产的。
最后再分享一个小技巧:调试收敛曲线时,把UB和LB画在同一个图里,横轴是迭代轮次,你很快就能判断出你的算法是“标准的锯齿收敛”还是“异常震荡”。正常收敛曲线一般是LB单调上升、UB阶梯状下降最后咬合;如果你看到LB下降或UB上升,别急着调参数,先回头检查子问题求解是否正确——这两个方向一错,后面调什么都是浪费时间。