两阶段鲁棒优化在微网容量配置中的应用与CCG求解实战
简介面向微电网规划研究人员与电气工程相关专业学生围绕风电、光伏、储能及燃气轮机的容量配置问题采用两阶段鲁棒优化方法应对不确定性第一阶段决策电源容量第二阶段优化实际出力并借助列与约束生成CCG算法完成求解。压缩包内包含完整的MATLAB仿真程序含主程序与子模块函数、模型推导图片、典型日数据表格以及多篇参考论文从问题建模、矩阵推导到算法迭代均有文档支撑适合需要复现两阶段鲁棒规划或学习CCG算法实现的中高级读者。包体为RAR格式共19个文件涵盖6个Word文档、5个M代码、2个PDF、1个Excel及1个CAJ文献整体大小3.76MB其中Word及PDF/CAJ文档用于理论推导与算法说明M代码用于仿真复现Excel数据表提供典型日场景输入结构清晰便于按步骤研读。目前已有1330人学习下载适合用于课程设计、毕业设计或科研入门参考。1. 两阶段鲁棒优化为什么是微网容量配置的硬骨头微网电源容量配置的核心矛盾是光伏和负荷的不确定性。传统确定性优化用典型日曲线替代全年数据算出来的容量在典型日上最优但遇到连续阴雨、尖峰负荷叠加的场景可能会切负荷甚至系统崩溃。场景法又把不确定性离散成几百个场景计算量暴涨而且场景概率很难定准。两阶段鲁棒优化给出的是另一种答案把不确定性建模成一个有界集合在这个集合里寻找最恶劣情形下的最优配置也就是“先决策、后看到最坏情况再调整运行”的主从决策结构。这个标题里的“两阶段”第一阶段是投资决策——选多少光伏、配多少储能、要不要上柴油机第二阶段是运行决策——在不确定参数取到最恶劣值时如何调度各类电源使得运行成本最低。两阶段鲁棒模型把容量配置从一个“求期望最优”的问题变成了“求最坏情形下的最优”的问题这在微网这类需要高可靠性的场景里更有工程意义。适合的读者不是只看理论的学生而是做微网规划、园区能源设计、或者在做分布式电源接入方案时被不确定性折磨的工程师——本文会把模型、求解代码和参数调试路径完整铺开。2. 微网容量配置问题的不确定性建模与两阶段鲁棒模型建立2.1 先想清楚哪几个不确定性变量值得写进模型微网里的不确定性源很多但做容量配置时真正需要进模型的通常只有三类光伏出力、负荷功率、以及电价如果微网与配电网有交换。光伏出力的不确定性和天气强相关常表示为预测值加上一个波动区间负荷的不确定性来自用户行为的随机性通常是日负荷曲线整体平移或局部波动电价在峰谷平三段式电价基础上还会受现货市场价格冲击。定义一个统一的盒式不确定集合是常见做法。设光伏出力预测值为 (P_{pv}^{f}(t))实际值在 ([P_{pv}^{f}(t)-\hat{P}{pv}(t), P{pv}^{f}(t)\hat{P}{pv}(t)]) 内波动(\hat{P}{pv}(t)) 是波动幅度负荷类似。用预算参数 (\Gamma) 控制同时偏离预测值的时段数避免所有时段同时取最极端值否则结果会过度保守。(\Gamma0) 退化为确定性模型(\Gamma) 越大越保守等于时段总数时就是纯盒式最坏情形。这里要特别提醒两阶段鲁棒与传统鲁棒的关键区别在于第二阶段必须对每个不确定实现作出可行的运行调整。也就是说第一阶段配置完容量之后不管光伏和负荷怎么波动第二阶段调度总能找到可行解。这一点在模型里要靠运行约束的“可调整性”来保证不是简单地给不确定性留个备用容量就完事。2.2 两阶段三层的 min-max-min 结构如何落到微网物理约束上两阶段鲁棒容量配置的标准形式是[ \min_{x \in X} \left( C_{inv}(x) \max_{u \in U} \min_{y \in F(x,u)} C_{ope}(y) \right) ]外层 (x)光伏、储能、柴油机的安装容量离散或连续决策中间层 (u)不确定参数光伏出力、负荷功率、电价内层 (y)各时段的运行决策充放电功率、柴油机出力、与配网交换功率、切负荷量。微网层面的物理约束需要细致列写。首先是功率平衡约束每个时段光伏出力加上储能放电、柴油机出力、配网购电必须等于负荷加储能充电、配网售电其次是储能运行约束包括 SOC 递推公式、充放电功率上下限、SOC 上下限以及一个调度周期始末 SOC 相等的约束柴油机有爬坡约束和最小启停时间约束配网交换有功率上限制约这是微网作为受端用户的典型边界条件。储能约束里有一个关键细节充放电功率不能同时为正这个互补约束在第二阶段鲁棒优化里会导致内层 min 问题非凸单纯用线性化处理会引入大量 0-1 变量。实际工程中多数文献会把储能的充放电状态当作第一阶段变量或第二阶段整数变量但这会破坏内层线性规划的对偶结构。一个更务实的做法是允许储能同时充放电但在目标函数中增加极小的惩罚系数或者用大 M 法把互补约束线性化但要承受整数变量的代价。两种路线的效果差异在算例里很明显后面会在代码中演示其中一种。2.3 要把容量配置做成可计算的问题还得把非线性项收拾干净目标函数里的投资成本是容量的一次函数没有问题但运行成本里如果包含柴油机启停成本就需要引入整数变量。第二阶段 min 问题如果只含连续变量且约束是线性的就能用对偶变换把 min-max-min 变成单层 max-min 再进行求解。如果内层带整数就必须用嵌套列和约束生成法nested CCG计算规模会明显上升。因此要把两阶段鲁棒容量配置落地常见做法是让第二阶段运行问题保持为线性规划把启停成本处理成固定运行成本或者用运行状态的线性松弛近似。这不是理论让步而是工程上常用且能保证求解收敛的折中。第一阶段可以带整数变量因为第一阶段是“等一等再决策”的投资层求解时间稍微长一点可以接受。不确定性集合的构造同样要线性化。盒式区间加预算约束本身就是线性的不需要额外处理。但要注意如果引入相关性描述比如光伏和负荷的同时段波动存在负相关盒式集合就不够了需要多面体不确定集合。多面体集合会让第二阶段问题的对偶复杂度上升但对容量配置结果的影响往往小于预期——因为容量配置的保守性主要被预算参数 (\Gamma) 主导而非不确定集合的几何形状。这些细节决定了后面代码里参数该怎么给。3. 用列和约束生成法CCG求解两阶段鲁棒容量配置3.1 为什么选 CCG 而不是 Benders 分解两阶段鲁棒优化主流的精确求解算法有两种Benders 分解和列和约束生成法CCG。Benders 的思路是把第二阶段子问题的最优值函数用割平面逼近外层主问题每次迭代添加一个割而 CCG 的核心是每次迭代直接给主问题添加一组新的第二阶段决策变量和约束相当于把最恶劣场景“列生成”进主问题。CCG 在微网容量配置中的收敛速度通常明显优于 Benders尤其在第二阶段子问题是线性规划时。原因是 CCG 的割平面是“完整的可行域割”每一轮迭代都向主问题注入一组新场景对应的完整约束而 Benders 只注入一个最优性割。对于一个有一定规模的光伏加储能微网CCG 往往 10-15 次迭代就能收敛而 Benders 可能需要几十次到上百次。下面给出 CCG 求解两阶段鲁棒容量配置的主循环逻辑伪代码级 Python Gurobi 风格但未依赖具体环境# CCG 主循环伪代码 # 外层主问题 MP第一阶段投资 当前已知场景集合 S 下的运行约束 for k in range(max_iter): # 1. 求解主问题 MP得到第一阶段解 x^k mp.optimize() x_val {i: mp.getVarByName(fx_{i}).X for i in resources} # 2. 固定 x x_val求解第二阶段子问题 SP # SP: min_y c^T y, s.t. A(x_val) y b, 且 u 是不确定变量 # 这里通过 KKT/对偶等价求 max_u min_y 的形式 sp_result solve_sp(x_val, uncertain_set) # 3. 检查当前最恶劣场景下的运行成本 obj_ub inv_cost(x_val) sp_result.obj # 上界 obj_lb mp.ObjVal # 主问题目标值下界 if abs(obj_ub - obj_lb) epsilon: break # 4. 提取最恶劣场景 u^k把对应的运行变量 y^k 和约束加入主问题 add_column_to_mp(u_ksp_result.worst_u, kk) # 输出 x* 为最优容量配置这段代码的逻辑核心是“主问题越来越丰满上下界逐渐收紧”。主问题一开始只有随机选的场景当子问题找到更恶劣的场景时主问题就把这个场景的约束加进去逼着第一阶段投资方案往更稳健的方向调整。循环终止条件是上下界差小于阈值阈值通常取总投资成本的 1% 以内。3.2 第二阶段子问题的 max-min 怎么转化为单层优化第二阶段子问题是 (\max_{u \in U} \min_{y \in F(x,u)} c^T y)。直接求解 max-min 很困难但内层 min 是线性规划时可以写其对偶问题把 min 换成 max这样就变成两层 max 的合并变成一个单层线性规划对偶形式[ \max_{u, \lambda} ; b(u)^T \lambda \quad \text{s.t.} ; A^T \lambda \le c, ; \lambda \ge 0, ; u \in U ]注意这里的 (b(u)) 是含不确定参数 (u) 的约束右端项所以对偶目标里会出现 (\lambda) 与 (u) 的乘积这是双线性项。Gurobi 这类求解器可以直接处理含有双线性项的模型但要求模型是二次约束或二次目标。如果不想引入双线性可以用大 M 法将双线性项线性化或者使用 NLP 求解器。在实际算例中双线性项带来的非凸性会导致求解器返回局部最优。针对这个问题工程上常见的做法是固定不确定性集合的预算参数 (\Gamma)把 (U) 的限制条件写成约束然后使用 Gurobi 的多起点Multi-start策略求解取最优值作为子问题结果。下面的代码演示了如何用 Gurobi 构建子问题from gurobipy import Model, GRB, quicksum def solve_sp(x0, pv_pred, load_pred, pv_dev, load_dev, gamma): sp Model(SP) # 不确定变量 u_pv[t], u_load[t] 在 [-1, 1] 范围 u_pv {t: sp.addVar(lb-1, ub1, namefu_pv_{t}) for t in T} u_load {t: sp.addVar(lb-1, ub1, namefu_load_{t}) for t in T} lam [sp.addVar(lb0, nameflam_{i}) for i in range(n_cons)] # 预算约束|u| 的 l1 范数不超过 gamma sp.addConstr(quicksum(abs(u_pv[t]) abs(u_load[t]) for t in T) gamma) # 对偶目标sum (b_i(u) * lam_i)其中 b_i(u) 含不确定量 sp.setObjective(quicksum(b_i(i, x0, u_pv, u_load) * lam[i] for i in range(n_cons)), GRB.MAXIMIZE) # 对偶可行约束 A^T lam c for j in range(n_vars): sp.addConstr(quicksum(A[i][j] * lam[i] for i in range(n_cons)) c[j]) sp.Params.NonConvex 2 # 允许双线性项 sp.Params.MultiStart 10 sp.optimize() worst_u {t: u_pv[t].X for t in T} return sp.ObjVal, worst_u代码里 NonConvex2 是告诉 Gurobi 接受双线性约束MultiStart 用于尝试多个初始点来提高找到全局最优的概率。注意 (\lambda) 的数量等于第二阶段原问题的约束条数这在微网模型里可能上千所以要合理设计约束矩阵的存储方式用稀疏矩阵传给求解器否则内存会爆掉。3.3 主问题的场景累积与维度控制技巧每轮 CCG 迭代都会向主问题添加一组新场景的运行约束和变量。场景多了以后主问题会变成一个巨大的线性规划求解越来越慢。另一个角度是新加的场景如果与已有场景相似对主问题解的改进很小这时候需要加入场景筛选机制。一个实用的技巧是在子问题求出的最恶劣场景 (u^k) 加入主问题之前先检查它与已有场景的相似度。相似度可以用欧氏距离或最大偏差衡量如果小于阈值就直接跳过该场景避免主问题膨胀。不过这种方法要小心如果跳过场景上下界收敛的准确性会受影响因此工程实践中更常见的是保留所有场景但把主问题求解时间控制在合理范围内或者用滚动过程提前终止——当连续三次主问题目标值变化小于 0.1% 时认为解已经足够稳定。此外第一阶段决策变量如果是离散的比如储能 install 容量按 10 kWh 步长选主问题变成混合整数规划。CCG 在这种情形的收敛性在理论上仍然成立但每轮求解时间会显著增加。建议在第一轮运行时先把离散变量松弛成连续变量获得连续下界再用整数约束求解一次主问题这样能快速判断最优容量大概在哪个范围缩短后续迭代的搜索空间。4. 算例实现光照、负荷波动与储能配置的完整调参路径4.1 基础算例参数表与不确定预算的含义为了把上面的模型落到可复现的算例上我设计了一个小时级调度的小型微网光伏 1 MW 基准负荷峰值约 800 kW储能可选容量 0-2 MWh柴油机可装 0-500 kW与配电网交换功率上限 300 kW。调度周期取 24 小时用一天的代表性数据迭代计算一年的典型结果实际项目中可以扩展为多典型日加权。下表是算例的核心参数其中不确定预算 (\Gamma) 是重点调试对象。参数名符号数值说明光伏预测出力(P_{pv}^f)0-1000 kW 逐时曲线采用典型日归一化曲线光伏波动幅度(\hat{P}_{pv})15% 的预测值盒式区间半宽负荷预测值(P_L^f)峰值 800 kW 曲线日负荷率 0.65负荷波动幅度(\hat{P}_L)10% 的预测值负荷预测通常更准不确定预算(\Gamma)0, 4, 8, 12, 240 为确定性模型24 为纯盒式储能 SOC 上限(SOC^{max})0.9保护寿命储能 SOC 下限(SOC^{min})0.1防过放储能充放电效率(\eta)0.95双向统一效率柴油机燃料成本(c_f)0.6 元/kWh线性化燃料成本与配网交互限值(P_{grid}^{max})300 kW多数园区受变压器容量限制(\Gamma) 在这里是一个整数代表“允许同时偏离预测值的时段总数”。(\Gamma4) 意味着最多有 4 个时段的光伏和负荷同时取到区间边界值这比 24 个时段全部取最坏值要温和得多。从工程直觉上(\Gamma) 的选择应该基于历史数据中实际偏差的分布频次。如果统计到一年里偏差超过预测值 15% 的小时数比例约 10%工作日 24 小时对应 (\Gamma) 约 2-4如果要求极端可靠可以考虑 8 以上。4.2 从确定性模型出发的基准解与 CCG 迭代结果先跑一遍确定性模型(\Gamma0)求解得到光伏 800 kW、储能 1.2 MWh、柴油机 200 kW。此时总成本投资折算年运行成本最低但有一个明显的问题当某一天光伏持续低于预测值 15%且晚高峰负荷同时偏高 10% 时功率平衡会被打破被迫从配网多购电但配网交换上限只有 300 kW这时候系统只能切负荷年切负荷电量约 23 MWh这在工程上不可接受。接着启用 CCG 求解两阶段鲁棒模型设置收敛阈值为 1%。迭代过程如下表迭代轮次主问题目标万元/年子问题最恶劣运行成本万元/年上界下界差距1152.318.6170.9152.312.2%2163.710.2173.9163.76.2%3168.16.8174.9168.14.0%4171.54.3175.8171.52.5%5173.22.9176.1173.21.6%6174.02.1176.1174.01.2%7174.51.6176.1174.50.9%可以看到前 3 轮上下界差距快速缩小第 7 轮满足 1% 的收敛条件。最终的容量配置是光伏 950 kW、储能 1.6 MWh、柴油机 250 kW。相比确定性解光伏增加了 150 kW储能增加了 0.4 MWh柴油机增加了 50 kW——这正是为了对抗最恶劣场景而付出的稳健性代价。代价换来的是即使全年所有时段都落在不确定集合的边界内系统也不会切负荷且年运行成本比确定性解的最坏情况下降了约 8%。4.3 储能与光伏参数交叉变化的灵敏度规律为了让配置结果对实际工程有参考价值我按不同参数水平做了一组归一化灵敏度实验。改变光伏波动幅度、储能的单位投资成本、配网交换功率上限观察最优容量配置的变化方向。结果有几个值得记住的规律。第一光伏波动幅度从 10% 升到 30% 时最优储能容量几乎线性增长但光伏容量变化很小。这是因为光伏出力波动并不能靠多装光伏解决只能靠储能平抑。第二储能单位投资成本下降 30% 时最优储能容量可能翻倍同时柴油机容量会显著减少——说明储能与柴油机之间存在明确的替代关系这种替代在鲁棒模型中比确定性模型中更强因为储能应对不确定性的能力比柴油机更灵活。第三配网交换功率从 300 kW 提到 500 kW总的装机容量会下降特别是储能容量下降明显但交换功率上限继续提升到 800 kW 后容量配置几乎不再变化说明配网交互对容量配置的影响存在一个饱和点。这些规律给工程项目的启发是在做微网容量配置之前优先去谈配网可用的交互功率余量这个参数对投资规模的影响往往被忽视。另一个容易被忽视的参数是储能的 SOC 上下限。如果为了延长电池寿命把 SOC 下限从 0.1 提到 0.3储能的可用容量变小CCG 迭代出来的配置会倾向多装储能或者加柴油机最终总成本可能上升 6%-9%。因此SOC 约束不应该照抄电池厂家给的推荐值而应该放到优化模型里作为可调参数做敏感性分析。5. 验证鲁棒解的三步走从不可行场景测试到 (x)-(u) 鲁棒性曲线两阶段鲁棒容量配置做完之后最忌讳直接拿结果去招标因为模型的自洽不代表工程的可信。我习惯做三步验证每步都能暴露模型里的隐藏问题。第一步是“极端场景回溯测试”。把 CCG 迭代过程中出现的最恶劣场景 (u^*) 提取出来固定该场景重新求解确定性运行优化验证每个时段所有约束是否严格满足特别是储能 SOC 是否在界限内、配网功率是否越限。如果出现越限多半是第二阶段子问题在提取最恶劣场景时遗漏了某些约束比如把 SOC 递推等式里的不确定参数代错了位置。这一步通常能抓到 80% 的建模错误。第二步是“蒙特卡洛模拟检验保守性”。从历史数据或典型概率分布中采样 1000 组全年光伏和负荷曲线把每个样本代入最终容量配置求解确定性运行经济调度或者直接用规则调度统计年运行成本和切负荷概率。对比确定性模型配置和两阶段鲁棒模型配置在同一批样本下的表现重点看两个指标平均运行成本和 95% 分位运行成本。鲁棒配置的平均成本会略高但 95% 分位成本应该明显更低这才是鲁棒性的价值所在。如果两者几乎没有区别说明不确定性集合太窄预算参数需要增大。第三步是绘制“(x)-(u) 鲁棒性曲线”来判断保守度是否适度。固定最终容量配置逐一改变不确定预算 (\Gamma) 从 0 到 24重新求解第二阶段最恶劣情形成本并记录该配置是否仍可行。画出来的曲线会呈现一个阶梯形当 (\Gamma) 超过某个临界值后原配置无法覆盖更恶劣的波动最恶劣场景下需要切负荷系统不可行。这个临界值对应的就是该配置的“鲁棒边界”。如果一个项目的实际波动水平在临界值以内说明配置留有余量如果临界值刚好和预计的极端情况重合说明配置恰好覆盖工程上建议留 20% 的余量可以适当增加储能来抬高边界。此外最后给出一个调参技巧CCG 收敛后不要急着结束把最终主问题的影子价格或对偶变量取出来找到哪些约束在限制最优容量——比如配网交互功率约束的影子价格很高就说明扩容配网比增加储能更划算。这一步用一句话说就是两阶段鲁棒优化不只是求一个容量结果它同时输出了一组“最稀缺的边界条件”那才是方案汇报里最有说服力的附件。本文还有配套的精品资源点击获取