搞微电网的人,最怕的不是设备坏,而是预测不准。我做过一个园区微电网项目,光伏装机5MW,夏天午后预测出力4.2MW,实际只有3.1MW,这一下子1.1MW的差额,让按日前点预测排好的经济调度计划瞬间失效——燃气轮机顶到上限、联络线越限,最后被调度中心罚了一笔。这件事让我彻底想明白一个道理:微电网经济调度本质上是一场“先拍板、后见分晓”的博弈,你不可能等不确定性消失再做决策,而两阶段鲁棒优化,就是专门对付这种场景的最优调度方案设计思路。
这篇内容适合正在做微电网能量管理、储能调度,以及被电工杯这类竞赛题和毕业设计折磨的电气系学生。我会把两阶段鲁棒优化的原理、建模、求解决策和MATLAB实现整个链路拆开讲,最后聊到它和滚动时域控制、模型预测控制怎么结合起来用。全是这些年做实际项目踩坑之后沉淀下来的东西,不是教材里那种只给公式不给经验的路数。
先从一句话说起:预测越准,确定性优化越好用;但只要预测误差存在,确定性最优解往往就是最脆弱的解。
1. 为什么微电网调度不能只信“点预测”:一次实际调度失效的复盘
1.1 确定性优化模型长什么样,问题出在哪
大多数人在接触鲁棒优化之前,写的都是确定性优化模型,形式大概是这样的:
[ \min \sum_{t=1}^{24} \left( c_{GT}P_{GT,t} + c_{buy,t}P_{buy,t} - c_{sell,t}P_{sell,t} \right) ]
约束是功率平衡、储能SOC递推、机组出力上下限、联络线功率限幅等。建模过程很顺手,把光伏预测曲线和负荷预测曲线当真实值代进去,求解器输出一个“最优计划”。问题在于:这个计划只在预测场景下最优,而且往往在偏差出现时直接不可行。
我给一个自己遇到过、也经常拿来给学生讲的算例。某微电网14:00的负荷预测是5.0MW,光伏预测出力3.0MW,日前计划里燃气轮机出0.5MW、储能放电0.5MW、从联络线购电1.0MW,刚好满足平衡。结果到了14:10,实际负荷涨到6.0MW,光伏骤降到2.0MW。再看资源:燃气轮机0.5MW已经接近上限,储能0.5MW已经放完,联络线1.0MW的额度早被日前合同锁定。功率缺口2.0MW,没有任何调节手段,只能甩负荷。
这就是确定性模型的死穴:它把每一个预测值都当作“准确值”来安排其他资源,于是所有可调资源都被填满,系统没有任何冗余应对偏差。你做的计划越是“严格最优”,在真实场景里往往越是“一触即溃”。
1.2 不确定性的三个主要来源
搞微电网调度,面对的偏差主要有三个来源。
第一是光伏出力。云层遮挡、辐照度突变、组件温度变化都会造成出力偏差。我统计过某园区夏天的15分钟级光伏数据,预测误差的标准差大约在装机容量的15%左右,极端天气下偏差到30%也不奇怪。更麻烦的是,光伏预测误差往往不是平稳的,而是午后强、早晚弱,并且相邻时段有相关性。
第二是负荷波动。工业负荷和商业负荷虽然有一定规律,但空调、充电桩、大功率设备启停都会带来明显的随机偏差。尤其夏季高温天,空调负荷可能让预测曲线整体抬升5%到10%。
第三是电价。如果微网参与现货市场或峰谷分时电价,购电成本本身就存在不确定性。这个更偏向市场风险,但同样会影响调度方案的经济性。
不管来源是哪个,结论都一样:你拿到的不是确定值,而是一个带偏差的区间。问题是,调度方案必须在这个区间内的所有情况下都满足功率平衡和运行约束。
1.3 从“事后补偿”到“事前免疫”的范式转变
传统微电网能量管理系统怎么应对偏差?主要靠AGC/AVC这类自动发电控制和实时备用容量。但备用容量是有限的,爬坡速率也是有限的。真遇到1.1MW的突然缺口,AGC未必拉得回来。事后补偿的问题在于:你是在问题已经发生之后才调动资源,留给你的调节时间和调节空间都很小。
鲁棒优化的思路完全反过来。它是在方案生成阶段,就要求计划对不确定集合里的所有场景都可行。也就是说,不等偏差出现再去弥补,而是从源头上让计划“扛得住”各种偏差。这像设计一座桥,不是等汛期来了再堆沙袋,而是按百年一遇洪水来设计桥墩。
当然,“事前免疫”不是白来的。免疫的成本就是方案的保守性——最坏情况下依然可行的计划,通常比最坏场景发生时的期望最优计划都要贵一些。所以关键问题变成了:怎么设计一个工具,让保守性可控、成本增加有限,同时还能保证系统安全。这就是两阶段鲁棒优化的价值所在。
2. 两阶段鲁棒优化:先做保守决策,再做最优调整
2.1 两阶段结构拆解
先给出两阶段鲁棒优化的标准形式,后面的建模和求解都围绕它展开:
[ \min_{x} \left( c_1^T x + \max_{u\in\mathcal{U}} \min_{y\in\Omega(x,u)} c_2^T y \right) ]
其中 (x) 是第一阶段决策变量,必须在不确定性实现之前确定;(u) 是不确定参数,属于一个事先设定的不确定集合 (\mathcal{U});(y) 是第二阶段决策变量,可以在 (u) 的实际值暴露之后做调整,而且调整要满足可行域 (\Omega(x,u))。
放在微电网场景里:
- 第一阶段决策:燃气轮机启停状态、购售电合同电量、储能日前基准计划。这些决策要么物理上不能频繁更改(机组启停需要提前通知和热启动准备),要么有市场申报时限(日前市场要求在某个时间点之前提交第二天每个小时的购电计划)。
- 第二阶段决策:当光伏和负荷的实际值暴露后,通过调整燃气轮机出力增量、储能充放电功率修正、弃光、切负荷等手段维持功率平衡。这些是“可以等一等再做的决策”。
用生活中的例子理解:出差前先定往返机票,不可退改,这是第一阶段决策;到了当地根据天气决定打车还是坐地铁,这是第二阶段决策。机票只能在不知道天气的时候买,但交通方式可以等落地后再定。
2.2 与单阶段鲁棒、随机规划的对比
表格能直观说明区别:
| 方法 | 不确定建模方式 | 决策机制 | 优点 | 缺点 |
|---|---|---|---|---|
| 确定性优化 | 忽略不确定,只用一个预测场景 | 单阶段 | 模型小、求解快 | 对偏差敏感,易越限 |
| 随机规划 | 假设概率分布,生成若干场景 | 两阶段或多阶段 | 期望意义下经济性最优 | 分布假设难验证,场景多时计算量大 |
| 单阶段鲁棒 | 不确定集 | 所有决策在实现前一次性敲定 | 强鲁棒,求解相对简单 | 过度保守,经济性差 |
| 两阶段鲁棒 | 不确定集 | 先定第一阶段,再等实现后调整第二阶段 | 保守度适中,物理意义清晰 | 模型复杂度高,求解有门槛 |
随机规划和两阶段鲁棒长得有点像,都是“先决策、后调整”,但核心区别在于:随机规划需要知道不确定性的概率分布,求解的是期望成本最优;两阶段鲁棒只需要知道不确定性的取值范围,保证的是最坏情况下的可行性。
在工程实际中,准确的分布往往很难拿到,尤其是光伏出力的分布在不同季节、不同天气下差异很大。相对而言,从历史数据里统计一个误差上下界要容易得多。这也是鲁棒优化在微电网调度里有其适用性的原因。
2.3 保守度不是越大越好
很多人第一次接触鲁棒优化时会陷入一个误区:不确定性模型越保守越安全?实际不是。两阶段鲁棒优化的“鲁棒”主要体现在第一阶段决策,第二阶段本身还针对最坏场景做调整。如果你把不确定集设得太大(比如认为所有时段光伏和负荷同时取极端偏差),得到的方案会非常贵——燃气轮机多开、储能多预留、购电合同多签,结果就是日常运行成本被严重抬高。
工程师真正要做的,是调节不确定集合的形状,把“保守度”控制在一个合理位置。后面第三部分会详细讲不确定集怎么建,这里先记住一个原则:不确定集应该描述“现实中可能发生的最坏情况”,而不是“数学上可构造的最坏情况”。
3. 不确定集合怎么建:决定你保守程度的“尺子”
3.1 盒式不确定集:简单但容易过度保守
盒式不确定集是最简单的一类,形式为:
[ \mathcal{U}_{box} = \left{ u_t : \hat{u}_t - \Delta u_t \le u_t \le \hat{u}_t + \Delta u_t \right} ]
其中 (\hat{u}_t) 是预测值,(\Delta u_t) 是预测误差的上限。它表达的意思很直观:每个时段的不确定参数都在预测值加减一个最大误差的范围内。
问题在于,它隐含了一个很强的假设:所有时段的最坏偏差会同时发生。拿微电网来说,就是假设一天24个时段的光伏出力同时达到预测下界、负荷同时达到预测上界。这在物理上几乎不可能——云层不可能从早上到晚上一直遮着光伏板,负荷也不可能连续24小时都是最极端值。
用盒式集做鲁棒优化的结果就是方案极其保守:燃气轮机全天高负荷运行、储能时刻准备放电、购电合同签得很大,运行成本高到没法接受。除非系统非常小、对安全要求极高,否则不建议直接上盒式集。
3.2 预算不确定集:用“预算”控制保守度
工程里更常用的是预算不确定集,也叫Budget Uncertainty Set,形式为:
[ \mathcal{U} = \left{ u_t = \hat{u}t + \Delta u_t z_t, \quad z_t \in [-1, 1], \quad \sum{t=1}^{24} |z_t| \le \Gamma \right} ]
相比盒式集,多了一个关键约束 (\sum |z_t| \le \Gamma)。(z_t) 是每个时段的归—化误差,范围在 ([-1,1]) 之间;(\Gamma) 是预算参数,限制了所有时段误差绝对值之和的上限。
这个约束的直观含义是:允许某些时段出现极端偏差,但不允许所有时段同时出现极端偏差。(\Gamma) 可以理解为“你愿意为多少个时段的极端偏差买单”。(\Gamma=0) 时退化为确定性模型;(\Gamma=24) 时等价于盒式集。实际工程里,(\Gamma) 取8到12比较常见,意思是允许大约三分之一到一半的时段出现满偏,其余时段误差较小。
这里有个经验值可供参考:光伏预测误差服从近似正态分布时,取历史数据的90%分位数对应的累计偏差作为 (\Gamma),既能覆盖绝大多数恶劣场景,又不至于过度保守。具体做法是对历史预测误差时间序列求 (|z_t|) 的累计分布,找出90%分位数对应的累计偏差值。
3.3 光伏与负荷的时序相关性不要忽视
预算不确定集最大的简化在于:它假设每个时段的误差是独立同分布的,只通过累计预算来约束整体。实际上光伏出力的预测误差有很强的正自相关——如果10:00预测偏大,11:00大概率也偏大,因为云层遮挡的过程是持续的。
处理这种相关性,理论上可以用椭圆不确定集或基于协方差矩阵的主成分分析来构造更精细的集合。但我要说的是:建模复杂度会明显上升,求解难度也会上去。我的建议是“先用预算集跑通整套流程,再用历史典型场景做校验”。如果预算集下得到的方案在真实极端天气场景里都能过关,就没必要为了理论上的精确去上椭圆集。
在校验时,可以准备三到五个历史极端日作为“影子场景”:夏季强对流天气日、冬季阴雨天、负荷尖峰日、光伏大发日。把鲁棒优化得到的日前计划在这几个场景里做可行性仿真,如果都能满足功率平衡和安全约束,就说明不确定集设置合理。
4. 目标函数与约束的数学化:从物理问题到优化模型
4.1 成本构成与目标函数
微电网经济调度的成本不是一项,而是好几项叠加。两阶段鲁棒优化的目标函数写成:
[ \min_{x} \left( C_{startup} + C_{fuel} + C_{grid} + \max_{u\in\mathcal{U}} \min_{y} C_{adjust} \right) ]
第一阶段的成本包括:
- 燃气轮机启停成本:(C_{startup} = \sum_{t} S_{GT} \cdot v_{t})
- 燃料成本:可以简化成出力的线性或二次函数 (C_{fuel} = \sum_t (a P_{GT,t} + b))
- 购售电成本:(\sum_t \left( c_{buy,t} P_{buy,t} - c_{sell,t} P_{sell,t} \right))
第二阶段的成本包括:
- 机组出力调整成本(上调/下调,通常价格不对称,上调更贵)
- 储能充放电调整带来的寿命损耗成本
- 弃光惩罚成本
- 切负荷惩罚成本
注意,第二阶段的成本被包在 (\max \min) 里面,含义是:在不确定集合中找最恶劣的场景 (u),然后在这个场景下做成本最小的调整。(\max) 决定了第二阶段的成本是“最坏情况下的最低成本”,而不是某个固定场景下的成本。
4.2 储能系统建模:SOC递推与充放电互斥
储能是微电网里最重要的柔性资源,建模细节直接决定优化结果靠不靠谱。核心是SOC递推方程:
[ SOC_{t+1} = SOC_t + \eta_c P_{ch,t} \Delta t - \frac{1}{\eta_d} P_{dis,t} \Delta t ]
(\eta_c) 和 (\eta_d) 分别是充放电效率,实际工程中取0.90到0.95比较合适。除此之外还要写:
[ 0 \le P_{ch,t} \le P_{ch}^{max} \cdot \alpha_t ] [ 0 \le P_{dis,t} \le P_{dis}^{max} \cdot (1 - \alpha_t) ] [ SOC_{min} \le SOC_t \le SOC_{max} ]
其中 (\alpha_t) 是0-1变量,表示充放电互斥。这个互斥约束很容易被初学者忽略,结果是求解器为了凑目标函数让电池一边充电一边放电,方案看似完美实际物理上不可行。
还有一个更隐蔽的坑:日循环约束。很多系统要求一天结束时SOC恢复到初始值 (SOC_T = SOC_0),否则求解器会想办法耗尽电池电量来赚取售电收益,第二天的计划就从“有电可用”变成“无电可用”了。
4.3 功率平衡与电网交互约束
功率平衡是所有微电网模型的核心约束,每一时段都要满足:
[ P_{GT,t} + P_{PV,t} + P_{dis,t} - P_{ch,t} + P_{buy,t} - P_{sell,t} = P_{L,t} ]
其中 (P_{PV,t}) 和 (P_{L,t}) 是带有不确定性的参数。在两阶段鲁棒模型里,平衡方程需要区分第一阶段和第二阶段。第一阶段的平衡由计划值决定;第二阶段的调整变量,比如燃气轮机出力增量 (\Delta P_{GT,t})、弃光量 (P_{curt,t})、切负荷量 (P_{shed,t})、储能修正功率,也要满足调整后的平衡关系。
电网交互方面,要注意购电和售电不能同时发生。用0-1变量和Big-M约束实现:
[ 0 \le P_{buy,t} \le P_{tie}^{max} \cdot \beta_t ] [ 0 \le P_{sell,t} \le P_{tie}^{max} \cdot (1 - \beta_t) ]
如果不加这个互斥约束,模型会在峰谷电价差明显时“低买高卖”套利,造成联络线功率与实际不符的假象。
4.4 第二阶段调整空间的建模
第二阶段调整变量是两阶段鲁棒模型里比较特殊的一类。它们的作用是“救场”——当光伏和负荷偏离预测值时,用这些资源补上功率缺口或者消化多余功率。
典型调整变量包括:
- 燃气轮机出力上调量/下调量:受爬坡速率和上下限余量约束
- 储能充放电功率修正量:受当前SOC和功率上限约束
- 弃光量:受当前光伏实际出力的上限约束
- 切负荷量:受重要负荷比例上限约束
这些调整量的成本通常远高于正常发电成本。比如切负荷惩罚可以设成正常电价的几十倍,弃光惩罚设成正常发电成本的两到三倍。这样设计的目标是让求解器在第二阶段优先使用“便宜”的调节手段,比如储能和机组调整,实在不行才用弃光和切负荷。
另外,第二阶段是“最坏场景下的最优调整”,所以调整空间越大,鲁棒解的保守性越低。这也是为什么储能容量在鲁棒框架下价值会高于确定性框架下的价值——它既是正常运行时段的调节资源,也是极端场景下的“安全垫”。
5. C&CG算法求解:把min-max-min问题变成能算的问题
5.1 子问题的对偶转换
两阶段鲁棒优化直接求不了,因为内层是 (\max\min) 结构,不是标准的凸优化形式。C&CG(列与约束生成)是目前比较主流的解法,核心思路是把原问题拆成主问题和子问题迭代求解。
子问题是这样的:给定第一阶段决策 (x^*),求:
[ Q(x^) = \max_{u\in\mathcal{U}} \min_{y\in\Omega(x^,u)} c_2^T y ]
其中 (\Omega(x^,u) = { y \ge 0 : G y \ge h - E x^- F u }) 是第二阶段可行域。
内层的 (\min) 是一个线性规划。根据强对偶定理,可以把它换成对偶问题:
[ Q(x^) = \max_{u\in\mathcal{U}, \pi \ge 0} \pi^T (h - E x^- F u) ]
约束条件是 (G^T \pi \le c_2)。这样就把内层的 (\min) 消掉了,但带来了一个新的难点:目标函数里出现了 (\pi^T F u),这是对偶变量 (\pi) 和不确定参数 (u) 的乘积,构成双线性项,问题变成非凸的。
5.2 双线性项的处理思路
处理双线性项是两阶段鲁棒求解里最核心的细节。工程上有几种做法,我按推荐程度排序:
第一种,当不确定集是预算集且 (\Gamma) 较小时,可以直接枚举不确定集的顶点。因为预算集的极值点有明确结构,顶点数量虽然会随维度增长,但微电网调度问题按24时段建模时,(\Gamma) 取8到12,顶点规模还在可控范围内。枚举顶点后,每个顶点对应一个线性规划,取目标值最大的那个,就是子问题的最优值。
第二种,把双线性项做线性化。具体做法是把归一化误差变量 (z) 拆成正负两个0-1变量,用大M约束把 (v_j z_j)(其中 (v_j) 是对偶变量相关的量)线性化成一组混合整数线性约束。代码量大一些,但求解精度高。
第三种,直接用能处理双线性项的商业求解器。Gurobi 9.0之后支持非凸MIQP/Bilinear求解,CPLEX也支持,代码写起来省事。但要注意,非凸求解器在模型规模变大时可能很慢,不适合在线滚动优化场景。
我的建议是:做学术研究可以用第二种方式写精确解,工程初版先用第一种枚举顶点的方式把链路跑通,效率不够再换线性化。
5.3 C&CG迭代框架
C&CG的完整流程可以用伪代码描述:
1. 初始化: k = 1 选择初始场景 u^(1)(一般用预测值) LB = -inf, UB = inf 2. 求解主问题: min c1'*x + theta s.t. Ax <= b theta >= c2'*y^(j), j = 1,...,k G*y^(j) >= h - E*x - F*u^(j), j = 1,...,k 第一阶段与y^(j)的相关约束 得到 x*, theta* LB = c1'*x* + theta* 3. 固定 x*,求解子问题: Q(x*) = max_{u in U, pi>=0} pi'*(h - E*x* - F*u) s.t. G'*pi <= c2 得到 u* 和 Q* UB = min(UB, c1'*x* + Q*) 4. 收敛判断: if (UB - LB) / abs(UB) <= epsilon 输出 x*, 结束 endif 5. 生成新列: k = k + 1 u^(k) = u* 给主问题新增一组第二阶段变量 y^(k) 和对应的耦合约束 转到步骤2收敛速度方面,经验数据是:对24时段的微电网模型,(\Gamma) 取8到12时,一般10到20次迭代就能达到相对gap小于1e-3。比Benders分解快不少。
5.4 与Benders分解的对比
可能有人会问:为什么不用Benders分解?两者核心区别在于:
| 项目 | C&CG | Benders分解 |
|---|---|---|
| 主问题内容 | 新增完整第二阶段变量和约束(列) | 只添加割平面(约束) |
| 主问题规模 | 随迭代次数增大较快 | 规模增长慢 |
| 收敛速度 | 通常更快,迭代次数少 | 迭代次数多 |
| 适用场景 | 第二阶段为连续变量、线性约束 | 各种场景,但割平面近似可能慢 |
C&CG的另一个优势是:每次迭代都把最恶劣场景的一整套第二阶段变量和约束“写死”进主问题,主问题的决策质量会快速逼近原问题最优解。Benders需要很多次割平面才能逼近,而且割平面太弱时容易振荡。
我在微电网模型上的实际体验:C&CG平均15次迭代收敛,Benders要跑到100次以上,两者在单次迭代的耗时差异不大。所以微电网领域优先用C&CG。
6. MATLAB+YALMIP实现:从数学公式到能跑的项目代码
6.1 主程序流程设计
下面给出一个完整的实现框架,求解器用Gurobi或CPLEX。MATLAB里配YALMIP工具箱,建模效率比直接用求解器API高很多。
主流程伪代码:
% 输入基础数据:负荷预测、光伏预测、分时电价、机组参数、储能参数、Gamma % 初始化 u_cell{1} = [PV_forecast; Load_forecast]; % 初始场景 K = 1; LB = -inf; UB = inf; Gap = 1; while Gap > 1e-3 && K <= 30 % 求解主问题 [x_opt, theta_opt, MP_model] = solve_MP(u_cell, K); LB = cost1(x_opt) + theta_opt; % 求解子问题 [Q_val, u_worst] = solve_SP(x_opt, uncertainty_set_params); UB = min(UB, cost1(x_opt) + Q_val); Gap = (UB - LB) / abs(UB); K = K + 1; u_cell{K} = u_worst; end主问题和子问题分别封装成函数。每个函数内部用YALMIP定义变量和约束,求解后返回需要的值。迭代过程中,u_cell 保存所有已经发现的恶劣场景,主问题里每列约束对应一个场景。
6.2 用YALMIP表达不确定集与C&CG循环
不确定集的YALMIP代码很直观:
% 不确定参数定义 z = sdpvar(2*T, 1); % 前T个是光伏归一化误差,后T个是负荷归一化误差 % 实际值与预测值的关系 U = U_forecast + Delta_range .* z; % 预算不确定集约束 Uncertainty_bound = [-1 <= z <= 1, norm(z, 1) <= Gamma];主问题里,每组场景对应的第二阶段变量直接在循环里创建:
for k = 1:K y{k} = sdpvar(2*T, 1); % 调整变量 Constraints = [Constraints, theta >= c2' * y{k}, G*y{k} >= h - E*x - F*u_cell{k}, y{k} >= 0]; end子问题里,核心是求解对偶后的最坏场景问题。如果按枚举顶点的简化方式,可以这样写:
function [Q_val, u_worst] = solve_SP(x_opt, ...) best_Q = -inf; for each vertex u_of_vertex in uncertainty_vertices % 对固定场景u,第二阶段是标准LP [y_opt, cost] = solve_LP_with_fixed_u(x_opt, u_of_vertex); if cost > best_Q best_Q = cost; u_worst = u_of_vertex; end end Q_val = best_Q; end6.3 储能SOC约束的调试细节与初值陷阱
储能建模里最容易翻车的地方有三个,我一个个说。
第一,SOC初值不能乱设。很多初学者的模型里 (SOC_1 = 0.2),然后就不管了。如果没加日循环约束 (SOC_{T+1} = SOC_1),求解器会为了让购电成本最小,把电池的电全部放光还款日结算,第二天直接没法用。这种计划在仿真里好看,落地就是事故。正确做法:要么加日循环约束,要么把SOC初值作为一个待优化变量,给它一个合理的区间。
第二,充放电效率的方向别搞反。(SOC_{t+1} = SOC_t + \eta_c P_{ch,t} - P_{dis,t}/\eta_d),(\eta_c) 和 (\eta_d) 都小于1。如果写反了,模型的“免费能量”会凭空出现,目标函数值虚低。
第三,互斥约束别省。前面提过,不写 (\alpha_t + \beta_t \le 1) 这种互斥约束,模型会出现电池同时充电和放电。原因是分时电价下,求解器可能用低电价充电、高电价放电,同时在同一个时段充放来满足某个虚构约束。只要不存在互斥约束,线性规划里同时充放有时候反而能满足某些边界条件。调试时直接看P_ch和P_dis的时序图,一眼就能发现这种问题。
6.4 Big-M的选取与数值稳定性
两阶段鲁棒模型里到处都是Big-M约束,比如购售电互斥、双线性项线性化。Big-M取多大,直接决定求解器数值稳定性。
经验公式很简单:M取物理量合理上界的1.1到1.5倍。比如联络线功率上限5MW,M取6到8就够;储能充放电功率上限1MW,M取1.5就够。
坑在哪里?很多人图省事取M=1e6。问题不是逻辑错误,而是数值病态。CPLEX和Gurobi在MIP预求解时遇到极端的Big-M,会把一些变量的实数精度拖到不可接受的程度,导致整数变量判断错误,产生不满足物理规律的解。我在一个项目里就吃过亏:把M取成1e6后,求解器给出的“最优解”里出现了一个时段联络线功率超过上限几十倍的异常值,查了半天才发现是Big-M太大把预求解搞崩了。
另一个数值稳定性经验:求解器选项里把MIPGap设成1e-4,TimeLimit设成300到600秒。微电网调度模型规模不算大,正常不会超时,但加个限制能防止某些数值病态场景下求解器无限跑下去。
7. 从日前到日内:滚动时域与模型预测控制的工程化结合
7.1 多时间尺度框架:日前鲁棒计划 + 日内MPC修正
两阶段鲁棒优化解决的是日前调度问题,但实际微电网控制系统不是“一天算一次然后照做”。工程上标准的做法是多时间尺度能量管理:日前做鲁棒优化,日内做滚动优化,实时层做本地控制。
以我参与的项目为例,框架是这样的:
- 日前阶段(提前24小时):用两阶段鲁棒优化生成第二天的机组启停、储能基准计划、购售电合同。这些决策不能随便改,尤其是机组启停,涉及现场人员的排班和燃料准备。
- 日内阶段(每15分钟):用模型预测控制(MPC)滚动重调度。每次优化使用最新的光伏和负荷预测(短期预测精度比日前高很多),在满足日前计划约束的前提下,修正储能功率、燃气轮机出力、联络线交互功率。
- 实时层(秒级):本地P/Q控制器跟踪MPC下发的功率指令,处理毫秒级的扰动和通信延迟。
这里的关键逻辑是:日前鲁棒计划给了系统一个“安全基线”,日内MPC在这个基线上做经济性修正。二者不是替代关系,而是互补关系。如果只有日前鲁棒优化,方案太保守,日常运行成本偏高;如果只有日内MPC,遇到大偏差时调节空间可能不够。鲁棒给出安全兜底,滚动修正找回经济性。
7.2 MPC滚动优化目标设计与约束软化
日内MPC的优化问题在每个采样时刻 (k) 求解一次,预测时域一般取4到6小时,控制时域取1小时。目标函数示例:
[ \min \sum_{t=k}^{k+N_p-1} \left( c_{buy,t}P_{buy,t} - c_{sell,t}P_{sell,t} + c_{GT}P_{GT,t} + \lambda_{curt}P_{curt,t} + \lambda_{shed}P_{shed,t} + \lambda_{soft}(\varepsilon_t^+ + \varepsilon_t^-) \right) ]
其中 (\varepsilon_t^+) 和 (\varepsilon_t^-) 是约束软化变量,用来保证MPC在模型失配时不会因为约束太硬而无解。这个软化的思路一定要有。实际系统里,预测不是完全准确的,模型也有误差,硬约束MPC很容易在某一步求解失败。加了软约束之后,MPC至少能输出一个可行的次优解,保证系统不失控。
MPC的功率平衡约束写成:
[ P_{GT,t} + P_{PV,t}^{forecast} + P_{dis,t} - P_{ch,t} + P_{buy,t} - P_{sell,t} = P_{L,t}^{forecast} + \varepsilon_t^+ - \varepsilon_t^- ]
外部电网交互策略方面,我倾向于在MPC里把日前合同购电量作为参考值,允许小范围偏差,偏差部分按实时电价结算。这样既尊重了日前市场的承诺,又保留了日内调节的灵活性。
7.3 工程实践中的几个关键建议
滚到工程落地环节,有几个坑值得提前说。
第一,日前鲁棒优化的 (\Gamma) 不应该是固定值。天气不稳定时(比如强对流季节的午后),光伏预测误差大,(\Gamma) 应该调大;天气稳定时,(\Gamma) 可以调小。我在项目里用了一个简单策略:根据当日天气预报的云量和降雨概率,对 (\Gamma) 做分档调整。效果比固定值好不少。
第二,储能SOC的日内管理要留调节裕度。日前鲁棒计划如果已经让SOC接近上限或下限,日内MPC就没有调节空间了。所以我会在日前计划里主动把SOC的运行区间压缩到10%到90%,而不是让优化去触碰真正的硬边界。牺牲一小部分经济性,换取日内足够的调节能力。
第三,MPC的预测模型建议加上状态估计。光伏和负荷的实际值不能直接从预测曲线拿,要用卡尔曼滤波或移动平均处理实测数据,得到更准确的当前状态。否则MPC的反馈校正环节会引入较大误差。
第四,微电网与外部电网的联络线功率要设置安全裕度。很多项目只按变压器容量设上限,实际运行时联络线功率接近上限会导致并网点电压波动。我一般会在MPC里把联络线上限设为变压器容量的85%,留出15%的调节空间。
另外想说一点关于“微电网日前优化调度”竞赛类项目的经验。很多人参加电工杯这类竞赛时,把精力都花在模型复杂度上,结果忽略了一个基本问题:方案在遇到不确定性时到底扛不扛得住。竞赛给的评分细则里如果有“鲁棒性”这一项,两阶段鲁棒优化的思路会好过单纯的确定性优化。如果没有专门评分项,写报告时也建议把“确定性方案在偏差场景下的失效分析”放进去,这能显著提升方案的说服力。
最后再分享一个调试小技巧。两阶段鲁棒模型跑完之后,别急着看成本值,先把以下三个指标打印出来看:第一阶段方案的启停状态、最恶劣场景下第二阶段的调整量分布、以及每个时段的功率平衡残差。这三个指标能在5分钟内帮你判断模型到底是“逻辑错了”还是“参数不合理”。我调试这类模型时,这已经成了标准动作,能省下大量排查时间。