简介这套代码面向微电网规划与电气工程研究者解决含风电、光伏、储能及燃气轮机的多电源容量配置问题。程序基于两阶段鲁棒优化方法一阶段决策储能、风电和光伏的安装容量二阶段在不确定性场景下优化各机组实际出力兼顾经济性与可靠性最终输出容量配置结果及各电源运行出力情况仿真采用YALMIPCPLEX求解适合需要掌握两阶段鲁棒规划建模的进阶学习者。资源包共426个文件压缩包大小93.72MB包含276个xls结果表格、110个mat数据文件、8个csv数据文件、6个docx说明文档以及5个m源程序文件等类型覆盖源码、数据、文档与图表便于按需查阅。目前已有242人学习下载。店主自编了非常细致的参考文档并配有实现效果截图可帮助读者快速理解模型构建、参数设置与求解流程直接用于相关课题研究、毕业设计或项目复现。1. 两阶段鲁棒容量配置微网多电源规划为什么要看最坏场景配电网里做微网规划的人最先碰到的矛盾往往是光伏和风电的容量值很容易算配多少都行可一旦并网运行出力波动立刻让储能和燃气轮机的配置变得尴尬——储能配少了夜间风电大发时段扛不住燃气轮机配大了全年利用小时数低到无法回本。确定性优化在这里的失败不是算法问题而是场景覆盖问题单组典型日曲线替代不了真实天气过程的连续相关性。两阶段鲁棒优化算法解决的是这一类“先定容量、再看出力”的决策链问题。它把风电、光伏、储能和燃气轮机的容量规划作为第一阶段变量把不确定出力下各机组的最优运行方案作为第二阶段变量通过发掘最坏场景来压缩配置冗余。这套MATLAB代码基于YALMIPCPLEX实现行列生成算法面向的是微网容量配置的工程验证也适合做含不确定性的新能源规划课题基底。以下按模型、编码、数据、校验四层拆开讲。2. 盒式不确定集与CCG求解框架容量配置的两阶段鲁棒模型两阶段鲁棒优化的核心不是“多跑几次随机模拟”而是把不确定性建模成集合再在这个集合里找最坏情况做决策。微网容量配置里常见的做法是盒式不确定集即每个不确定参数只在上下界之间波动同时用一个预算约束限制同时波动的参数个数避免最坏场景过于极端而失真。2.1 一阶段与二阶段变量的划分逻辑一阶段变量是配置决策包括风电安装容量、光伏安装容量、储能额定容量与额定功率、燃气轮机装机容量。这些变量在优化开始前是自由变量一旦确定就贯穿整个运行周期不随天气场景变化。二阶段变量是运行决策包括逐时段的风电实际出力、光伏实际出力、储能充放电功率、燃气轮机出力、弃风弃光量、切负荷量以及微网与外部电网的交换功率。二阶段问题在每个不确定场景下都会重新求解反映“配置已定、运行随动”的物理关系。这种划分的价值在于一阶段决策被迫对所有可能场景负责而不是只对期望场景负责。目标函数的一阶段项是投资成本二阶段项是运行成本两阶段鲁棒优化的目标是让最坏场景下的总成本最小化。2.2 不确定集与预算参数的数学描述考虑风电和光伏的出力不确定性不确定参数集合可以写成U { u | u_min ≤ u ≤ u_max, Σ |u_t - u_forecast_t| / (u_max_t - u_min_t) ≤ Γ }其中Γ为鲁棒预算控制波动最不利时段的数量。Γ0时退化为确定性模型Γ取满为最保守场景即所有时段都处于最坏情况。对容量配置而言当储能容量相对小时通常不建议Γ取满否则燃气轮机配置会异常偏大投资回收期显著拉长。参数含义对结果的影响方向Γ鲁棒预算限制同时波动的时段数Γ越大风光配置越保守燃气轮机容量与储能容量上升风电预测误差边界各时段风功率波动上限边界越宽储能配置越高光伏预测误差边界各时段光功率波动上限边界越宽弃光惩罚成本越高储能SOC上下限决定储能可用调节区间区间越窄燃气轮机出力峰谷差越大2.3 CCG行列生成的主从问题结构求解两阶段鲁棒优化通常不直接使用通用求解器因为第二阶段是max-min结构YALMIP无法直接处理。常见做法是使用列与约束生成算法核心思路是把主问题MP和子问题SP交替迭代求解。主问题是在已知的有限场景集合上求解一阶段配置和对应运行成本的联合优化给出决策下界。子问题是固定一阶段决策后在当前不确定集中寻找使运行成本最大的场景即最坏场景并向主问题返回新场景和对应约束。CCG相比Benders分解的优势是每次迭代向主问题添加的是完整场景约束而不是割平面收敛速度在容量配置问题上通常显著更快。迭代收敛判据为主问题上界与下界间隙小于设定阈值常见阈值取1%或0.5%。MP: min c^T x η s.t. η ≥ d^T y_k g^T z_k, k 1..K F x G y_k H z_k ≤ h, k 1..K SP: max (d^T y g^T z) s.t. G y H z ≤ h - F x* y, z ∈ 运行可行域, u ∈ U主问题中η替代二阶段成本k表示已发现的不确定场景索引子问题在给定配置x*下求解最坏场景的运行成本。实际编码时子问题需要通过强对偶或KKT条件转化为单层优化问题这是实现中最容易出现错误的环节。3. YALMIPCPLEX实现行列生成算法的MATLAB编码要点YALMIP在这套代码里的角色是建模语言层CPLEX作为底层MIP求解器。两阶段鲁棒优化的编码难点不在求解器调用而在主问题与子问题的数据流衔接以及子问题对偶转换后约束的拼装。3.1 主问题建模与场景集迭代主问题采用YALMIP的optimize直接求解。需要维护一个场景集每次CCG迭代向场景集中追加新场景。% 主问题场景集 I 中每个场景对应一组二阶段变量 x_wind sdpvar(1, 1); % 风电装机容量 x_pv sdpvar(1, 1); % 光伏装机容量 x_ess sdpvar(1, 1); % 储能容量 x_gt sdpvar(1, 1); % 燃气轮机容量 eta sdpvar(1, 1); % 二阶段成本代理变量 Constraints []; OperCost 0; for k 1:length(MP_Scenarios) % 每个场景创建独立的运行变量 y_gt sdpvar(T, 1); % 燃气轮机逐时出力 y_ess sdpvar(T, 1); % 储能逐时充放电 y_curt sdpvar(T, 1); % 弃风弃光量 % 功率平衡约束 Constraints [Constraints, ... y_gt y_ess MP_Scenarios{k}.wind * x_wind ... MP_Scenarios{k}.pv * x_pv y_curt Load_profile]; % 二阶段成本进入 eta 的约束链 OperCost OperCost sum(y_gt) sum(y_ess); end Constraints [Constraints, eta OperCost];这段代码中MP_Scenarios{k}是结构体数组存储第k个场景下的风电和光伏出力系数。每个场景独立创建运行变量这是CCG主问题的关键结构——场景之间通过共享一阶段变量耦合但运行变量彼此独立因此主问题规模会随迭代次数线性增长需要监控求解时间。3.2 子问题对偶转换与最坏场景识别子问题的原始形式是max-min双层结构无法直接交给CPLEX。常见做法是通过强对偶定理将内层min问题转换为对偶约束使子问题变成单层max问题。转换后的子问题包含连续不确定变量u与对偶变量的乘积项属于双线性项需要引入大M法线性化。% 子问题固定一阶段变量后求解最坏场景 x_fixed value([x_wind; x_pv; x_ess; x_gt]); % 不确定变量风电与光伏逐时出力系数 u_wind sdpvar(T, 1); u_pv sdpvar(T, 1); Constraints [u_wind wind_forecast - wind_dev, ... u_wind wind_forecast wind_dev, ... u_pv pv_forecast - pv_dev, ... u_pv pv_forecast pv_dev, ... sum(abs(u_wind - wind_forecast) ./ wind_dev) ... sum(abs(u_pv - pv_forecast) ./ pv_dev) Gamma]; % 二阶段运行约束 对偶约束拼装 [SP_obj, SP_constraints] build_sp_with_dual(u_wind, u_pv, x_fixed); % 求解双层转化后的单层问题 optimize(SP_constraints, -SP_obj, sdpsettings(solver, cplex));子问题返回的目标值作为上界同时提取最坏场景下的u_wind和u_pv作为新场景追加到主问题。这个过程中要特别注意对偶转换要求内层问题是线性规划储能SOC递推约束和燃气轮机爬坡约束都必须保证线性任何min/max表达式都要提前展开为线性约束。3.3 CPLEX参数设置与求解效率平衡两阶段鲁棒问题的计算瓶颈在主问题规模尤其是储能SOC跨时段约束使每个场景的约束矩阵变宽。实际编码时我一般会设置CPLEX的MIP间隙为0.1%并开启并行模式同时对主问题的运行变量设置合理的起始解以加速分支定界。options sdpsettings(solver, cplex, ... cplex.mip.tolerances.mipgap, 0.001, ... cplex.parallel.mode, 1, ... cplex.mip.limits.times, 3600, ... verbose, 2);mipgap设0.001表示允许0.1%的MIP间隙对容量配置问题足够times限制单次CPLEX求解最长3600秒防止CCG迭代中某个子问题卡死。如果发现单次求解时间过长优先检查是否有非线性的min/max约束混入其次是检查对偶变量与大M常数的边界范围是否过宽。4. 数据对齐与Gamma调参历史负荷气象数据如何进入鲁棒模型这套代码的输入数据是多个CSV文件分别承担负荷、气象、基准场景和权重等角色。数据使用的方式直接影响鲁棒模型的保守度这里最容易踩坑的不是算法而是数据对齐。4.1 数据文件角色划分与字段对齐Load_history.csv存放历史负荷时间序列temperature_history.csv是温度数据zhenjiang_power.csv和Tianchi_power.csv分别是镇江与天池区域的实测功率数据Benchmark.csv是基准场景数据weights.csv是场景权重test.csv是测试集输入格式submission_template.csv是结果输出模板。这些文件里的时间戳格式可能不一致需要统一为相同的时间索引% 统一时间戳并进行插值对齐 load_hist readtable(Load_history.csv); temp_hist readtable(temperature_history.csv); power_zj readtable(zhenjiang_power.csv); % 统一按15分钟粒度重采样 time_ref (datetime(2023, 1, 1): minutes(15): datetime(2023, 12, 31, 23, 45)); load_aligned interp1(load_hist.time, load_hist.load, time_ref, linear);数据对齐的核心是采样粒度和时区一致性。15分钟粒度下一天96个点一年35040个点如果某个数据源是小时粒度直接interp1线性插值会平滑掉峰谷特征导致负荷峰谷差被低估最终容量配置偏小。遇到这种情况我一般先用retime做聚合检查确认插值前后峰谷差不失真。4.2 风电光伏预测误差边界的估计方法两阶段鲁棒模型中不确定集的上下界不能拍脑袋定通常由历史预测误差的统计分位数给出。常见做法是以预测值为中心取历史误差的5%和95%分位数作为上下界。% 计算风电出力预测误差边界 wind_err wind_actual - wind_forecast; wind_dev_low quantile(wind_err, 0.05); wind_dev_high quantile(wind_err, 0.95); % 构造不确定集边界 wind_dev max(abs(wind_dev_low), abs(wind_dev_high));这里用的是对称边界。从工程角度看风电出力预测误差分布往往左偏即实际出力低于预测值的情况更多因此对称边界会让模型对“高估风功率”的场景覆盖不足。更稳妥的方式是分别统计上下行边界但对称边界在CCG框架下可以简化对偶乘子的取值范围所以不少实现仍然采用对称处理。4.3 权重、基准场景与竞赛提交流程Benchmark.csv是确定性基准下的运行结果weights.csv是不同场景的加权因子。两阶段鲁棒优化的最终输出需要与基准场景做价格或成本对比时按权重加权汇总即可。submission_template.csv规定了输出字段的格式其中必须包含各电源容量配置值和典型日逐时出力矩阵。% 输出结果到提交模板 results_table table({wind_capacity; pv_capacity; ... ess_capacity; gt_capacity}, ... [x_wind_opt; x_pv_opt; x_ess_opt; x_gt_opt], ... VariableNames, {item, value}); writetable(results_table, my_result.csv);微网与外部电网的交换功率是容量配置的隐藏约束。如果微网允许从外部电网购电那么容量配置结果会明显偏向于减少储能和燃气轮机如果外部电网交互受限则储能容量会显著上升。建议在求解前先确认模型中是否包含联络线功率上限约束这直接影响结果的工程可用性。5. 风光燃储四种电源鲁棒出力的校验技巧两阶段鲁棒优化跑完后不能只看容量配置结果就收工。需要验证鲁棒解的有效性和保守程度这里给出几个工程上常用的校验手段。5.1 最优性间隙曲线检查CCG的收敛过程应输出下界主问题目标和上界子问题目标随迭代次数的变化。正常情况下下界单调上升上界单调下降两者逐渐逼近。如果出现上界振荡通常是子问题对偶转换后漏掉了某类约束如果下界长时间不变而上界持续波动主问题需要添加更多约束检查预算约束是否真正生效。5.2 与确定性解的保守度对比在相同数据上运行Γ0的确定性模型对比储能容量差异方案风电容量(MW)光伏容量(MW)储能容量(MWh)燃气轮机(MW)确定性18.212.68.44.2鲁棒Γ217.111.812.55.8鲁棒Γ416.311.016.27.4容量配置比例和具体数值仅作示例说明趋势。鲁棒配置下风光容量略降、储能与燃气轮机容量上升这是符合预期的交换关系。如果出现风光容量反而上升的情况检查是否因为功率平衡约束方向写反或者供需两侧不确定性符号设置错误。5.3 微网与外部电网电力调控的延伸消纳校验容量配置结束后将得到的容量值代入历史真实天气序列做全年8760小时模拟统计弃风弃光率、切负荷率和联络线功率越限次数。这套校验逻辑与数学建模国赛中的微网与外部电力交互场景高度一致核心是确认鲁棒配置在实际运行中不存在极端但未被模型覆盖的运行状态。% 全年模拟校验 for t 1:8760 % 取历史实际风电、光伏出力 wind_real wind_actual(t) * x_wind_opt; pv_real pv_actual(t) * x_pv_opt; % 计算净负荷 net_load load_actual(t) - wind_real - pv_real; % 储能配合燃气轮机平衡净负荷不足时记录切负荷 if net_load ess_power_max gt_capacity shed_energy(t) net_load - ess_power_max - gt_capacity; end end shed_ratio sum(shed_energy) / sum(load_actual);最后检查全年切负荷率是否在可接受范围内并对照子问题输出的最坏场景出力曲线确认储能SOC没有长时间触达边界。两阶段鲁棒优化结果在工程上是否可接受最重要的判断依据不是间隙收敛到多小而是配置结果放到真实历史数据中不“露馅”——这两者之间往往存在不小差距也正是这个模型需要反复调试的地方。本文还有配套的精品资源点击获取
