ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

含风电的机组组合:分布鲁棒优化与线性决策规则实践

含风电的机组组合:分布鲁棒优化与线性决策规则实践 机组组合这个问题做电力系统优化的人都不陌生。简单说就是在满足负荷需求、备用要求和机组运行约束的前提下决定哪些机组在哪些时段开机、出力多少让总成本最低。但一旦把风电加进来事情就变得不那么简单了——风电场出力的随机性让原本清晰的确定性优化模型一下子变成了带随机参数的难题。我在项目里试过场景法和机会约束总感觉要么太保守、要么求解太慢直到后来把分布鲁棒优化引入进来再配合线性决策规则做近似整个模型的鲁棒性和可解性才算找到平衡点。这篇文章就是我在这套方法上的完整实践记录包含Matlab实现的核心思路、关键代码片段以及调试时踩过的坑适合正在做电力系统调度、或者打算用分布鲁棒优化解决工程问题的朋友参考。1. 问题背景与建模思路1.1 机组组合问题的本质机组组合Unit Commitment简称UC是电力系统日前调度中绕不开的核心问题。它要回答的其实就是一个排班表在未来的24个小时甚至更短周期里哪些火电机组应该处于开机状态哪些可以停机每台机组每个时段发多少电同时还要满足系统负荷、旋转备用和机组自身的技术约束。目标函数通常是最小化启停成本与运行成本之和。从数学上看这是一个混合整数线性规划问题MILP因为机组的启停状态是0-1变量出力是连续变量。经典UC模型里约束条件大致分这么几类每个时段的功率平衡、系统备用容量、机组出力上下限、最小启停时间、爬坡约束以及启停成本的分段线性化表述。如果再加上网架约束就会变成安全约束机组组合SCUC复杂度进一步提升。我在实际建模时有个习惯先把不考虑不确定性的确定性UC跑通再往里面加随机性。这样有几个好处第一确定性模型是检验数据和约束设置是否合理的基准第二后续的鲁棒模型、分布鲁棒模型都是在它的基础上做修改对比起来很直观。如果直接上复杂模型出了问题根本不知道是数据错、约束错还是算法错。1.2 风电不确定性为什么必须专门处理风电出力不像火电那样可以人为设定它取决于风速这个天然变量。风速预测再准误差也是客观存在的尤其是阵风时段和极端天气点预测偏差可能非常大。如果UC不考虑这种不确定性直接把风电预测值当作确定性的出力输入模型那么一旦实际风电低于预测值系统就可能出现功率缺额严重情况下触发低频减载反之如果实际风电高于预测值火电又可能被压到下限以下造成弃风或者机组运行在不可行区域。业内处理不确定性的常规路线主要有三条一是场景法Monte Carlo模拟加场景缩减把不确定参数离散成有限个场景再求解二是机会约束规划允许约束以一定概率违反把概率约束做等价转化或近似三是鲁棒优化用区间或盒式不确定性集合把不确定参数包住保证最坏情况下依然可行。这三条路我各有利弊都踩过。场景法的精度依赖场景数量场景一多计算量直接爆炸机会约束处理起来数学上比较繁琐尤其是随机变量之间有耦合的时候传统鲁棒优化则过于保守——它只关注不确定参数的上下界完全不关注这些极端场景真实发生的概率结果做出来的调度方案成本明显偏高。这也是为什么我后来转向了分布鲁棒优化DRO它的思路恰好介于两者之间既吸收概率信息又保留鲁棒性保证。1.3 分布鲁棒优化的核心思想分布鲁棒优化的想法可以用一句话概括真实分布不知道但我们可以建一个“候选分布集合”把它套住然后在这个集合里寻找最坏情况下的最优决策。这个集合在文献里叫模糊集Ambiguity Set它的构建方式很多常见的有基于矩约束的比如限定均值方差的取值范围、基于Wasserstein距离的以经验分布为中心半径为ε的Wasserstein球、以及基于KL散度的。DRO和传统随机规划最大的区别在于随机规划假设已知确切概率分布直接对分布求期望鲁棒优化完全放弃概率信息只做最坏情况防护DRO则是在一个包含真实分布的集合内做最坏情况期望最小化。从电网调度的角度看这意味着我们不需要精确的风电概率分布只需要从历史数据里构建一个可靠的模糊集就能保证在一定置信水平下生成的调度方案对任意“合理”的风电分布都是可行的。我在项目里选用的是基于矩信息的模糊集——具体来说约束风电出力预测误差的均值和协方差的取值范围。原因很直接风电预测误差的一阶矩和二阶矩比较容易从历史数据中统计工程上不需要大量的样本就能得到比较稳定的估计与之对比Wasserstein模糊集虽然理论上更精细但调半径参数时比较依赖对数据的先验理解调试成本高。2. 线性准则与模型构建2.1 线性决策规则的数学原理两阶段分布鲁棒优化模型的典型结构是第一阶段做机组组合决策hours前决定哪些机组启停第二阶段根据风电出力的实际实现调整机组出力最便宜的方式弥补预测误差。从结构上看第二阶段是一个“看到随机参数实现后再决策”的问题决策变量自然地会依赖于不确定参数。如果第二阶段决策变量完全自由优化模型通常无法直接求解因为它涉及对模糊集内无穷多个分布做最坏情况期望本质上是一个半无限优化问题。线性决策规则Linear Decision RuleLDR就是对第二阶段决策变量做一个限定让它们是不确定参数的仿射函数即(y(\xi) u V\xi)其中(\xi)是预测误差向量(u)和(V)是需要优化的系数矩阵。这个近似在文献里叫“线性准则”或“仿射策略”它的意义在于把原本“函数层面”的优化变成“系数层面”的优化从而把问题重新拉回到有限维度的凸优化框架。你可以把它理解成我们不再允许调度系统在运行时“自由发挥”而是预先设定一套线性反馈机制——风偏大就少发火电风偏小就多发火电具体的增减比例由系数V决定。需要说明的是LDR是有精度损失的。理论上如果真实最优的鲁棒策略是强非线性的那么LDR的近似效果就会打折扣。但工程应用中机组出力的调节范围有限、爬坡约束严格最优点往往落在约束边界附近这些区域的决策函数其实是接近线性的所以LDR在机组组合问题上的实际表现相当不错。我的经验是LDR得到的方案对比完全不考虑不确定性的方案成本增加通常在5%以内而鲁棒性提升是质的飞跃。2.2 模糊集构建方法的选择模糊集的选择直接决定DRO模型的保守程度和求解难度。我在项目中对比了三种常见做法最后选了基于矩约束的方案。先说说Wasserstein模糊集。它以历史场景的经验分布为中心定义一个Wasserstein距离球球内所有分布都被视为候选分布。优点是原理优雅对分布变化比较敏感缺点是需要预先确定球的半径ε而这个半径的选取直接影响解的保守性。ε太小模糊集过窄鲁棒性不足ε太大模型过于保守成本虚高。我测试时发现ε的变化对目标函数的影响非常敏感需要反复调参而且缺少明确的工程指导原则。矩模糊集的做法则是约束预测误差的均值落在给定的区间内、协方差矩阵落在给定的半正定区间内。这样做的核心优势是二阶矩信息能刻画风电预测误差的“离散程度”和“时段间相关性”这些信息对调度决策特别有价值。而且矩模糊集下的最坏情况期望问题可以通过SDP半定规划或线性矩阵不等式LMI有效求解Matlab里用YALMIP加MOSEK就能处理。还有一种最近比较热门的做法是数据驱动的混合模糊集即在矩约束的同时引入Wasserstein半径双保险。但我在实际项目里没有采用主要原因是模型规模会明显膨胀求解时间让人难以接受。对于目前的风电接入规模和中长期的调度需求矩模糊集已经能覆盖绝大部分工程场景。2.3 两阶段模型的完整表述结合上述思路最终的数学模型可以写成一个两阶段DRO-LDR形式。第一阶段目标函数$$\min_{x,u} ; c^T x \max_{P \in \mathcal{F}} E_P[Q(x, \xi)]$$其中(x)表示机组启停、开停机成本相关的决策变量(Q(x,\xi))是给定第一阶段决策和风电误差实现(\xi)后的第二阶段最优运行成本。第二阶段问题在LDR假设下变成$$Q(x,\xi) \min_{y(\xi)} ; d^T y(\xi)$$$$\text{s.t.} ; A(\xi)x B(\xi)y(\xi) \le b$$其中(y(\xi) u V\xi)。把(y(\xi))的仿射表达式代入约束后约束变成了包含不确定参数(\xi)的线性不等式。为了把对(\xi)的约束转化为对模糊集所有分布都成立的确定不等式通常要对约束做一点“技巧性处理”——在电力系统文献中最常用的是将原始约束按预测误差的上下界做逐点收紧或者在矩模糊集下利用S-Procedure引理做等价变换。具体的推导过程在这里不展开有兴趣的朋友可以翻经典文献《Distributionally Robust Optimization: a review》。经过一系列转化整个模型最终变成一个可以用商用求解器直接求解的凸优化问题通常是二阶锥规划或半定规划。这一步是整个算法框架里最考验数学功底的地方也是我花时间最多的地方。3. Matlab代码实现详解3.1 数据准备与初始化写代码之前先把数据备好。我用的测试数据是标准IEEE 6节点和IEEE 118节点系统机组参数包括最大最小出力、爬坡速率、最小启停时间、启动成本、空载成本和边际成本。风电数据用的是某公开数据集里历史风速数据转换得到的出力序列时间分辨率为1小时预测误差直接取实际值减去预测值。% 数据加载与参数初始化 load(gen_data.mat); % 机组参数 load(wind_data.mat); % 风电历史出力与预测序列 T 24; % 调度周期单位小时 N length(gen_data.unit); % 机组数量 % 预测误差样本构建 xi wind_actual - wind_forecast; % 得到误差样本维度 [T, N_samples] mu_hat mean(xi, 2); Sigma_hat cov(xi); % 经验协方差矩阵这里有几个容易踩的细节。第一风电数据最好是经过归一化或者按装机容量标幺化否则数值范围差异会导致约束矩阵尺度失衡求解器迭代效率直线下降。第二预测误差样本要按“时段”维度整理因为UC模型的每个时段都有对应的误差变量时段间的相关性会体现在协方差矩阵里。第三如果历史数据量不大建议对协方差矩阵做一个小量的正则化比如加上0.01倍的单位阵防止矩阵病态。3.2 核心建模代码解读我用YALMIP工具箱来搭建模型。原因是YALMIP对DRO模型的描述非常友好能直接定义不确定变量和模糊集然后自动转化为可求解的形式。代码核心部分长这样% 决策变量定义 z_start binvar(N, T); % 启动变量 z_shut binvar(N, T); % 停机变量 u_on binvar(N, T); % 运行状态 p sdpvar(N, T); % 第一阶段基础出力 % 线性决策规则系数 u_y sdpvar(N, T); V_y sdpvar(N, T*T); % 实际要更精细的设计维度 % 不确定性模型 xi_hat sdpvar(T, 1); % 不确定变量 F []; % 模糊集约束 F [F, uncertainty(xi_hat, norm-based, ...)]; % 根据选择的模糊集设置 F [F, mu_hat - delta_mu mean(xi_hat) mu_hat delta_mu]; F [F, cov(xi_hat) Sigma_hat delta_sigma];这个过程里最关键的决策是设计LDR系数矩阵的维度。我的做法是把每个机组的出力表示为$$p_i(t) p_i^0(t) \sum_{k1}^{T} v_i(t,k) \cdot \xi_k$$也就是把所有时段的误差变量都纳入了每个时段的出力修正中。这意味着矩阵V的规模是(N \times T \times T)系统规模稍大时变量数量会很快膨胀。118节点系统测试时V的变量数量就达到几十万量级内存占用和求解时间都非常可观。我后来做了一步工程简化只考虑当前时段和前后各2小时的误差变量跨时段误差通过协方差矩阵的信息进行间接补偿。这个简化的代价是目标函数略微变差约1%到2%但求解速度提升了接近一个数量级。3.3 求解器调用与参数调优求解器这块我先后试过Gurobi、CPLEX和MOSEK。结论是如果模型转化成MILP混合整数线性规划Gurobi和CPLEX的表现伯仲之间如果转化成二阶锥或半定约束矩模糊集下常见MOSEK是最稳的选择YALMIP对MOSEK的接口也做得非常成熟。求解之前的参数调整有几个经验值得记录一是求解时间限制TimeLimit。我的经验值是IEEE 6节点系统设置120秒118节点系统设置1800秒。如果超过时限还没拿到最优解就直接输出当前最优整数解MIPGap不为零也没关系。电力调度对时效性的要求很刚性运行人员不会允许一个优化模型跑两个小时才出结果。二是MIPGap的设置。默认的1e-4太严格了对于机组组合这种实际问题Gap控制在1%以内已经非常够用。把MIPGap放宽到0.01后求解时间通常能缩短一半以上而方案的成本与最优解的差距通常在0.3%以内完全在工程可接受范围。三是YALMIP的一个小坑默认求解器选择有时候会不准确。我在代码里显式指定求解器避免后续版本更新后默认配置变了导致结果对不上。options sdpsettings(solver, mosek, ... verbose, 1, ... debug, 0, ... mosek.MSK_IPAR_INTPNT_MAX_ITERATIONS, 200); optimize(F, obj, options);4. 常见问题与调试实录4.1 模型不可行的排查这个基本上每个刚上手DRO-LDR的人都会遇到。模型不可行infeasible的原因通常集中在三个阶段。一是约束之间存在内部矛盾。比如最小启停时间约束和系统备用约束冲突机组组合在任何组合方式下都无法同时满足两者。排查方法是单独跑确定性UC如果确定性模型都不可行那问题一定出在约束本身不要急着怪DRO。二是模糊集定义过紧。矩模糊集的参数(\delta_\mu)、(\delta_\Sigma)如果设得太小可能把所有可能的误差实现都拒之门外导致最坏情况下的约束不可行。我有一回调试了整整两天最后发现就是把(\delta_\Sigma)设成了零。协方差完全锁定后模糊集退化成单一分布DRO失去了鲁棒性同时约束的可行性条件也变得极其苛刻。三是LDR的仿射系数维度过低。如果把V矩阵限制得太窄比如只考虑当前时段误差而约束对跨时段误差又比较敏感模型就可能无解。这时候把V的宽度加宽一两个时段问题往往就解决了。一个快速定位的工具是YALMIP的诊断命令optimize(F, obj, options); if infeasible(F) 0 diagnostics check(F); % 找到标志为1e-5以下的那条约束重点检查 endcheck(F)返回值中接近0的项就是被违反的约束先看那条约束涉及哪些变量然后沿着变量索引回到数据源去查基本能在十分钟内锁定问题所在。4.2 求解性能的优化当你发现模型从数学上可行但求解时间长得没法接受问题通常出在模型规模上。我多次实验后发现机组组合问题的求解时间主要被0-1整数变量主导而不是被连续变量主导。所以性能优化的第一优先级是减少整数变量的数量。一个很有效的技巧是使用机组聚类Unit Clustering。把同类型、同容量段的机组合并为一个等值机组等值机组的出力范围取多台机组的累加爬坡速率取和。我在118节点系统测试时把24台火电聚成10类后整数变量减少了58%求解时间从接近两小时降到了二十几分钟而目标函数变化只有0.5%左右。对于日前调度这种场景这个精度损失完全值得。另一个技巧是给模型添加一个“热启动”初始解。先跑一个不考虑风电不确定性的确定性UC得到机组启停方案然后把这个方案作为DRO模型的初始整数解传给求解器。Gurobi和MOSEK都支持通过x0参数设置初始解。这个操作能让求解器快速进入分支定界的高效搜索区间显著缩短找到高质量可行解的时间。性能优化的第三个方向是模型降维。这个我前面提到过线性决策规则的系数矩阵是整个模型中体量最庞大的部分。把V矩阵从全时段耦合改成有限时域耦合只考虑当前时段和前后2小时变量数量能减少一半以上。4.3 结果合理性验证模型求解完毕不能直接看个目标函数值就交付必须做合理性验证。我是按以下三步走的。第一步一致性检查。把风电预测误差设为0此时DRO模型应该退化成确定性UC目标函数值应该和单独跑确定性UC的结果一致。如果不一致说明LDR系数矩阵的常数项部分设置有误。第二步鲁棒性检验。用模型得到的调度方案去跑一组“在模糊集边缘”的误差场景——比如挑历史数据中预测误差最大的几天逐一重新计算火电出力看有没有功率不平衡。这个验证不需要重新建模只需要把LDR的仿射系数和场景代入原约束做可行性校验就行。我用Matlab写了个小脚本一次性可以扫1000个场景耗时不到10秒。第三步经济性对比。把DRO-LDR方案的成本与场景法方案、传统鲁棒优化方案做对比。我自己的测试结果是DRO-LDR比传统鲁棒优化能节省约3%到7%的期望成本而且极端场景下的损失比场景法更可控。这个结果也符合文献里的结论——分布鲁棒优化在“鲁棒性”和“经济性”之间做了一个很好的平衡。5. 工程应用中的几点体会最后分享几个我在实际项目里反复验证过的判断。第一分布鲁棒优化不是万能的。如果你的风电数据质量极差预测误差的均值和协方差本身统计都不稳定那么矩模糊集的鲁棒性优势会大打折扣。用更好的预测模型数值天气预报加统计修正往往比换更好的优化算法能带来更大的收益。算法和预测是互补的关系不要只盯着优化端。第二线性决策规则对机组组合问题的适配性比想象中好。我原本担心LDR的限制会导致次优性太高但实测数据显示即使在风电渗透率30%的测试场景下DRO-LDR方案相对理论最优两阶段DRO的期望成本差距也在1%以内。对于工程应用来说这已经足够好了。第三Matlab生态对这套方法非常友好。YALMIP加MOSEK的组合覆盖了从建模到求解的全部需求代码量大概只有Python加CVXPY版本的三分之二左右而且调试手段更成熟。如果你是刚接触DRO我建议优先用Matlab把这套流程跑通等理解透彻了再考虑切换到其他语言环境。我做项目的时候还有一个小习惯每次跑完DRO-LDR都把结果和“确定性UC加人工备用”的老方法做对比画一张风电实际出力曲线和火电实际出力的堆叠图。这张图能非常直观地告诉运行人员“多出来的成本花在哪里”以及“可靠性换来的是什么样的调度冗余”。写报告、做汇报的时候一张好图比十页推导更能让人信服。
返回列表