
最近一个做分布式能源规划的朋友来找我说他们手里的多微网项目从单微网独立优化扩展到多微网联合调度之后问题复杂度直接上了一个台阶。光伏出力和负荷需求一波动原先那套确定性调度结果就完全不能用。我们后来把思路切成两阶段鲁棒优化用MATLAB从头搭了一套“容量配置联合调度”的完整代码才把问题理顺。这篇就把模型怎么建、算法怎么解、代码怎么写、实际踩过哪些坑一次性理清楚给正打算做多微网鲁棒规划的同学省点时间。1. 多微网联合调度与容量配置为什么放在一起做1.1 联合调度改了什么以前做单微网规划逻辑很简单给一组预测曲线比如典型日的光伏出力和负荷曲线然后在这个确定场景下优化设备容量和运行策略。设备之间无非是光伏、储能、柴发模型规模小求解快结果也容易解释。扩到多微网之后如果还是把每个微网拆开单独优化问题就来了。不同微网的光伏出力峰值时段往往错开负荷峰谷也不对齐有的微网午间光伏多得要弃掉有的微网晚上负荷高得只能高价购电。信息互通、功率互联之后闲置储能和盈余电量完全可以被邻居消纳单微网各自死守自己的平衡反而浪费。联合调度的核心是在模型里多引入一类联络线功率变量把各微网的功率平衡方程从“独立等式”改成“耦合等式”。某个微网缺电时可以从相邻微网购电也可以把多余电量卖给邻居。这个改动让目标从“每个微网各自最小化自己的成本”变成了“整个微网集群协同最小化总成本”投资容量、运行策略、交互功率必须一起决策。1.2 两阶段鲁棒优化到底在优化什么多微网调度一旦引入不确定性问题性质就变了。光伏出力不是确定值负荷也不是固定曲线它们会在某个区间内波动。确定性优化给出的方案在预测场景下可能是最优的但遇到光伏大幅度低于预测、负荷又高于预测的时候可能直接导致切负荷或者储能过放。随机规划可以处理这类问题但它需要知道不确定量的概率分布而实际工程中分布信息往往拿不准。两阶段鲁棒优化选择了一条更稳妥的路不确定性只给边界不给概率。第一阶段做投资决策也就是容量配置包括光伏装机、储能容量、柴发台数第二阶段等不确定性真正暴露之后再做运行调度也就是各时段机组出力、储能充放电、微网间交互功率。数学上可以写成这个形式min_x c^T x max_{u ∈ U} min_{y ∈ F(x,u)} d^T y其中 x 是容量配置决策c^T x 是投资成本u 是不确定参数U 是不确定集合y 是第二阶段运行变量d^T y 是运行成本。后面的 max-min 结构要找的是“最坏不确定性场景下的最小运行成本”外层 min 选择的容量配置必须保证未来无论 u 在 U 里怎么变都能找到一个可行的运行方案。用生活里的例子类比就是一个城市决定修多宽的马路这是第一阶段决策每天根据实际车流安排车道和信号灯这是第二阶段决策。确定性规划只看预测车流随机规划要给车流假设概率分布鲁棒优化只给车流一个变化范围算法自己去找“车流最坏的情况下也不至于全城拥堵”的最优修路方案。三类方法的核心区别可以用一张表说清楚对比维度确定性优化随机规划两阶段鲁棒优化不确定性描述取预测值给定概率分布给定不确定集合目标函数单层最小化期望值最小化最坏场景最小化保守程度最低中等较高可由预算参数调节对分布信息依赖无强无求解难度低中较高这也是为什么这两年多微网规划领域的代码和论文里两阶段鲁棒优化出现频率越来越高。它不需要精确分布又能保证一定的工程保守性配合容量配置正好对路。2. 数学模型从设备类型到约束细节2.1 系统结构与变量定义设计模型之前先把系统结构定下来。我用的是三个微网组成的标准集群每个微网内部包含四类设备光伏机组、储能系统、柴油发电机、本地负荷。三个微网通过联络线两两相连微网集群通过一个公共连接点与上级配电网相连。决策变量分成两批。第一阶段变量是容量配置各微网光伏装机容量、储能额定容量、储能功率上限、柴油发电机台数。第二阶段变量是运行调度各时段光伏实际出力、储能充电功率、储能放电功率、储能荷电状态、柴发出力、微网间交互功率、公共连接点购售电功率。区分清楚这个变量层次非常重要因为它直接决定了模型怎么写、子问题怎么对偶。很多初学者把投资变量和运行变量混在一起建出来一个超大超复杂的混合整数规划结果既难解又难调试。2.2 目标函数拆解目标函数也不复杂本质是“投资成本加最坏场景年运行成本”。投资成本这部分是线性的公式可以写成C_inv c_pv * P_pv c_bess_e * E_bess c_bess_p * P_bess c_dg * N_dg其中 P_pv 是光伏装机容量E_bess 是储能容量P_bess 是储能功率上限N_dg 是柴发台数对应的 c 是单位容量成本系数。这里注意储能容量和功率是做两个变量分别收费的容量对应电池本体成本功率对应PCS变流器成本两者约束不同不能混成一个参数。第二阶段运行成本包括柴发燃料费用、设备运维费用、从上级电网购电费用再减去向电网售电的收益。实际项目中还可以加惩罚项比如切负荷惩罚和弃光惩罚两种惩罚力度设置得好不好直接决定鲁棒解会不会出现极端优化结果。目标函数落成代码如下% 两阶段鲁棒优化模型目标函数结构示意 % x_first第一阶段容量配置变量 % y_second第二阶段运行变量 % eta辅助变量表示最坏场景运行成本的近似值 objective c_invest * x_first eta;2.3 关键约束与储能动态多微网联合调度模型里最核心的约束是功率平衡约束。每个微网每个时段都要满足光伏出力 柴发出力 储能放电 - 储能充电 从邻居微网购电 - 向邻居微网售电 负荷这条约束看起来简单但它是第二阶段变量之间的耦合关系也是子问题对偶之后双线性项最容易出现的地方。储能动态约束是另一个重点。荷电状态满足递推关系SOC(t1) SOC(t) - P_dis(t) / η_dis P_ch(t) * η_ch储能系统还必须满足容量约束、充放电功率约束、以及同一个时段不能同时充电和放电的约束。最后这条通常需要引入二进制变量主问题求解时二进制变量会让模型变成混合整数线性规划求解时间会明显增加。柴发约束包括出力上下限、爬坡约束和最小启停时间。如果只做容量配置层面的联合调度柴发的开关状态可以适当简化连续出力加爬坡约束就够了。真要把最小启停时间也建进去模型会变得很重后续CCG迭代每一轮都要重新求解混合整数规划整体计算量会爆炸。联络线约束也要单独处理。每条联络线有最大传输功率限制公共连接点与上级电网之间也有购电和售电功率上限。实际运行时微网之间的交互功率是双向的建模时需要定义正方向并用两个非负变量分别表示买电和卖电再约束二者之和不超过线路容量。2.4 不确定性集合怎么建两阶段鲁棒优化的不确定集合是整个模型设计的灵魂。最常用的方式是盒式区间加预算约束。光伏出力的不确定参数表示为预测值乘一个波动系数u_pv ∈ [ u_pv_min, u_pv_max ]其中 u_pv_min 通常取预测值的0.6到0.8倍u_pv_max 取预测值的1.0到1.2倍。负荷同理可以在±15%区间内波动。光有盒式集合还不够因为盒式集合允许所有不确定参数同时取最坏值结果过于保守。工程上引入预算参数 Γ限制所有不确定参数偏离预测值之和的上限。Γ 从0取到最大可能值对应从完全确定性到最保守的过渡。不确定集合写出来就是U { u | u_i ∈ [u_pred_i - Δ_i, u_pred_i Δ_i], Σ |u_i - u_pred_i| / Δ_i ≤ Γ }这个集合的好处是Γ 可以直接当作保守性旋钮来调。做实际项目时可以先设 Γ 为零跑一版确定性结果再逐渐增大 Γ观察容量配置和系统成本的变化趋势最后选一个业主能接受的折中方案。3. CCG 算法求解与 MATLAB 实现3.1 列与约束生成的整体流程两阶段鲁棒优化不能直接扔给普通求解器求解因为 max-min 结构不是一个标准数学规划形式。工程上最主流的求解方法是列与约束生成算法简称 CCG。算法核心思路是迭代逼近最坏场景。先求解一个只包含有限个最坏场景割集的主问题得到候选容量配置方案然后把这个方案固定求解子问题找出当前方案下的最坏不确定性场景再把新的割集加入主问题继续求解。反复迭代直到上下界收敛。迭代流程可以写成如下伪代码初始化LB -inf, UB inf, k 0 循环 1. 求解主问题MP得到最优解 x_k、目标值 obj_MP 2. 更新 LB obj_MP 3. 固定 x_k求解子问题SP得到最坏场景 u_k 和运行成本 Q(x_k) 4. 更新 UB min(UB, c_inv * x_k Q(x_k)) 5. 如果 (UB - LB) / UB 1e-3终止 6. 把最坏场景 u_k 加入主问题新增变量 y_k 和割集 7. k k 1这个算法收敛速度非常快通常迭代十几次上下界gap就能压到很小。比起Benders分解CCG每次生成的是“列和约束”同时添加割集质量高很多尤其适合含二进制变量的场景。3.2 子问题的 max-min 结构与线性化子问题是整个求解过程的硬骨头形式是Q(x) max_{u ∈ U} min_{y ∈ F(x,u)} d^T y内层是对固定 x 和 u 的运行优化外层要找最坏 u。内层是个线性规划可以取对偶把 min 转成 max。对偶之后内层和外层合并成一个新的 max 问题但对象是原来的 u 和新增的对偶变量目标函数里会出现 u 乘以对偶变量的双线性项。处理双线性项是子问题求解的关键。工程上有两种路线。第一种是直接利用不确定集合的几何性质盒式集合加预算约束的最优解通常落在边界顶点上可以枚举候选极值场景依次求解内层线性规划取最大的那个。这种方法在不确定源数量不多时非常高效稳定性也好。第二种是引入大M法把双线性项线性化或者把内层优化用KKT条件替换成互补约束再用混合整数规划求解。后者对大规模系统更通用但实现复杂度直接高一个级别。我做这个项目的实际经验是先枚举极值场景验证逻辑正确性等模型整体跑通了再考虑换对偶线性化的通用版本。上来就写大M法调试时会分不清是模型问题还是线性化问题。3.3 MATLAB 代码框架MATLAB 下实现 CCG核心是循环加两个求解模块。主问题是带割集的混合整数线性规划子问题固定第一阶段变量。代码框架可以组织成三个函数主问题求解、子问题求解、主循环控制。主问题模块示例如下function [x_star, eta_star, obj_MP] solve_MP(c_invest, cut_pool) % 第一阶段变量光伏容量、储能容量、柴发台数 x1 sdpvar(3, 1); % 辅助变量 eta 是割集逼近的最坏运行成本 eta sdpvar(1, 1); constraints [x1 0; x1(3) 0]; % 添加历史割集 for k 1:length(cut_pool) cut cut_pool(k); constraints [constraints, eta cut.affine_expr]; end obj c_invest * x1 eta; optimize(constraints, obj); x_star value(x1); eta_star value(eta); obj_MP value(obj); end子问题模块相对复杂固定 x 之后把不确定参数当成变量内层运行优化用对偶或者枚举处理。枚举型的子问题结构比较直观function [Q_val, u_worst] solve_SP(x_fixed, system) scenarios generate_extreme_scenarios(system.UncertaintySet); Q_val -inf; u_worst []; for i 1:size(scenarios, 2) u scenarios(:, i); Q_i solve_inner_op(u, x_fixed, system); if Q_i Q_val Q_val Q_i; u_worst u; end end end主循环模块把两者串起来维护割集池和上下界。每次子问题求解得到一个最坏场景 u就在主问题里复制一组新的第二阶段变量新增加强约束。收敛之后x 就是鲁棒最优容量配置目标函数值对应整个系统在最坏场景下的综合成本。3.4 收敛判据与迭代上限设置CCG代码里收敛判据不能只看迭代次数。上下界gap通常定义为gap (UB - LB) / UB我习惯设三重停判标准gap小于0.1%停机迭代次数超过20次停机连续三次迭代UB不再下降停机。三重判据的好处是防止偶尔出现数值振荡上下界在小范围内抖动但始终不收敛白白浪费时间。还要注意求解器的相关配置。MathWorks环境自带的混合整数线性规划求解器能对付小规模算例一旦微网数量超过五个、每个微网设备多了建议换成专业商用求解器。建模工具箱只是帮我们把模型翻译成求解器能识别的标准格式真正决定求解速度的还是底层求解器。4. 一个典型算例的完整试验与结果分析4.1 算例设置算例采用三个微网的集群结构。三个微网的负荷峰值分别是200千瓦、150千瓦、250千瓦光伏预测最大出力分别是300千瓦、250千瓦、400千瓦。储能初始设计候选容量范围是100到400千瓦时柴发单台容量50千瓦最多可装4台。联络线容量统一设为150千瓦。不确定性参数设置上光伏波动范围取预测值的0.7到1.0倍负荷波动范围取0.9到1.1倍预算参数 Γ 从0逐步调整到最大场景数。所有成本系数参照常见工程数据光伏单位容量年化投资成本按每千瓦6000元计算储能按每千瓦时3000元加上每千瓦2000元变流器成本柴发按每台2万元年化成本购电价和上网电价分峰谷时段设置。4.2 与确定性优化方案对比先跑确定性方案也就是 Γ0 的情况。优化结果里三个微网的光伏装机基本接近预测出力上限储能总容量配置偏小柴发总台数只有三台。这个方案在预测场景下年运行成本最低看起来非常漂亮。然后跑两阶段鲁棒优化Γ 逐步调到5再调到10容量配置出现了明显变化。光伏装机总量略微下降储能总容量显著上升柴发总台数增加到五台。原因是光伏在不确定集合取最坏值时出力大幅下降系统必须靠储能和柴发来兜底所以可调度资源必须多配。两种方案的对比可以用表格直观体现对比项确定性方案鲁棒方案(Γ10)光伏总装机950 kW880 kW储能总容量360 kWh620 kWh柴发总台数3台5台预测场景下年运行成本低高约12%最坏场景下年运行成本高低约35%这组数据揭示了一个关键规律鲁棒优化不是让所有场景下都更省钱而是把成本风险从极端场景转移到正常场景。确定性方案在最坏场景下可能崩溃鲁棒方案虽然正常场景多花一点钱但换来的是最坏场景不再失控。4.3 微网间功率交互的价值联合调度相比各微网独立运行的收益主要体现在微网间功率交互上。独立运行时每个微网必须单独应对自己的不确定性储能和柴发都要预留足够的备用容量。联合运行之后三个微网可以共享备用某时刻光伏出力偏低的微网可以从光伏出力正常的微网购电整集群的备用需求就下降了。算例里我做了对比独立运行模式下储能总容量需要700千瓦时才能满足鲁棒约束联合调度模式只用620千瓦时储能投资成本下降了约11%。微网间联络线一小时最多交互的电量虽然只有150千瓦但这个容量带来的整体备用共享收益非常可观。预算参数 Γ 对结果的影响也很有意思。Γ 越大不确定集合覆盖的场景越极端容量配置越保守。把 Γ 从0逐步调到12储能总容量从360千瓦时逐步上升到680千瓦时但增幅越来越缓说明边际保守化的收益在下降。实际工程报价时我会推荐选曲线拐点附近的 Γ 值既能覆盖大部分风险又不至于过度投资。5. 实际编写中的常见问题与排查经验5.1 子问题求解不出来CCG最常见的运行错误是子问题无解或者目标值异常。原因多数不是算法本身而是第一阶段变量固定之后第二阶段的可行域为空也就是当前容量配置根本没法应对某个极端场景。排查方法是先检查子问题的约束条件是否包含第一阶段变量与第二阶段变量的耦合项。比如柴发功率上限应该由第一阶段柴发台数决定储能充放电功率上限应该由第一阶段储能功率决定。这些耦合约束漏掉任何一条子问题就会给出违反物理意义的结果。另外建议在子问题目标函数里加松弛惩罚变量给功率平衡约束加上切负荷和弃电惩罚。这样即使最坏场景真的超过设备能力子问题也会给出一个有限的成本值而不是直接报错后续迭代还能通过增大惩罚来逐步修正容量配置。5.2 收敛太慢CCG不收敛或者收敛慢第一个要检查的主问题割集添加方式。每次子问题返回最坏场景之后主问题必须新增一组独立于之前变量的第二阶段变量并增加对应约束。如果偷懒直接修改原有变量割集信息就会互相污染上下界gap永远压不下去。第二个常见原因是容差设置不协调。主问题求解器和子问题求解器的相对容差如果设置太大比如默认的1e-4和1e-2混合使用整个CCG的收敛精度会被最宽松的那一环限制。我遇到过一次gap卡在0.8%不动的情况排查半天发现是子问题求解器用了过大的可行容差导致返回的“最坏场景”质量很差。第三个原因是数值缩放。多微网模型里储能容量可能是几百千瓦时运行费用可能是几十万元这些量级差距大的系数放在同一模型里会让求解器数值状态恶化。建议把所有功率和能量单位统一折算成标幺值成本统一折算成年化成本数值问题会少很多。5.3 保守性怎么调鲁棒优化最大的工程争议是保守程度。光伏区间设成0.7到1.0倍负荷区间设成0.9到1.1倍这些参数都是人工定的定得太大建出来的系统容易投资过度。我的经验是先用历史数据做统计取90%置信区间作为不确定集合的边界。如果历史数据不足可以通过试算几个版本给业主看曲线支持率、投资额、最坏场景成本在 Γ 坐标上的关系让决策者自己定接受程度。这比在论文里拍脑袋定 Δ 和 Γ 更有说服力。5.4 调试技巧多微网两阶段模型层级多、变量多直接调试完整的模型非常痛苦。我的习惯是分四步走。第一步把 Γ 设成0跑确定性模型先验证容量配置结果是否符合直觉。第二步固定第一阶段容量配置单独手动构造几个简单场景验证第二阶段运行模型是否正确。第三步用枚举极值场景的方式跑通完整CCG此时不追求速度只求上下界单调收敛。第四步再换对偶线性化版本提速做规模化测试。这样每一步出问题都能快速定位。直接一上来就调完整的对偶线性化代码一旦出错根本搞不清楚是原问题建错了、对偶对了没、还是大M参数不合适。最后说一点个人体会多微网联合调度加容量配置这个题目说难确实难但拆开之后无非是“模型分层”和“算法迭代”两件事。模型层的关键是把投资变量和运行变量、确定部分和不确定部分分清楚算法层的关键是把主问题和子问题分清楚每个子问题内部再把内层优化和外层优化分清楚。层级一旦理清代码怎么写都不会乱。给后来者的建议是不要一开始就追求大而全的模型和最新的求解方法。先从两微网、三台设备、确定性场景的模型跑通再逐步加入不确定性集合、联络线交互、CCG迭代。每一步都保留可以对比的中间结果你会发现所谓“两阶段鲁棒优化”并没有传说中那么神秘它只是在把一个工程问题用一个严谨的框架表达出来。而当你亲手把第一版代码跑出收敛的上下界曲线时那种“原来我能控住最坏场景”的踏实感是单纯看代码永远体会不到的。