做微电网日前优化调度的朋友应该都有过这种体验:光伏和负荷预测曲线在计划阶段画得漂漂亮亮,第二天一跑,实际出力和用能跟预测差出一大截。尤其是光伏,一阵云飘过来功率能掉一半,这种不确定性靠常规的确定性优化根本防不住。所以这两年,两阶段鲁棒优化在微网优化调度里越来越受关注,它不要求你给出精确的概率分布,只要界定一个“不确定集合”,就能在保证最坏情况系统安全运行的前提下把成本压到最低。而这类方法里最核心、也最影响求解效率的,就是对“关键场景”的识别——也就是怎么从无穷多种可能的日出力组合中,把最恶劣、最值得警惕的那一个找出来。这篇文章我就围绕基于关键场景辨别算法的两阶段鲁棒微网优化调度,把问题模型、算法原理、Matlab实现和踩坑记录一次性讲透。
1. 先搞清楚两阶段鲁棒微网调度到底解决什么问题
1.1 微网调度里的确定性思维及其局限
传统的日前优化调度,套路很固定:拿光伏、负荷的预测曲线,加上系统参数,建立一个混合整数线性规划或非线性规划,目标是最小化运行成本,约束覆盖功率平衡、机组出力上下限、爬坡约束、储能SOC约束、与主网的交互功率限制,最后丢给Cplex或Gurobi一次求解。这个方案的优点是模型简单、求解快,但它默认“预测值就是真实值”,一旦第二天光伏少发、负荷多涨,原计划里的功率平衡就被打破,调度员只能临时追加调节,而追加调节往往意味着更高的成本,极端情况下甚至需要切负荷。
很多人觉得,那我把预测误差留个备用容量不就行了。但备用容量留多少是拍脑袋定的,留少了扛不住大偏差,留多了又在绝大多数日子里白白浪费经济性。随机规划倒是能把预测误差的概率分布考虑进去,但实际工程里光伏和负荷的分布很难精确获得,假设错了模型就失真了。鲁棒优化走的是另一条路:不给概率,只给一个包含所有可能情况的“不确定集合”,然后在这个集合里找最坏情况下的最优方案。换句话说,鲁棒方法牺牲一点正常天气下的经济性,换来的是“无论天气怎么变,系统都能安全运行”这个承诺。
另外提一句,这套两阶段鲁棒加关键场景辨别的思路并不只在微电网里能用。凡是“日前计划加日内修正”的调度问题都适用,园区综合能源、楼宇能量管理、数据中心用能优化,甚至电动车有序充电,本质上都是同一个框架,换一下对象和约束而已。
1.2 两阶段鲁棒优化的“先决策、后调整”架构
两阶段鲁棒优化的名字听起来唬人,拆开看其实很符合调度员的直觉。第一阶段是“今天为明天排计划”,需要提前确定哪些决策是不能等到实际出力出来之后再改的,典型的比如机组启停、与主网签订的购售电协议量、储能的日前调度策略。第二阶段是“明天到来、不确定性暴露之后”,光伏和负荷的实际值都知道了,系统在已有的第一阶段决策基础上做经济最优的实时调整,比如储能多充一点还是多放一点、实际购电是增是减、是否要弃光或切负荷。
数学上,这个决策过程被写成min-max-min结构:
min_x 第一阶段成本 c^T x + max_{u∈U} min_y 第二阶段成本 d^T y
最外层min是“制定第一阶段计划”,中间max是“自然界跟你作对,挑一个最恶劣的场景”,内层min是“在这个最恶劣场景下做最经济的调整”。这种嵌套结构正好对应了调度员在日前和日内两个时间尺度上的决策逻辑,所以工程上接受度很高。
注意这里面有个容易误解的点:鲁棒优化不是把所有时段的光伏和负荷都按最坏值算,那样模型会非常保守,成本高到没法用。中间那层max是在不确定集合U里挑“组合起来最恶劣的场景”,而这个最恶劣场景往往只出现在某些特定时段取极端值,其他时段还是正常值。这正是后面关键场景辨别算法要解决的问题。
1.3 不确定集合与鲁棒预算:给不确定性画个圈
不确定集合的构造是整个鲁棒优化的地基。最常见的是盒式集合加预算约束。拿光伏举例,可以设光伏实际出力在预测值上下20%的范围内波动,即:
P_pv,t = P_pv,forecast,t + ΔP_t * ξ_t, ξ_t ∈ [-1, 1]
其中ΔP_t是时段t的预测偏差上限,比如取预测值的20%。但如果不加限制,所有时段的ξ_t同时取边界值,鲁棒优化会认为太阳整天都处于最差状态,这显然不合理。于是再加一个预算约束:
Σ |ξ_t| ≤ Γ
Γ就是鲁棒预算。它限制了“偏离预测值的总程度”,Γ越大,允许的偏离越厉害,模型越保守;Γ=0时模型退化为完全相信预测的确定性优化。
实际操作时,我建议不要一上来就拍脑袋选Γ。先跑一组Γ从0到T(时段数)的灵敏度分析,观察总成本怎么变化。正常情况下成本会随Γ先快速上升然后趋于平缓,转折点附近往往就是工程上“性价比”最高的鲁棒水平。这个经验我用过很多次,比按文献里的经验值直接抄要靠谱得多。
2. 关键场景辨别算法:怎么快速抓到“最恶劣场景”
2.1 为什么不能穷举所有极端场景
现在来到这篇文章的核心算法部分。两阶段鲁棒模型写出来容易,真正难的是求解。问题卡在中层的max上:不确定集合U如果连续,要从无穷多个场景里找最恶劣的一个;如果把每个时段的光伏和负荷简单分成“高、中、低”三档,一天24个时段,组合数量是3的48次方,这种天文数字即使再快的计算机也没法穷举。
但线性规划领域有一个经典结论:如果整个模型是线性的,最优点一定落在约束构成的可行域的极点附近。也就是说,最恶劣场景大概率出现在不确定集合的“角点”上,即某些时段的光伏或负荷刚好取到偏差上限或下限。关键的难点在于:一天24个时段,每一个时段的光伏、负荷两个不确定变量都有上下两个极值,组合起来有2的48次方量级的极点,仍然多到无法枚举。
所以处理思路要反过来:不用枚举全部极端场景,而是让算法在迭代中“主动辨别”哪些场景真正值得关注。谁值得关注?答案很直观:对当前的第一阶段决策杀伤力最大的那个场景。找到它、把它拿进调度模型里,再去检查有没有其他更恶劣的场景,循环往复,直到找不出更能让系统痛苦的场景为止。这个“找最恶劣场景”的过程,就是关键场景辨别算法要做的事。
2.2 关键场景辨别的核心思想与算法流程
在两阶段鲁棒优化领域,求解嵌套min-max-min问题最主流的框架是C&CG(列与约束生成,Column-and-Constraint Generation)。它的核心思想是把原问题拆成主问题和子问题,通过迭代互相喂数据。主问题是一个包含部分已知关键场景的优化模型,子问题是在固定第一阶段决策后去辨别新的最恶劣场景。
完整流程可以概括成四步:
- 初始化:给出一个初始的关键场景集合,这个集合可以来自确定性预测场景,也可以来自历史典型恶劣日,甚至可以只放一个场景。
- 求解主问题:在当前场景集合下,同时优化第一阶段决策和所有场景对应的第二阶段成本,得到一个“候选决策”和下界。
- 固定第一阶段决策,求解子问题:子问题就是在不确定集合里寻找最恶劣场景,以及该场景下的最小调整成本。这个场景和成本一起构成了对当前决策的“压力测试”。
- 收敛判断与迭代:把上一步得到的最恶劣场景加入主问题的场景集合,重新求解主问题。当主问题的下界和子问题上界之间的间隙小于设定容差时,算法收敛。
每一步产生的“最恶劣场景”,就是题目里说的关键场景。每迭代一次,主问题里就多一个关键场景和对应的约束,优化结果会越来越安全,直到哪怕加入再多极端场景也不再显著改变结果时,说明当前计划已经在全景范围内站得住脚了。
2.3 与C&CG配合:每次迭代只加最关键的一个约束
C&CG和Benders分解的思路有相似之处,但关键区别在于:Benders分解是在主问题里加割平面,而C&CG是加新的变量和约束。具体到两阶段鲁棒问题,每识别出一个关键场景,主问题就会新增一组与该场景对应的第二阶段变量和约束。正因为如此,C&CG在小规模问题上通常比Benders收敛更快。
这也正好体现了“关键场景辨别”的价值。如果不用C&CG,常规做法是把所有可能的极端场景一次性全部塞进主问题,场景一多就变成一个大得没法解的混合整数规划。C&CG不一样,它每次只加一个“当前最需要警惕的场景”,主问题规模是缓慢增长的,而场景又是真实最恶劣的,所以通常迭代十次上下就能收敛,求解速度快,内存占用也可控。
我实际跑这类微网算例的感受是:用YALMIP加Cplex求解,24时段、光伏加负荷两个不确定源,一般迭代8到20次就能把相对间隙压到1%以内,单次主问题求解时间在几秒到几十秒之间,完全能满足科研和工程验证的需要。
2.4 一个直观的小例子:用2时段系统理解场景辨别
为了把算法说透,我举个极简单的小例子。假设一个只有2个时段的微网,光伏偏差在每时段只有“高、低”两个状态,高代表光伏少发,低代表正常甚至多发。这两个时段排列组合总共4个场景:
- 场景A:时段1高,时段2高,整体最恶劣
- 场景B:时段1高,时段2低,影响较小
- 场景C:时段1低,时段2高,影响较小
- 场景D:时段1低,时段2低,最温和
确定性调度相当于只看了场景D,完全没考虑光伏偏差。而两阶段鲁棒的思路是:先以场景D做计划得到第一阶段决策,然后固定决策去检查4个场景,发现场景A造成的失负荷和调整成本最高,场景A就是“关键场景”。把它加入主问题重新优化,得到新的第一阶段决策后,再回头检查所有场景,发现场景A仍然是最大威胁,而且成本已经不再上升,于是收敛。最终计划就是“在场景A下也不至于出大问题”的方案。
用这个简单例子能看出,关键场景辨别本质上是一个“寻找系统软肋”的过程。系统的软肋可能随第一阶段决策的变化而转移,所以必须迭代求解。实际24时段系统只是把“枚举所有组合”换成了“用数学规划高效搜出最恶劣组合”,思想完全一致。
3. 两阶段鲁棒微网模型的数学建模与Matlab搭建
3.1 系统结构与变量定义
下面进入建模部分。这里以一个典型的并网友好型微电网为例,包含光伏、风电、蓄电池储能、微型燃气轮机以及与大电网的联络线交换功率。对应用2017年电工杯微电网调度赛题背景的朋友来说,这个配置很有代表性,很多算例都是从那里演化来的。
模型涉及的变量可以按两阶段划分:
第一阶段决策(日前确定):
- 微燃机启停状态和日前计划出力
- 与主网的购售电计划功率
- 储能日前充放电计划(也可放在第二阶段,根据建模偏好)
第二阶段决策(不确定性实现后调整):
- 实际光伏、风电出力水平下的储能再调整量
- 实际购售电功率修正量
- 弃风弃光量和切负荷量
第二阶段变量带着场景索引出现,也就是说每个关键场景都对应一组自己的第二阶段变量。这是C&CG主问题里模型规模增长的主要来源。
3.2 目标函数与分时电价建模
目标函数是全天运行总成本,包含以下几项:
- 向主网购电的费用,减去向主网售电的收益,购售电价按分时电价区分峰平谷
- 微型燃气轮机的燃料成本,一般用二次函数表示,优化时需要分段线性化
- 储能充放电带来的折旧损耗成本
- 弃风弃光惩罚和切负荷惩罚
写成数学形式:
min Σ_t [ c_buy(t)·P_buy,t - c_sell(t)·P_sell,t + C_MT(P_MT,t) + C_ESS(P_ch,t, P_dis,t) + M·(P_curtail,t + P_shed,t) ]
其中分时电价是微网调度里的核心输入。参考国内峰平谷电价的典型设置,可以按下面的表格配置:
| 时段类型 | 时段范围 | 购电价(元/kWh) | 售电价(元/kWh) |
|---|---|---|---|
| 峰时 | 10:00-15:00、18:00-21:00 | 1.20 | 1.00 |
| 平时 | 07:00-10:00、15:00-18:00、21:00-23:00 | 0.80 | 0.50 |
| 谷时 | 23:00-次日07:00 | 0.40 | 0.20 |
售电价低于购电价,避免系统通过低买高卖套利,这是并网微网模型里的常见设置。分段线性化方面,如果用YALMIP建模,可以用binvar辅助变量加额外约束,或者直接用implies、ismember这类工具箱函数简化,但要注意这些函数会增加约束数量,求解速度会变慢。更快的做法是手动写大M分段线性化,我后面避坑部分会细说。
3.3 关键约束建模:功率平衡、储能SOC、鲁棒预算
约束方面,最重要的五类不能漏:
功率平衡约束(每个时段、每个场景):
P_pv + P_wind + P_MT + P_buy + P_dis = P_load + P_ch + P_sell + P_shed
右边是负荷加储能充电加售电,左边是各电源出力加购电。切负荷量P_shed是松弛变量,正常情况下应当为0,它的存在是为了保证极端场景下模型仍然有可行解。
储能SOC约束:
SOC(t+1) = SOC(t) + η_ch·P_ch(t)·Δt/E_cap - P_dis(t)·Δt/(η_dis·E_cap)
同时要加SOC上下限约束,以及充放电功率上下限约束。如果允许储能同时充放电,模型会跑出“边充边放”的数值假象,解决办法是加二值变量互斥约束,或者干脆在目标函数里给充放电都加上成本,让同时充放电不经济,从而自然避免。
微燃机约束:出力上下限、爬坡约束、最小启停时间约束(如果考虑机组组合)。最小启停时间在现代调度模型里很常见,但会让模型从LP变成MILP,求解时间明显增加。如果只是验证算法,可以先不算启停时间,把重点放在鲁棒迭代上。
与主网交互约束:购售电功率不能超过联络线容量,且购售电状态互斥,也往往需要0-1变量。
不确定集合预算约束:光伏和负荷的实际值由预测值加偏差构成,偏差项的绝对值之和受鲁棒预算Γ限制。这是关键场景辨别算法搜索范围的核心约束。
3.4 主问题与子问题的数学形式及转化
按C&CG框架,两阶段鲁棒模型可以写成标准形式:
min_x c^T x + max_{u∈U} min_{y∈Ω(x,u)} d^T y
约束形式为A x ≤ b,以及对于给定场景u,第二阶段可行域满足B y ≤ g - C x - D u。
主问题MP是包含已识别关键场景集合K的优化问题:
min_x η s.t. A x ≤ b η ≥ c^T x + d^T y_k,对每个k∈K B y_k ≤ g - C x - D u_k,对每个k∈K
其中η是辅助变量,代表“最坏场景下的总成本”。每次迭代增加一个场景,就增加一组第二阶段的变量y_k和对应约束。
子问题SP是固定x后求解最恶劣场景:
SP(x*) = max_{u∈U} min_y d^T y s.t. B y ≤ g - C x* - D u
子问题本身是max-min结构,内层min是线性规划。处理标准做法是对内层LP做对偶变换,把min换成max,得到一个单层max问题。对偶后目标函数中出现u和对偶变量λ相乘的双线性项,需要用大M法把双线性项线性化,将子问题转化为一个MILP,交给Cplex或Gurobi求解。这正是前面说的“关键场景辨别”模块:子问题的最优解u*,就是在当前第一阶段决策下能被辨别出的最恶劣场景;如果子问题最优值为有限,说明当前决策扛得住,如果值很大,这个场景就会被加入主问题继续迭代。
4. Matlab实现:主程序流程、求解器配置与结果解读
4.1 整体程序框架与数据准备
Matlab实现这个模型,我习惯用YALMIP建模,求解器用Cplex或Gurobi,两个都支持MILP,Gurobi在个别算例上更快一些。数据准备阶段需要整理如下内容:
- 24小时光伏预测出力曲线、负荷预测曲线,以及对应的波动偏差上限
- 微燃机参数:额定容量、爬坡率、燃料成本系数、启停成本
- 储能参数:容量、最大充放电功率、充放电效率、SOC上下限、初始SOC
- 分时电价数据:峰平时段划分和价格
- 鲁棒预算Γ的取值
- C&CG收敛容差和最大迭代次数
一个比较容易被忽略的细节是数据单位。功率用kW、时间用h、能量用kWh、电价用元/kWh,这样储能SOC约束里的Δt就是1小时,计算最干净。如果数据源给的是MW,一定要统一换算,不然量纲错乱会导致完全无法收敛。
4.2 主程序伪代码与YALMIP求解细节
C&CG主循环的Matlab伪代码如下:
% 初始化 LB = -1e6; UB = 1e6; k = 0; scenarios = {}; % 关键场景集合 % scenarios{1} = nominal_scenario; % 可选:先加入确定性预测场景 tol = 1e-3; Kmax = 50; while (UB - LB) / max(1, abs(UB)) > tol && k < Kmax % 1. 求解主问题 [x_opt, lb] = solve_MP(scenarios); LB = max(LB, lb); % 2. 固定x_opt,求解子问题辨别关键场景 [u_hat, sp_obj] = solve_SP(x_opt); % 3. 计算总成本上界 ub_temp = obj_first_stage(x_opt) + sp_obj; if ub_temp < UB UB = ub_temp; x_best = x_opt; end % 4. 将关键场景加入主问题 scenarios{end+1} = u_hat; k = k + 1; endsolve_MP内部用YALMIP建模,大概长这样:
function [x_opt, obj] = solve_MP(scenarios) yalmip('clear'); x = binvar(N_MT, T, 'full'); % 机组状态,如果是启停问题 p_mt = sdpvar(N_MT, T, 'full'); p_buy = sdpvar(1, T, 'full'); p_sell = sdpvar(1, T, 'full'); eta = sdpvar(1, 1); % ... 其他变量 Constraints = []; % 第一阶段约束,功率平衡、机组出力等 % 小技巧:主问题的功率平衡中,光伏和负荷要用预测值;极端场景偏差通过新增的y变量来补偿 for k = 1:length(scenarios) % 每个场景对应一组第二阶段变量 y_k p_ch_k = sdpvar(1, T, 'full'); p_dis_k = sdpvar(1, T, 'full'); p_shed_k = sdpvar(1, T, 'full'); % 加入该场景下的功率平衡、储能SOC约束 % 加入成本不等式:eta >= c'*x + d'*y_k end Objective = eta; % 最小化最坏场景总成本 ops = sdpsettings('solver', 'cplex', 'verbose', 0, 'mip.tolerances.mipgap', 1e-4); optimize(Constraints, Objective, ops); x_opt = value(x); obj = value(eta); endsolve_SP内部是把子问题转成MILP后直接求解,返回最恶劣场景u_hat和子问题目标值sp_obj。这里不再展开全部代码,但有一个关键提醒:子问题里的大M系数不能统一设得太小,也不能太大。太小会把最优解截断,太大则导致数值病态,Cplex经常报数值警告。我的经验是M根据变量实际量纲设置,比如功率变量上限是500kW,那M取500到1000就够,不要为了省事全局设一个1e6。
4.3 求解器配置、收敛判据与常见调参
收敛判据是整个算法能否快速结束的关键。我见过很多人直接用绝对间隙UB - LB < 1e-4,结果在24时段问题上迭代几十次都停不下来。改用相对间隙(UB - LB)/max(1, abs(UB)) < 1e-3之后,通常十几次就能收敛。原因很简单:优化问题规模越大,目标函数绝对数值越大,绝对间隙的标准相当于要求小数点后好几位完全一致,现实中完全没必要。
还有几个调参经验可以共享:
- 子问题如果难以收敛,可以考虑限制求解时间,设一个
'cplex.timelimit',比如120秒,拿一个次优解作为场景加入主问题。因为即使场景不是绝对最恶劣,只要它能让主问题产生新的约束,算法依然能前进,只是迭代次数可能多一点。 - 主问题每个循环都会膨胀,变量名不建议直接覆盖,会导致内存消耗越来越大。用
yalmip('clear')或者把每次循环的模型放到子函数里,变量自动清理。 - Gurobi求解MILP时默认线程数可能不高,可以设置
'gurobi.Threads'为4或者8,算例规模大时提速明显。
4.4 仿真结果怎么看:调度计划、SOC曲线、收敛曲线
算法跑完后,要输出几类结果来验证正确性:
第一是日前调度计划曲线,也就是第一阶段决策里的微燃机出力、购售电功率、储能充放电计划。重点看储能是否在谷时充电、峰时放电,购电是否避开峰时高价,这些基本规律能验证模型逻辑是否正确。
第二是SOC变化曲线。正常结果中SOC应该始终维持在上下限之间,且曲线平滑,不会有频繁的剧烈波动。如果SOC在某个时段反复来回反弹,大概率是储能互斥约束没做好,或者充放电成本设置有问题。
第三是C&CG收敛曲线。把每次迭代的LB和UB画出来,正常情况是LB逐步抬升、UB逐步下降,两条线逐渐靠拢。如果看到某一方长期不动甚至出现UB小于LB的情况,说明子问题或主问题有一个算错了,这是检查代码逻辑最直接的信号。
第四是不同鲁棒预算Γ下的总成本对比。把Γ设成0、5、10、15、24分别跑一遍,能直观看到成本随鲁棒性增强的变化趋势,这也是论文里最常用的一张敏感性分析图。
5. 常见问题与避坑实战
5.1 子问题对偶后的双线性项怎么处理
这是新手最容易卡住的地方。子问题对偶之后,目标函数会变成类似于Σ (a_λ + b_λ·u)·λ的形式,也就是不确定变量u和对偶变量λ相乘,这是个双线性项,Cplex不能直接处理。最常见的做法是引入一个大M,把u·λ拆成新的辅助变量w,再加约束把w限制为:
- w ≤ M·z
- w ≥ -M·z
- w ≤ λ + M·(1-z)
- w ≥ λ - M·(1-z)
其中z是0-1变量,用来表示u取上边界还是下边界。这套线性化几乎在所有两阶段鲁棒优化的论文里都会出现,属于必须掌握的“基本功”。
操作时注意三点:一是u的每一个分量都要单独做线性化,不能把整个向量打包处理;二是M的取值最好贴合u和λ的实际量级,否则数值稳定性差;三是做完线性化后整个子问题变成MILP,求解时间会比LP慢一个数量级,但在24时段的小规模算例里完全可接受。
5.2 C&CG不收敛或收敛很慢怎么办
不收敛的场景我遇到得不少,总结下来原因主要有三类:第一类是容差设置不合理,建议改用相对间隙判断;第二类是子问题返回的场景质量太差,比如求解时间太短导致每次拿到的场景都是次优的,可以通过延长子问题求解时间或给子问题加一个“必须比现有场景差到一定程度才接受”的判断来改善;第三类是第一阶段决策变量和第二阶段变量耦合过强,导致主问题每次调整幅度都很大,UB和LB长期对不上。
针对第三类情况,一个非常有效的技巧是给主问题额外加一个“确定性预测场景”作为初始场景,也就是scenarios集合里先放入Γ=0的场景。这样主问题一开始就有了一个真实可执行的基准解,UB起始值不会太空,收敛速度肉眼可见地提升。
5.3 储能同时充放电、SOC漂移等工程细节
储能建模里最典型的坑是“同时充放电”。如果模型对充放电功率只给了上下限,没有加互斥约束,求解器可能给出同时充电和放电的解,两者在功率平衡中抵消,但目标函数里却白算了一笔损耗成本,严重误导结果。解决办法有两种:一是加两个0-1变量做互斥约束;二是在目标函数里同时给充放电设置损耗成本,使得同时充放电不经济。第二种方法省变量、求解快,但需要谨慎设置成本系数,不能让成本高到影响正常充放电策略。
SOC漂移是另一个容易遇到的问题。如果模型没有设置调度周期末SOC回到初始值,长期运行下来储能电池可能在每个调度日内逐步亏空或充满。要不要加SOC_T = SOC_0这个约束,取决于实际应用场景。孤立微网通常建议加,保证长期可循环运行;并网型微网如果对储能连续运行要求不高,可以不加,把灵活性留给调度模型。
5.4 数值病态与求解器报错处理
跑YALMIP加Cplex时常碰到数值问题警告,比如“Problem is badly scaled”。原因绝大多数是变量量纲悬殊。光伏出力几百kW、价格零点几元,如果目标函数里没有做归一化,矩阵里既有1000又有0.3,Cplex的数值容差很难同时处理。我给的建议是功率量纲统一为kW、价格统一为元/kWh,目标函数系数都尽量控制在1到1000的数量级之内。如果怎么调都还有数值警告,可以考虑把目标函数整体除以1000再求解,最后再乘以1000还原,很多情况下能压下警告。
还有一种情况是子问题有时无界。出现无界说明第二阶段可行域在某些场景下是开放的,比如切负荷量没有设置上限,或者储能SOC没有加下限。处理办法是给所有松弛变量设一个合理上限,切负荷不超过负荷总量,弃风弃光不超过对应电源出力,这样数学模型才真正对应物理系统的边界。
6. 写在后面:我的实操体会
这套“两阶段鲁棒加关键场景辨别”的模型,我从最初照着论文抄代码到真正跑通自己的微网算例,中间踩过的坑比想象中多得多。最大的体会是,鲁棒优化不是一个“一次求解、一劳永逸”的模型,它更像一套防御机制,你必须先想清楚自己要防什么:是防光伏波动,还是防负荷冲击,还是两者一起防。不确定集合、鲁棒预算、惩罚系数,都是围绕“防守目标”来设的,目标没想清楚,参数调得再精细也白搭。
另外一个很实际的建议是,做这类项目时不要一上来就追求最复杂的模型。把两阶段问题拆开,先跑通不含不确定性的确定性模型,再跑通不含C&CG的静态鲁棒模型,最后再加关键场景辨别迭代。每一步都对照结果检查一遍,比一次写完再回头调试要省太多时间。Matlab加YALMIP的好处是建模直观,调试方便,三四天时间就能从一个空文件到一个能跑出合理调度结果的完整程序。后面如果你想把工作往实际工程推进,可以把确定性参数扩展成多场景随机数据,甚至加进日前实时联动滚动优化,框架都不用大改。