2026/10/12 15:00:28

微电网多阶段鲁棒调度模型与MATLAB实现方法

微电网多阶段鲁棒调度模型与MATLAB实现方法 1. 微电网调度到底在解决什么问题1.1 可再生能源接入带来的新挑战这几年做微电网运行优化的朋友应该都有感受光伏、风电一多起来调度模型的复杂度就完全不一样了。传统的确定性调度思路——把光伏和风电出力当作已知参数直接代入——在天气好的时候还能凑合一旦云层飘过、风速突变母线电压和电量平衡就会出问题。我在实际项目里遇到过最典型的一次某天下午光伏出力在10分钟内从额定值的60%掉到15%前一天晚上算好的机组组合方案直接失效最后只能靠储能硬扛才没有造成重要负荷断电。也就是从那次起我把研究重心彻底转向了考虑不确定性的鲁棒优化方法。微电网调度的本质其实是在“用电需求、发电能力、储能状态”之间找一个最佳平衡点。当只有传统机组时负荷预测误差相对可控调度问题相对“静态”但可再生能源大规模接入后净负荷等于负荷减去风光出力的波动区间被急剧拉大。光伏的昼夜特性、风电的阵发性、负荷本身的随机波动叠加在一起任何一个环节预测失误都可能导致调度方案在执行时失去可行性。如果事先不考虑这些不确定性所谓的最优方案也许在纸面上很漂亮到现场却根本跑不动。1.2 为什么传统确定性优化不够用确定性优化追求的是“给定一组输入给出一个最优解”它默认输入是唯一的。但在真实微电网里光伏和风电出力根本不是一个固定数值而是一个带概率分布的随机过程。处理这种随机性大致有三条技术路线一是用随机规划stochastic programming通过大量场景模拟来逼近期望成本模型规模通常非常大二是用鲁棒优化robust optimization用一个不确定性集合刻画所有可能的出力区间优化目标是保证最坏情况下的安全性三是用模型预测控制MPC通过滚动优化不断修正误差但对预测模型的依赖比较强。我在这类复现工作和实际项目中用得最多的是鲁棒优化原因很简单微电网对安全性要求极高你不需要为所有场景的“平均表现”负责必须保证即使出现最不利的出力组合系统仍然能安全运行并尽可能经济。而多阶段鲁棒调度正是把这个问题从“单时点博弈”扩展成了“跨时段博弈”——储能的SOC会延续机组爬坡会延续昨天的决策直接影响今天的可行域。这种跨时段耦合如果不建模结果十有八九会失真。这也是为什么标题里专门强调“多阶段”它跟单纯的两阶段鲁棒优化有本质区别后面会详细展开。2. 多阶段鲁棒调度的数学模型设计2.1 两阶段与多阶段鲁棒的基本思想两阶段鲁棒优化的核心思路可以用一个很生活化的场景来理解你早上出门前决定带不带伞第一阶段决策等你看清天空乌云密布不确定性实现你决定是否在半路打车第二阶段决策。第一阶段决策必须现在就定下来第二阶段决策可以等看到实际情况后再调整但调整的前提是第一阶段的选择已经固定。如果第一阶段不带伞第二阶段雨停了你无所谓一旦下大了只能挨淋或者被迫打车付出的代价可能比带伞要大得多。在微电网调度里第一阶段决策往往是机组启停状态、储能充放电状态等“0-1变量”这些变量通常不能瞬间切换必须提前一天安排好第二阶段决策则是各机组和储能的出力水平可以在当日根据实际风光出力进行调节。两阶段鲁棒优化的目标是在固定第一阶段决策后搜索最坏情况下的不确定性出力场景让第二阶段最优调整成本最小。多阶段鲁棒multi-stage robust和两阶段的本质区别在于微电网运行不是“一日游”而是连续多日的接力赛。储能的SOC递推方程让每个时段的充电量直接变成下一时段的可用功率机组爬坡约束让上一时段出力和下一时段出力绑在一起。如果把每个时段都独立做一次两阶段鲁棒储能和机组的时间耦合就全部丢失了。多阶段鲁棒把整个调度周期比如24小时作为一个整体用跨时段的预算约束控制最坏场景的分布这是它比静态鲁棒更贴合实际的关键。2.2 目标函数与约束条件梳理一个典型的多阶段鲁棒调度模型目标函数通常包含以下几类成本传统机组的燃料成本二次函数线性化后的分段线性表达、机组启停成本、储能充放电退化成本、弃风弃光惩罚费用、切负荷惩罚费用。优化目标是让所有成本之和最小但在鲁棒框架下这个“最小”不是对单一预测场景说的而是对所有可能的不确定性组合中代价最坏的那一个场景来保证的。约束条件包含下面几大类每类都有自己的作用和坑功率平衡约束每个时段所有机组出力、储能放电、光伏风电出力之和等于负荷加储能充电功率。这是最基本的等式约束在不确定场景下需要写成对任意可能出现的不确定性出力都成立的形式。机组运行约束出力上下限、爬坡速率限制、最小启停时间等。其中爬坡约束和最小启停时间是典型的跨时段耦合约束在多阶段模型里不能省略。如果省略了爬坡约束调度方案可能要求机组在短短几分钟内从50 kW爬到300 kW现场根本执行不了。储能运行约束充放电功率上限、SOC上下限、SOC递推关系。储能约束是微电网多阶段调度里最关键的约束之一因为它最直观地展现了“这一个时段的决定如何影响下一个时段的可行域”。SOC递推通常写成SOC(t1) SOC(t) 充电功率×充电效率 - 放电功率/放电效率其中充电功率和放电功率不能同时为正。不确定性集合约束对于光伏和风电出力的预测误差用盒式不确定性集合刻画通常还会引入预算约束budget constraint限制最坏情况在所有时段的分布次数避免每个时段都同时取最坏值这种过度保守的假设。2.3 不确定性集合的构建方法不确定性集合的设计直接决定了鲁棒解的保守程度。常见的做法有以下几种盒式集合是最常用的入门选择。每个时段的光伏/风电出力在预测值的某个百分比区间内波动。比如光伏出力预测20 MW允许波动±20%那区间就是[16, 24] MW。这种集合建模最简单对偶变换容易处理。椭圆集合则用历史误差数据的协方差描述波动相关性约束形式更复杂但对数据的依赖更强数据量不够时效果反而不如盒式集合稳定。预算约束集合是在盒式集合基础上引入一个参数控制“最多多少个时段同时达到最坏情况”。比如预算量为10意味着24小时里最多10个小时可以同时取波动区间的端点值其余时段的不确定性取在区间内部。预算量的取值直接影响保守程度取值越大越保守、成本越高但安全性也越高。我在复现项目中通常推荐先用“盒式集合预算约束”的搭配原因很实际盒式集合建模简单、对偶变换容易处理预算约束又能有效调节保守度调试起来容易出结果。椭圆集合虽然理论上更精确但对误差协方差矩阵的估计要求高历史数据不够时计算出来的所谓“精确”反而会带偏调度结果。算法层面求解这种两阶段/多阶段鲁棒问题最主流的方法是CCGColumn and Constraint Generation列与约束生成算法。它的思路是把原问题拆成一个主问题和一个子问题主问题在给定已经发现的“最坏场景”子集上做优化得到一个候选方案子问题在固定这个候选方案后搜索所有可能的不确定性场景找出让系统代价最大的那个最坏场景然后把该场景对应的约束加入主问题继续迭代。这个过程重复进行直到主问题和子问题目标值之间的差距小于预设的容差。CCG为什么比传统的Benders对偶分解更受欢迎核心原因是子问题生成的约束针对性强、迭代收敛快。微电网调度里机组启停变量的存在本质上是个混合整数问题如果再用Benders生成割平面割的收敛速度往往很慢而CCG生成的约束直接对应一个具体的最坏场景信息量大很多。在实际算例中24时段的中等规模微电网模型用CCG通常二三十步就能收敛Benders则可能要上百步。3. MATLAB实现的核心要点3.1 求解工具选型与配置MATLAB做这类优化调度绕不开两个层面建模层和求解层。建模层我几乎只用免费工具箱YALMIP。它的好处是语法接近数学表达式把约束一行一行写下来代码跟论文公式几乎一一对应特别适合快速验证模型正确性。如果读者不想用YALMIP用MATLAB自带的optimproblem语法也可以但遇到大规模混合整数规划时表达效率会低一些。求解层需要区分情况。如果模型规模不大节点数少、时段少、没有太多二进制变量直接用MATLAB内置的intlinprog也能跑优点是零配置缺点是求解效率一般。对于稍具规模的模型强烈建议接入Gurobi或同级别的专业求解器。Gurobi在混合整数规划和LP子问题求解上优势明显尤其CCG迭代中反复求解LP子问题求解器的常数性能直接决定总耗时。在测试算例中同样一个24时段模型intlinprog可能要几分钟Gurobi往往几十秒就能收敛。我自己常用的搭配是YALMIP建模Gurobi求解MATLAB只做数据接口和结果可视化。这套组合在“完全复现”类项目里最稳因为你不需要自己写复杂的求解算法CCG主循环用MATLAB写内部每个子问题调用Gurobi即可。3.2 代码框架与关键函数设计一个典型的程序结构大致分五步。第一步是数据准备读取负荷数据、光伏/风电预测数据、设备参数机组出力上下限、爬坡率、储能容量、SOC上限下限、效率系数。所有参数集中放在一个结构体或脚本里方便修改。我习惯把所有原始数据单独放一个脚本主程序通过调用这个脚本获取所有参数这样后续调参时不用在一大段代码里翻来翻去。第二步是参数预处理将燃料成本线性化把二次函数转换为分段线性函数备用设定不确定性集合的波动幅度与预算量。这块虽然不起眼但特别容易出错。二次成本线性化的分段区间切分不当会造成求解结果与真实成本偏差很大。我一般会用10到20个分段区间来逼近精度就足够了。第三步是主问题构建定义第一阶段变量机组启停、储能状态以及第二阶段变量在各已生成最坏场景下的出力调整。目标函数是第一阶段成本与第二阶段所有已知场景成本之和约束包含机组运行约束、储能约束和功率平衡约束。主问题每迭代一次就新增一组对应于最新坏场景的约束所以变量和约束的维度是动态增加的。第四步是子问题构建固定第一阶段变量后对每个时段给定储能SOC轨迹和机组启停状态把不确定性场景的选择建模为max-min问题。内层对一台机组/储能/负荷做功率分配的LP优化外层搜索最坏场景。通常采用强对偶将内层LP并入外层问题转为单层max问题。第五步是CCG主循环主问题求解提取最优方案子问题求解判断收敛或生成新约束加入主问题继续迭代。这里有个非常关键的细节子问题里的“max-min”结构不能直接拿给Gurobi像普通模型那样暴力求解因为它是双层优化。正路是把内层min问题先转成其对偶max问题然后用强对偶定理将两个max合并成一个单层max-LP。这个操作要求内层问题必须是线性规划不能有二进制变量。如果内层由于机组组合变量出现整数麻烦就比较大了后面在常见问题里专门讲。3.3 求解效率优化技巧CCG的效率瓶颈通常出现在子问题的LP求解次数和主问题MILP规模膨胀上。几个实用的优化手段一是给子问题传冷启动值。每次CCG迭代时用上一轮的最优解作为新一次求解的初值可以显著减少求解器内部的单纯形迭代次数。在测试中这个优化能让子问题求解时间缩减30%以上。二是巧妙设置Gurobi的MIP gap。主问题内部迭代的MIP参数不必设得太苛刻比如gap设到0.1%甚至0.5%就够了因为外层CCG还有收敛控制。如果内外两层都要求高精度总耗时很容易翻倍。我见过很多新手把两层的容差都设成1e-6结果算法跑了两个小时还没结束其实就是浪费在无意义的精确求解上。三是预筛约束。在构建不确定性集合时利用“预算约束”直接把大量极端场景排除在外。比如24时段模型里预算设为6实际需要特殊考虑的时段组合数量是有限的通过组合预筛可以提前去掉那些根本不可能同时出现的极端组合减少子问题搜索维度。四是给储能模型做变量归一化。有时候储能SOC的数值范围很大比如0到1000 kWh而机组的出力范围只有几十kW量纲差距大会导致求解器数值不稳定。把储能相关变量统一归一化到0~1区间或者以单位容量的SOC百分比作为变量能明显改善收敛表现。这个方法在求解器内部其实只是做了一个线性变换但能有效减少数值病态问题。4. 算例分析与结果解读4.1 测试系统设置为了说清楚多阶段鲁棒调度的效果我构造一个典型的区域微电网测试系统规模不大但结构完整包含1台传统柴油机组、一组光伏电站额定60 kW、一组风机额定40 kW、一套储能系统额定容量300 kWh最大充放电功率60 kW以及一条连接配电网的联络线允许在应急情况下从外部购电但购电价格较高。所有节点简化成单母线模型负荷取自某实际园区的一日负荷曲线考虑光伏和风电预测误差分别在±20%和±25%范围内波动。对比方案设三个方案A确定性优化光伏和风电出力直接取预测值不做误差建模。方案B静态鲁棒优化每个时段的光伏/风电出力独立在盒式区间内波动允许所有时段同时取最坏值但没有跨时段预算约束。方案C多阶段鲁棒优化采用盒式预算约束预算量设为8储能SOC和机组爬坡跨时段耦合完整建模。所有方案都使用同一个负荷数据和同一组设备参数保证对比只反映调度策略本身的差异。求解时统一使用YALMIPGurobi所有模型均在个人电脑上运行完成。4.2 不同方案下的调度结果对比先说结论。方案A算出来的总运行成本最低但它的“最优”建立在预测完全准确的假设之上。我特意在所有算例里模拟了一次“最坏出现”——第12~16时段正午之后光伏出力大幅低于预测值风机出力也偏低。这种情况下方案A给出的机组组合和储能充放电计划完全失效系统需要切负荷来维持平衡最坏场景代价极高。方案B的安全性最好但成本也最高。因为它默认每个时段都可能同时出现最坏出力储能在放电安排上非常克制机组全天保持较高的出力裕度几乎失去了经济性。这种方案在成本上比方案C高出约12%~15%而且在部分时段出现了大量弃风弃光——为了“防御”并不实际发生的最坏场景白白丢了本可以消纳的绿色电量。方案C是三者中平衡性最好的。由于预算约束限制了最坏场景的时段数量储能可以在不确定性尚未集中爆发的某些时段充电储备在可能出现低出力时段集体放电支援。算例结果显示方案C的总成本比方案B低约12%同时在最坏场景下的切负荷量控制在可接受范围内大约只有负荷总量的0.5%。最关键的是储能SOC轨迹是连续合理的说明多阶段的跨时段耦合建模确实起了作用而没有预算约束的方案B则因为过度防御储能SOC测试全程大部分时间保持在90%以上实际上把自己变成了“只放不充”的应急电源完全没有发挥储能的容量价值。指标方案A确定性方案B静态鲁棒方案C多阶段鲁棒总成本基准单位100132118最坏场景切负荷量高计划失效低中低弃风弃光总量少多中全天成本波动幅度大小中计算耗时秒级分钟级分钟级这个对比表很直观地说明了一个问题鲁棒优化的价值在于“用可接受的成本冗余换取可靠性”但这个冗余成本需要控制。没有预算约束的静态鲁棒就像给所有人同时买最高配保险成本必然虚高多阶段鲁棒则像按风险分布精准投保该保的保、不该保的不保经济性和安全性才能真正兼顾。4.3 储能与可再生能源的协同优化这个算例里最值得琢磨的是储能的作用。很多人以为只要在微电网里装了储能不确定性就自动被“吸收”了其实完全不是。储能只能缓解部分不确定性矛盾而且储能的可用容量本身就是有限的资源——如果你在同一时段把它放光了下一时段出现低风光时你就只能切负荷或者高价购电。多阶段鲁棒优化的一大价值就是它能根据不确定性预算合理分配储能的充放电时机把最宝贵的容量安排在“最可能出问题”的时段。在方案C的SOC轨迹中可以看到一个很有趣的现象储能会在夜间低负荷时段主动充电把SOC拉到80%左右然后在上午和傍晚负荷高峰时段有序放电。当预算约束不允许“所有时段同时最坏”时模型选择了让储能“分时分段”去应对不确定性而不是一天到晚紧绷着。这种策略既保证了安全性又保住了经济性。在实际项目中我还经常把“储能寿命损耗成本”纳入目标函数——充放电循环越多电池衰减越快。用鲁棒模型算出来的储能出力曲线通常比确定性模型更平滑因为它减少了不必要的频繁深度充放电这对于实际部署的储能系统运维是实打实的好处。折算成项目收益延长电池寿命带来的收益可能比调度成本优化本身还高。5. 开发过程中踩过的坑与排查经验5.1 收敛性问题的排查跑CCG最常见的问题是算法不收敛或迭代到极限代数仍然无法满足收敛条件。如果遇到这种情况别急着加迭代次数先按这几步排查。第一检查子问题是否确实找到了“比当前更坏”的场景。如果子问题返回的最坏场景目标值和当前主问题下界差距很小说明其实已经收敛只是容差设置太严。把CCG的外层容差从1e-6放宽到1e-3结果往往立刻正常。第二检查对偶问题是否写对。很多刚接触CCG的开发者会把子问题对偶搞错导致双目标值不一致。一个简单验证方法取一个固定的不确定性场景分别用原LP和转换后的max-LP求解对比最优值是否一致。不一致就说明对偶变换过程有误需要重新推导。这个步骤虽然费几分钟但能省下后面一整天的排查时间。第三检查是否有数值病态。储能SOC这类大数值变量配上机组出力量纲很容易让求解器精度失效。我踩过最典型的坑是SOC上限设为300而机组出力只有几十kW计算结果直接出现SOC递推不守恒。解决方法是归一化变量把SOC和充放电功率全部转化为以“百分比”或“等效小时数”为单位。5.2 结果不合理的排查定位如果算出来的鲁棒调度结果看起来“太傻”——比如储能明明可以在低谷电价时段充电却一点不动或者机组出力整天贴着上限最可能的原因是约束条件写得太紧或写错了方向。常见的错误有两类。一是SOC递推公式里的符号方向搞反了。有些模型把充电功率定义为正值、放电功率定义为负值有些则反过来如果在约束里混用算出来的SOC会越跑越大甚至在一天结束时还剩下不合理的电量。二是充放电效率处理不当。储能充电时从电网吸收1 kWh实际存入电池的可能只有0.9 kWh考虑充电效率放电时电池放出1 kWh实际向电网发出的可能只有0.9 kWh。有些简化模型只用一个效率系数导致能量不守恒长时间的动态模拟误差会被累积放大。另一个容易忽略的点是旋转备用约束和不确定性集合之间的交互。如果备用约束要求“即使光伏完全不出力系统仍能维持功率平衡”那不确定性集合里光伏波动区间设得再大也没有意义因为最坏情况已经被备用约束提前覆盖了。这两种不确定性表达方式不应同时过于保守否则总成本必然被抬高而且这样的结果在实际工程中也没多大参考价值。5.3 对偶变换的常见错误前面提到CCG的子问题本质是一个max-min双层结构。处理它的标准手段是把内层min问题对偶化为max再与外层max合并变成一个单层的max-LP。这个操作听起来简单实际操作中有几个极易犯的错。一是内层LP必须写成标准形式。变量上下限、等式约束都必须显式写出来缺一个约束对偶就会少一个变量结果就完全不对。很多复制论文代码失败的案例问题就出在等式约束漏项。二强对偶的前提是内层可行且有界。如果子问题在某个不确定性场景下出现了不可行比如极端情况下功率平衡无法满足强对偶就不成立需要先引入辅助变量或惩罚项处理不可行性。三是离散变量进入内层的问题。如果子问题的内层变量包含机组启停这样的二进制变量那就不是简单LP了不能直接用对偶。这种情况下常见做法有两种一是把所有机组启停变量也放到一阶段决策子问题内层只保留连续变量二是对含离散变量的子问题做“big-M”转换加入惩罚项。前者建模干净后者实现复杂但对模型规模的限制更少。5.4 实用的调试经验速查我把平时调试这类模型时常用的排查经验整理成一个简单的对照表供大家日常参考现象可能原因排查方法CCG迭代不收敛对偶变换错误、容差过严用固定场景校验对偶、放宽容差储能SOC越界或异常SOC递推符号/效率处理错误检查正负号约定打印逐时段SOC结果过度保守预算量过大或备用与不确定集合叠加调整预算量、检查约束冗余子问题不可行功率平衡约束无解加切负荷/购电辅助变量惩罚求解速度太慢主问题MILP规模过大放宽内层MIP gap、加冷启动这份对照表是我自己做项目时根据踩坑记录整理出来的。每次遇到模型结果不对先对照这张表排除最常见的几个问题能省去大量无目的试错时间。尤其建议初学CCG的朋友第一次写完代码后先用一个很小的算例比如3个时段验证模型然后逐步扩时段数。小规模算例可以直接手算验证结果是否正确等到小算例确认无误再放大规模成功率会高很多。现在回想整个开发过程最深刻的体会是多阶段鲁棒调度不是一个“调好一个高深的模型”就结束的任务它要求你在每个环节都保持清醒——不确定性集合参数调得太保守成本就虚高SOC模型写得不严谨结果就完全不可信。我个人通常建议先跑确定性模型摸基线再加盒式不确定集合做静态鲁棒最后才上多阶段模型。这个三步递进的过程看似多花了一点时间但调试效率远高于一步到位因为你随时知道每个环节引入了多少偏差。最后再分享一个小技巧做完模型后一定要做一个“最坏场景复盘”。把鲁棒模型预测的极端场景拿出来和真实历史中的极端天气数据做对比看模型识别出的最坏场景是否符合工程直觉。如果模型说最坏情况发生在后半夜而历史数据里后半夜根本没出过极端低风况说明你的不确定性集合或预测误差分布设置出了问题——这种复盘往往能省掉大量现场调试时间。这个项目后续还能往两个方向扩展一是把单微网的鲁棒调度扩展到多微网互联让不同微网之间通过联络线共享储能余量二是把鲁棒优化和模型预测控制结合日前调度的同时保留日内滚动修正的能力。这两个方向我都在陆续做测试等有完整结果了再跟各位分享。