资讯动态

风电不确定性下基于DRO-LDR的机组组合Matlab实现

发布时间:2026/10/22 11:34:52 来源:尧图企业网站定制
风电出力的不确定性是机组组合Unit Commitment里绕不开的一座山。电网调度给风电一个预测出力但实际风况根本不是那个值波动起来可能相差很大。传统做法要么把风电当成确定的点值要么用一堆场景去逼近真实分布。前者在低谷负荷时容易低估风险后者在分布估计不准时会过度自信。这几年我一直在做电力系统调度优化相关的课题发现“分布鲁棒优化”Distributionally Robust Optimization, DRO在机组组合这个场景里恰好能走出一条中间路线不需要精确知道风电出力的真实分布只需要给定一个“分布可能落在哪个范围”的模糊集然后在这个模糊集内找最坏情况下的最优调度方案。而项目标题里的“线性准则”对应的就是线性决策规则Linear Decision Rule, LDR——把第二阶段出力调整量写成不确定参数的仿射函数。这个组合做出来的Matlab代码既能处理分布不确定性又不至于让模型变成无法求解的黑洞。这篇文章面向的是正在做机组组合、风电调度、分布鲁棒相关课题的研究生和工程师。如果你已经熟悉基础UC模型但对DRO和LDR怎么落地到代码有疑问这篇内容可以直接给你一套可复现的路径从模型推导到MatlabYALMIP实现再到模糊集参数怎么调、求解效率怎么优化。我会把我实际调试这段代码时踩过的坑也一并写出来。1. 为什么机组组合必须正面处理风电不确定性1.1 传统确定性UC被忽略的方差代价机组组合问题的经典形态是在未来一段时间比如24小时内决定每台机组在每个时段开还是不开以及开机机组的出力水平使得总成本最低同时满足负荷需求、备用要求和机组自身的技术约束。这个决策是典型的0-1混合整数规划每一步都要权衡启停成本和运行成本。但引入风电之后事情变复杂了因为风电预测值只是一个“期望”真实出力围绕它展开一个分布。我刚开始接触UC时一度觉得把风电预测出力直接塞进等式约束就行了顶多再留一个备用容量。这种确定性处理方式在风电渗透率低的时候还能凑合但风电占比一旦上去问题就暴露得很明显预测偏高的时段实际出力不足需要机组快速爬坡补上缺口预测偏低的时段实际出力反超只能弃风。无论哪种情况都在消耗额外的调节成本。确定性UC从不考虑这些“方差成本”它只对一个假设的风电出力点负责真实世界不按这个点出牌代价就是实际运行时的偏差成本和潜在失负荷风险。1.2 随机规划与鲁棒优化两种思路的代价面对不确定性最常见的两个工具是随机规划Stochastic Programming和鲁棒优化Robust Optimization。随机规划的做法是给风电出力假设一个概率分布然后用抽样生成的场景去逼近这个分布。每一组场景对应一个第二阶段决策目标函数是所有场景下期望成本的最小化。这种做法理论上很漂亮但有两个痛点。第一你假设的分布未必是真实分布。风电出力的概率密度往往带有偏态和厚尾用正态分布去近似低估极端情况是常有的事。第二场景数量太少分布逼近效果差场景数量一大决策变量和约束规模爆炸混合整数问题的求解耗时就上去了实际应用里经常面临算不动的问题。鲁棒优化的思路则完全相反它不问分布只定义一个不确定集合比如风电出力落在某个区间内然后要求在这个集合的最坏情况下调度方案依然可行。这种方案对分布估计误差完全免疫但代价是极其保守。因为它在集合边界处做文章相当于把所有场景都当作概率相等的极端情况来处理结果往往是备用容量开得特别足机组组合方案花钱多、经济性差。两张思路的对比很直观随机规划把宝押在“分布假设正确”上鲁棒优化则对分布信息“完全放弃”。两个极端之间确实缺一个既能用上分布信息、又不依赖精确分布的方案。1.3 分布鲁棒优化不确定的是“分布”本身分布鲁棒优化DRO的思路很直接真实分布不知道但我可以用历史数据造一个经验分布然后规定真实分布必须落在一个以经验分布为中心的模糊集里。这个模糊集的半径代表我对经验分布的不信任程度。优化的时候目标函数是模糊集内所有分布下期望成本的最大值最坏情况期望作为代价最小的机组组合方案。换个说法随机规划在“已知分布”下做期望优化鲁棒优化在“最不利场景”下做极小极大优化而分布鲁棒优化在“最不利分布”下做极小极大期望优化。它比随机规划更稳健比鲁棒规划更经济也更有理论保障——只要模糊集半径设置合理真实分布以很高概率被包含在内那么算出来的方案在实际中就有界。这个折中思路在风电UC场景下特别实用。因为风电预测误差分布本身不稳定不同季节、不同天气过程下差异很大想精确建模非常难。但DRO只需要给一个“误差不会超出一定范围”的模糊集这比精确分布容易获得得多。掉头回来再看“线性准则”真实调度中第二阶段出力调整量需要针对每一时刻的具体风电出力做出响应如果让这个响应函数有任意形式问题就变成一个无穷维优化无法直接求解。线性决策规则LDR把“响应函数”限制为不确定参数的仿射函数这样就把问题从“寻函数”降维成“寻系数”在可解性和保真度之间取得了平衡。这也正是分布鲁棒机组组合能落地到代码的关键所在。2. 把分布放进机组组合模型到底长什么样2.1 两阶段UC模型的完整数学形态分布鲁棒机组组合的标准建模方式是两阶段。第一阶段解决机组启停问题决策变量是各时段机组开/停状态u(i,t)、启动动作s(i,t)、停机动作z(i,t)这一阶段必须提前确定因为这些决策在实时调度前就要定下来。第二阶段解决经济调度问题给定第一阶段的启停方案和实际风电出力的观测值决策各机组实际出力、切负荷量和弃风量这一阶段可以“看着风电出力再调整”。目标函数也由此分为两部分第一阶段是确定性的开机成本和燃料成本第二阶段是调整成本包括再调度成本和切负荷惩罚。由于第二阶段发生在看到风电出力之后成本大小取决于风电出力的实际分布所以在DRO框架下第二阶段成本是一个“最坏分布下的期望值”。整个模型写成min第一阶段成本 第二阶段DRO成本这里第二阶段DRO成本可以写成一个嵌套的优化问题外层是机组组合变量内层是给定启停方案后先求每个场景下的最优调整成本再在模糊集内求这些调整成本的最坏期望。如果不做任何近似处理这个内层问题的维度和场景规模成正比求解复杂度极高。后面引入线性决策规则就是为了把这个内层问题转成有限维凸优化。2.2 模糊集的两种主流配方模糊集是DRO模型里最核心的组件它的设计直接决定模型的保守程度和求解难度。目前最常见的两种配方是矩模糊集和Wasserstein模糊集。矩模糊集约束的是分布的一阶矩和二阶矩比如规定真实分布的期望向量和协方差矩阵必须在经验分布估计值的某个邻域内。这种做法对“分布形状”不做要求只限定均值和协方差可行分布族比较宽泛保守度适中。对偶之后问题会引入半定规划SDP约束因为协方差矩阵的半正定性质带进来一个矩阵不等式。Wasserstein模糊集则按“分布与经验分布之间的Wasserstein距离不超过一个半径”来定义。它的好处是求对偶时相对干净而且当不确定参数维度不高时Wasserstein半径可以根据场景数量和历史数据量做一个理论校准数据少就把半径调大数据多就把半径调小。这两种配方在Matlab实现上难度差别不大主要看YALMIP用哪种约束类型来表述矩模糊集对应SDP约束Wasserstein模糊集对应一组带范数约束的线性表达式。2.3 线性决策规则把函数降维成系数第二阶段调度方案如果写成“机组出力调整随风电出力向量任意变化”那每个场景都要单独优化一组决策变量场景一多变量数量爆炸。LDR的核心思想很简单假设第二阶段决策变量y是不确定参数ξ的仿射函数即y(ξ) y0 Yξ其中y0是基准出力Y是一个系数矩阵。这样一来无论ξ取什么值调整量都可以由一组固定的系数线性生成不再需要为每个场景单独设变量。只要确定了y0和Y就能响应所有可能的场景。LDR在分布鲁棒调度中的合理性可以从工程角度理解风电预测误差相对总装机来说通常是中等偏差再调度时的出力调整量在预测点附近表现近似线性仿射函数能比较好地逼近真实最优调整策略同时因为LDR把所有可行的调整策略限制在一个子集里得到的解是原问题的最优解的一个上界也就是说方案是可行的只是成本可能略高于“完全灵活”的方案。替换进DRO模型之后第二阶段的对偶变量和矩阵运算会落在仿射系数上。模糊集取矩约束时可以用SDP对偶把最坏期望转成一个带松弛矩阵的线性矩阵不等式模糊集取Wasserstein时第二阶段的期望项会转成有限个场景的最坏成本加一个半径相关的正则项。无论走哪条路原问题最终都能写成“混合整数线性/半定规划”的标准形式交给求解器处理。3. Matlab代码实现从模型到可运行代码的关键步骤3.1 工具链选型YALMIP求解器复现这类DRO机组组合代码我目前比较顺手的组合是Matlab YALMIP Gurobi线性部分 Mosek半定部分。YALMIP提供符号化的建模语言能直接声明sdpvar变量、binary变量和约束不用手动推导对偶问题的系数矩阵Mosek对SDP和二次锥规划的处理效率高一些Gurobi则擅长处理混合整数线性规划的底层求解。模糊集选矩约束时最坏期望对偶后会带矩阵变量和线性矩阵不等式LMI约束用sdpvar声明一个矩阵变量塞进约束集YALMIP会识别成SDP选Wasserstein模糊集时问题可以一直保持线性约束用Gurobi就够了。需要注意的一点是YALMIP的变量声明要区分连续变量和有理整数变量。机组启停是binvar实际出力、切负荷量、弃风量是sdpvar仿射系数矩阵Y也用sdpvar。仿真脚本里要把约束按类型分组线性约束用normal形式的constraintSDP约束用lmi形式混在一起YALMIP也能自动分拣但工程上习惯分开写排查问题快得多。3.2 基础数据准备场景与机组参数代码跑通前先把三份数据准备好。第一份是系统负荷数据24小时或96点的负荷曲线单位MW。第二份是常规机组参数表包括最大/最小出力、爬坡速率、最小启停时间、燃料成本系数、启停成本以及备用贡献系数。这里用的是某标准6节点测试系统的公开参数和IEEE标准算例对比更有说服力。第三份是风电出力场景。场景可以从历史运行数据中抽取也可以用一个自回归模型模拟生成推荐直接用预测误差的历史样本比如风速预测值和实测值的差转成风电出力偏差场景。场景数量一开始不必追求多100-200个足够让经验分布稳定重点是对每个场景都要记录对应的风电预测偏差值偏差的均值向量和协方差矩阵是模糊集参数的主要输入。3.3 核心代码结构从UC主体到DRO对偶项以两阶段UCLDR为例代码骨架大概长这样% 第一阶段变量启停状态 u binvar(T, G, full); % 机组g在时段t是否运行 s binvar(T, G, full); % 启动动作 z binvar(T, G, full); % 停机动作 % 第二阶段仿射系数机组出力 p0 P * xi p0 sdpvar(T, G, full); % 基准出力 P sdpvar(T, G, K, full); % 出力对风电偏差xi的灵敏度系数 % 切负荷/弃风也做仿射展开 ls sdpvar(T, 1, full); % 切负荷基准 LS sdpvar(T, 1, K, full); curtail sdpvar(T, 1, full); CURT sdpvar(T, 1, K, full);目标函数的写法是确定性开机成本 基准出力燃料成本 DRO阶段的最坏期望调整成本。前两项直接写成线性表达式。DRO阶段的期望成本需要先调用一个函数根据模糊集类型构造对偶约束然后返回一个sdpvar表示最坏期望。这一步是整个代码里最容易出错的地方建议把模糊集对偶单独封装成一个函数输入是仿射系数矩阵和模糊集参数输出是第二阶段成本表达式和相关约束。搭建第一阶段约束时要保证启停逻辑约束、最小开机/停机时间约束、出力上下限约束都写全。特别注意爬坡约束要包含两个相邻时段的基准出力差再叠加上不确定部分的响应范围这两个部分要分别处理防止仿射系数在全场景下越过爬坡上限。3.4 从无限维到有限维LDR对偶转化的实操写法在YALMIP里手动写LDR对偶不太现实我通常的做法是先在纸面上把对偶问题推一遍然后把双重变量写成矩阵形式这样方便核对维度。以矩模糊集为例真实分布的期望μ落在以经验均值μ0为中心、半径为γ的椭球内协方差矩阵限制在一个半正定矩阵约束内。对偶之后第二阶段最坏期望会变成一个“常数项 与仿射系数相关的二次项 半定松弛矩阵”的组合。代码对应的YALMIP片段大致是Gamma sdpvar(K, K, symmetric); % 半定松弛矩阵 alpha sdpvar(1, 1); % 最坏期望成本 alpha trace(Gamma * Sigma0) ... % LMI: [Gamma, ...; ..., ...] 0 F F [Gamma 0]; F F [某些矩阵块 0];这里的Sigma0是经验协方差矩阵。模糊集半径γ可以用一个标量参数控制代码里做成可调节的外部输入。我一般写一个CalibrateRadius函数基于历史数据做bootstrap估计真实分布落到当前模糊集内的置信度再动态调整半径。直接拍脑袋给半径很容易出现两个极端半径太大时模型退化成鲁棒优化成本高得离谱半径太小且历史数据不够时方案的“鲁棒”属性名存实亡。4. 实操过程在6节点系统上完整复现一次4.1 实验方案设计为了验证模型我搭建了一个6节点测试系统包含3台常规机组、1个风电场和3个负荷节点。常规机组参数参考经典测试系统数据做了些微调让系统在风电接入前后都处于合理运行状态。负荷曲线取24小时峰谷差保持在40%左右。风电场景是用AR(1)模型模拟出力偏差得到的预测误差标准差控制在装机容量的10%-15%之间。运行流程是先跑一个确定性UC作为基准再用同一个数据分别跑DRO-LDR、标准鲁棒优化和两阶段随机规划最后对比四个方案的总成本、启停状态、备用水平和切负荷期望。这样的对比可以直观看出DRO在成本与稳健之间的定位。4.2 模糊集半径与参数校准模糊集半径的校准是这次实验中最关键的一步。我采用的方法是把历史场景随机切两半一半用来构造经验分布另一半当成“真实分布”的近似样本。然后在候选半径列表里逐步增大半径观察“真实分布”是否落在模糊集内直到覆盖率达到95%以上。这个覆盖率和半径之间基本是单调关系但增加到某个区间后趋势变缓这说明再加大半径对覆盖率的提升边际效应减弱继续增大会表现为成本上升而收益很小。实际操作中我发现当场景数量N200风电偏差维度K2时半径γ在0.05-0.1之间就能达到95%覆盖N50时同样的覆盖率需要0.15-0.2。场景数量和半径之间有明显的跷跷板关系理论上可以用ε(N)与1/sqrt(N)相关的规律去估算起始点再用覆盖率校准。4.3 结果怎么看成本、启停和风电消纳首先看总成本。确定性UC当然最低因为它无视所有偏差标准鲁棒优化最高备用冗余明显DRO-LDR介于两者之间并且随着模糊集半径的增大逐步逼近鲁棒优化成本。这个成本序列直观地体现了“你对分布的不信任程度越高付出的经济代价越大”。再看机组启停状态。确定性方案倾向于少开一台机组节约成本DRO方案会多开一台小机组作为灵活备用而RO方案有时候会多开两台。切负荷情况在DRO方案下几乎为零RO方案为应对最极端场景备用非常充足但也造成极大浪费。风电消纳率方面DRO-LDR比确定性方案高出不少因为LDR给出的出力调整系数能在风电出力偏高时快速压火电、抬风电出力减少弃风。这些结果输出时建议把每个方案的机组启停计划、各时段出力和成本细节全部落到表格里再挑峰荷和谷荷两个典型时段画Gantt图和负荷分配图。审稿人或导师看到这种级别的对比会比只看一个总成本数字更有说服力。5. 避坑指南我在复现这类代码时踩过的坑5.1 求解不可行先检查约束再怀疑模糊集DRO模型跑出“infeasible”是很常见的事。我的排查顺序是第一步把第二阶段仿射系数固定为零只跑确定性模型如果还是不可行说明第一阶段的启停约束或者功率平衡约束本身有问题。第二步打开仿射系数看是否出现某个场景下出力越界。通常是爬坡约束里的仿射项没有加上限或者风机出力的仿射表达让它超过额定容量。一个很实用的调试技巧是把第二阶段仿射系数矩阵初始化为零矩阵跑通后再逐步放开这样能精确锁定是哪个约束导致不可行。还有一个隐蔽问题模糊集半径设得过大时最坏分布会把切负荷量的期望放大到系统根本无法承担的程度导致第二阶段约束无解。处理方式是在切负荷项上设一个相对较大的惩罚系数同时给弃风量也设惩罚让模型“宁可弃风也不切负荷”的目标更明确。5.2 求解时间爆炸控制变量规模是头等大事YALMIPSDP对偶的代码跑不好经常一跑就是几小时。我试过把场景数从200减到50总成本结果变化不大但求解时间能降低一个数量级。场景数量的选择可以遵循一个经验法则先用50个场景快速验证模型正确性和参数敏感性再逐步增到200以上做精细结果。另外仿射系数矩阵P和LS的维度也要注意风电偏差维度K不要贪大风电偏差用一到两个主成分表示既能抓住主要随机性又避免矩阵维度爆炸。SDP部分建议在YALMIP里开启“reducedim”设置或者手动把对称矩阵声明成上三角形式减少冗余变量。求解器参数方面给Gurobi设置时间上限超过上限就取当前次优解工程上完全够用。5.3 LDR不是万能的什么时候该怀疑它LDR会限制第二阶段决策的灵活性当机组爬坡很慢或者风电偏差很大时仿射调整可能不足以应对所有场景这时模型的成本上界会明显偏离真实最优。一个典型信号是DRO-LDR的备用水平和切负荷风险都对模糊集半径极其敏感半径稍微增大一点成本就跳升很多说明仿射调整能力不足。这个时候可以考虑两种升级路线一是把LDR换成分段仿射决策规则PWLDR二是把第二阶段问题展开成有限场景的联合优化。前者在Matlab里实现起来会更复杂但能显著降低保守性后者更像随机规划牺牲部分稳健性换速度。5.4 模糊集参数的经验法则最后分享两个调参规律。第一模糊集半径不要一次性定死先按1/sqrt(N)的尺度设置一个初始值再根据覆盖率校准做微调。数据量越小半径越大。第二协方差矩阵估计不稳定时加一个小的正则化项比如0.01*I避免SDP求解器在数值上出问题。这个正则化对结果影响很小但对数值稳定性帮助很大。在个人实操里有几个很值得提醒的点。跑这类DRO代码最有把握的做法是先把确定性UC版本完整写好并验证通过再逐步加入模糊集和LDR。我一开始图省事直接上完整DRO模型结果不可行问题和数值警告混在一起花了整整两天才定位到是协方差矩阵奇异引起的SDP求解失败。后来学乖了每引入一个新模块就用小规模数据快速验证确认无误再做全规模实验。另一点小经验是第二阶段LDR系数初始化为零矩阵能让YALMIP减少不少符号运算开销也让约束的稀疏性更好。DROLDR这套组合目前已经比较成熟但后续扩展空间还很大比如把储能系统纳进模糊集、在模糊集里加入时序相关约束、或者用更精细的分段线性决策规则替代全局仿射规则都是可以延展的方向。只要把模型一层层拆开、各个模块边界理清楚这个方向还能继续深挖出很多有价值的工作。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑