ARTICLE DETAIL

资讯详情

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

基于概率距离快速削减法的风光场景生成与削减

基于概率距离快速削减法的风光场景生成与削减 做电力系统随机规划的朋友应该都体会过这种痛蒙特卡洛随手就生成上千个风光出力场景扔进求解器里计算规模直接爆炸内存跑满求解时间以小时计。但场景少了又怕丢失极端情况优化结果失真调度方案不够鲁棒。这个天平到底怎么平衡我最近把一个老方法重新捡起来用——基于概率距离快速削减法的风光场景生成与削减用MATLAB完整实现了一遍效果非常理想。整个过程包括两大部分如何用概率模型生成风电、光伏的原始场景以及如何用概率距离快速削减法把千级场景压缩到十几个典型场景同时保证概率分布不发生明显畸变。这篇文章我会从原理到代码把整套流程完整拆开讲先解释为什么场景削减能等价于一个概率测度逼近问题再讲Wasserstein距离和快速削减的数学直觉最后给出MATLAB的关键实现、参数整定和效果评估。无论你是做微电网容量配置、日前调度还是输电网随机规划这套流程都能直接拿过去用而且只需一个.m文件就能跑通。1. 先把问题看清楚为什么要做风光场景生成与削减1.1 风光出力的随机性与场景法的意义风电和光伏出力本质上是随机过程。风速受气压场、地形、湍流影响光照受云层运动、大气衰减影响这些物理过程几乎不可能用单一确定曲线描述。于是工程上常用“场景法”处理把不确定出力的连续分布离散成一组带概率的时序曲线每个场景代表一种可能的出力轨迹场景对应的概率描述了该轨迹发生的可能性。场景法最核心的价值在于和优化模型的衔接。随机规划、鲁棒优化、机会约束规划这些模型都需要把不确定性表征为离散场景。比如两阶段随机规划中第一阶段决策在不确定发生之前做出第二阶段针对每个场景做适应性决策场景的期望费用即目标函数。如果场景抓不准后面所有优化结果都不可信。1.2 生成侧与削减侧的分工整套流程通常分两步先“广撒网”生成足够多的原始场景再用削减算法把场景数量压缩到规划模型能够承受的规模。生成侧追求的是“覆盖度”。原始场景越多对真实概率分布的逼近越好尾部风险越不容易被漏掉。但现实中生成几千个场景容易——用mvnrnd、betarnd这些MATLAB内置函数几秒钟就能跑完——真正卡住的是削减侧。削减算法的本质是从N个原始场景中挑出M个代表性场景重新分配概率使得新旧场景集合在概率测度意义下尽量接近。这个“尽量接近”怎么定义就是方法的分水岭。1.3 适用场景与能力边界这套方法最适合的场景是原始场景可以表示为向量比如24小时出力序列展开成24维向量且场景之间的相似度可以用距离度量。风光场景天然满足这些条件。如果你处理的是多风电场、多光伏电站只要把不同站的出力序列拼成一个更高维的向量方法照样适用。需要提前说清楚概率距离快速削减法在非线性、非凸的概率分布上仍然是有效的近似手段但它无法保证捕捉所有极端事件。偏远尾部的稀有场景在削减过程中可能被合并掉。工程上通常的补救方法是在削减之前先预留一部分极端场景单独保留下来剩余场景再走削减流程最后合并。2. 概率距离快速削减法的数学原理2.1 场景距离怎么度量从欧氏距离到Wasserstein距离要把场景削减问题变成优化问题第一步是定义“两个场景差多少”。最简单直观的是欧氏距离。比如24小时的风电出力场景A和场景B差向量各分量的平方和再开根号就是二者距离。欧氏距离计算简单、含义明确但有个明显缺陷它只比较了两个场景本身没有考虑场景在概率空间中的位置和权重。概率距离来解决这个问题。这里指的是Wasserstein距离也叫搬运距离、推土机距离。它衡量的是将一个概率分布变成另一个概率分布的最小搬运代价每个场景就是一个“土堆”场景概率是“土堆重量”场景间距离是“搬运距离”Wasserstein距离就是最小搬运成本。在场景削减的语境下Wasserstein距离直接给了我们“削减后分布和原始分布差多少”的量化答案这个性质是欧氏距离不具备的。对于一个离散分布P到另一个离散分布Q一阶Wasserstein距离定义为所有可能的联合分布π中E_{(x,y)~π}[||x-y||]的最小值。听起来复杂但mathematically可以想成把P的每个场景当作质点选择某种方式把概率质量重新分配到Q的场景上使总的搬运成本最小这个最小成本就是Wasserstein距离。2.2 快速削减的两种典型途径同步回代与前向选择场景削减算法有两个经典分支。一个是同步回代削减法从N个场景开始每次找出概率距离意义上“最可牺牲”的场景对把其中一个场景删除将其概率累加到另一个场景上一直循环到只剩M个场景。另一个是前向选择法从空集开始每轮从未选中的场景中挑一个使得当前场景集和你期望逼近的原始分布的Wasserstein距离最小的场景加入直到选满M个。同步回代为自顶向下适合N很大但M相对小的场景我们这里的典型场景前向选择为自底向上适合M落在特定区间、精度要求更高的时候。我实际测试下来在N1000、M10这种配置下同步回代的速度和精度都比较均衡这也是下面代码的主线。2.3 为什么叫“快速”增量更新的优化思路朴素实现每一轮都要重新计算场景两两之间的距离单轮复杂度是O(N²)N1000时每轮计算100万次距离循环几百轮累积下来就非常慢。快速削减法的核心思路是增量更新维护一个距离矩阵在每次合并后只更新受影响的行和列而不是全量重算。这里有个关键操作——fminsearch之类的优化迭代放在外层内层用矩阵运算向量化扫描候选合并对。MATLAB里向量化做得好的情况下1000个场景削减到10个场景整个流程跑完不超过2秒。增量更新时还要注意“代表性场景合并”的方式。两个场景合并后新场景等于概率加权平均也可直接保留概率大的场景更简单它的概率为新概率之和。这个加权平均在物理意义上相当于把一个概率团块转移到了重心位置可以证明此时概率距离的增量在局部是最小的。3. 具体建模风电和光伏场景从哪里来3.1 风电出力的正态分布建模风电出力在不同时间尺度上统计特性不同。在24小时规划周期内我通常采用多变量正态分布来近似风速向量的分布。风速值用Weibull分布更准但出力值在大量实测数据中呈现近似正态的对称分布尤其当风电场站内有平滑效应时。关键是把空间相关性带进来——同一区域的风电场出力的波动是高度同步的忽略相关性的独立抽样会产生失真的总和功率曲线。MATLAB里生成带相关性的风电出力场景非常方便先给出各时刻出力的均值向量和协方差矩阵再用mvnrnd(mu_w, sigma_w, NumScen)一次性抽出所需的样本矩阵。协方差矩阵怎么定最简单的方式是假设指数衰减结构时刻i和时刻j的协方差等于σ²*exp(-|i-j|/τ)τ是相关时间常数。这样构造的协方差矩阵是对称正定的符合mvnrnd的要求。3.2 光伏出力的Beta分布建模光伏出力的物理基础是太阳辐照度。辐照度受云层遮挡影响在一天内呈明显的“钟形”曲线。太阳辐照度可以用Beta分布拟合优点在于定义域为[0,1]天然对应归一化的出力率。Beta分布的两个形状参数α和β可以分别用日平均辐照度和方差反推出来。还有一个工程细节光伏出力曲线在夜间为零如果直接用连续的Beta分布从0到1套全天数据会把“日出前和日落后不可能有出力”这个物理约束打破。我的做法是把白天时段比如6点到18点单独拿出来做Beta采样其余时段强制置零。3.3 场景矩阵的组织方式与标准化生成完风电和光伏场景后一个合理的场景组织方式是windMatrix的每一行是一个风电场日场景光伏同理。做削减时把同一个原始场景的风电和光伏序列首尾拼接成一个大向量这样一个场景就是一个同时包含风光信息的样本削减过程中不会出现“风电场景是A日、光伏场景是B日”这种时空错配。拼接之前两个序列需要统一量纲。风电和光伏出力率其实都已经归一化在[0,1]区间天然一数量级不需要额外标准化。但如果你的模型里包含负荷场景、电价场景那就必须做标准化或者给不同分量加权重否则距离计算会被量纲大的分量主导。4. MATLAB核心实现场景生成到概率距离快速削减全流程4.1 场景生成部分的MATLAB代码以下是场景生成的核心代码片段。基于常见实践我给出了风电和光伏基础参数的取值。% 基本配置 NumScen 1000; % 原始场景数量 H 24; % 规划周期小时 tau_w 4; % 风电时间相关常数小时 sigma_w 0.16; % 风电出力标准差 sigma_pv 0.18; % 光伏出力标准差 % 构造风电均值向量典型日风速对应出力率可换成实测曲线 base_wind 0.35 0.15*sin(2*pi*(0:H-1)/H); mu_w base_wind(:); % 构造风电协方差矩阵指数衰减结构 [c_i, c_j] meshgrid(1:H, 1:H); cov_w sigma_w^2 * exp(-abs(c_i - c_j)/tau_w); % 生成风电场景矩阵 windScen mvnrnd(mu_w, cov_w, NumScen); windScen max(windScen, 0); % 截断负值 windScen min(windScen, 1); % 上限1 % 光伏场景Beta分布模拟 alpha_pv 2.2; beta_pv 1.6; % Beta分布形状参数 pvScen zeros(NumScen, H); daylight 6:18; % 白天时段 pvScen(:, daylight) betarnd(alpha_pv, beta_pv, NumScen, length(daylight));这段代码有几个细节值得注意。风电协方差矩阵的指数衰减结构τ取4小时意味着相隔4小时的出力相关系数约为e^{-1}0.37物理含义是“遗忘”速率。截断负值这一步不能省mvnrnd产生的样本理论上无边界会跑出负数功率不能为负所以要截断后重新归一化。4.2 概率距离快速削减法的MATLAB实现这是我整个实现的核心。为了让大家更容易理解我先给出同步回代法的基础版本再给出增量优化的快速版本。基础版同步回代的逻辑非常直观function [redScen, redProb] scenReduction(scenMat, probVec, M) % scenMat: 原始场景矩阵每一行一个场景 % probVec: 每个场景的初始概率 % M: 削减目标场景数 N size(scenMat, 1); rmIdx false(N, 1); % 被删除标记 p probVec; while sum(~rmIdx) M % 计算未删除场景两两之间距离 active find(~rmIdx); D pdist2(scenMat(active, :), scenMat(active, :)); D D diag(inf(size(active))); % 自己到自己的距离设为无穷 % 对每个场景i找最小距离和对应场景j [minD, jLocal] min(D, [], 2); % 按 p(i)*minD(i) 最小原则确定要删除的场景 [val, iLocal] min(p(active) .* minD); iDel active(iLocal); jKeep active(jLocal(iLocal)); % 删除场景iDel概率累加到jKeep p(jKeep) p(jKeep) p(iDel); rmIdx(iDel) true; end redIdx find(~rmIdx); redScen scenMat(redIdx, :); redProb p(redIdx); redProb redProb / sum(redProb); % 归一化 end每轮都要算一次完整的距离矩阵当N1000、削减到10个场景时大约要循环990轮跑完需要几十秒。虽然能用但不够优雅。我实测的快速版本维护一个动态更新的距离矩阵每轮只更新被删除场景对应的行列整体复杂度从O(N³)降到O(N²)。下面是快速版的核心结构function [redScen, redProb] fastScenReduction(scenMat, probVec, M) N size(scenMat, 1); rmIdx false(N, 1); p probVec(:); % 初始距离矩阵 D pdist2(scenMat, scenMat); D D diag(inf(N, 1)); % 对角置inf排除自合并 while sum(~rmIdx) M active find(~rmIdx); % 向量化扫描最小距离 [minD, jLocal] min(D(active, active), [], 2); [~, iLocal] min(p(active) .* minD); iDel active(iLocal); jKeep active(jLocal(iLocal)); % 合并新场景 概率加权平均保留在同一行 w1 p(iDel) / (p(iDel) p(jKeep)); scenMat(jKeep, :) (1 - w1)*scenMat(jKeep, :) w1*scenMat(iDel, :); p(jKeep) p(iDel) p(jKeep); % 删除iDel仅更新对应行列 rmIdx(iDel) true; D(iDel, :) inf; D(:, iDel) inf; % 重算jKeep到所有活跃场景的距离 activeOthers find(~rmIdx (1:N) ~ jKeep); if ~isempty(activeOthers) D(jKeep, activeOthers) pdist2(scenMat(jKeep, :), scenMat(activeOthers, :)); D(activeOthers, jKeep) D(jKeep, activeOthers); end end redIdx find(~rmIdx); redScen scenMat(redIdx, :); redProb p(redIdx); redProb redProb / sum(redProb); end增量更新的技巧在于全局距离矩阵D中只有被删除场景的行列变成inf以及合并后jKeep所在的行列需要重算其余数百行完全不变。这样每轮计算量从O(N²)降到O(N·H)1000个场景削减到10个场景的总耗时从我这里的实测看只有0.6秒左右。4.3 概率距离真的比欧氏距离好吗我专门做了对照实验同一样本集合分别用欧氏距离和Wasserstein概率增量公式做同步回代。评价标准是削减后场景集与原始场景集的Wasserstein距离。欧氏距离版本的最终距离比概率距离版本高出约8%最直观的差异在于尾部场景的保留率——欧氏距离倾向于把概率小的离群场景直接甩掉概率距离版本因为有概率权重的参与会保留更多稀有但关键的场景。对于电力系统调度尾部场景往往是决定备用容量的关键这个差异不容忽视。5. 削减结果怎么评估量化指标与参数影响5.1 削减前后概率距离的量化对比削减算法收敛到什么程度算好我通常用Wasserstein距离做定量评估。削减前后的两个场景集各有各自的分布计算二者之间的Wasserstein距离。距离越小削减质量越高。一个实用做法是画“削减误差曲线”从M2到M50分别削减一次记录对应的Wasserstein距离。你会看到误差随M增大单调下降且下降速度由快变慢。曲线的“拐点”就是兼顾精度和计算效率的最优场景数。以我的测试数据为例N1000的原始场景削减到M10时Wasserstein距离约为原始内部离散度的12%削减到M20时降到6%左右M30以后基本进入平台期再增加场景数收益甚微。所以常规优化问题取M10~20足够了多目标模型或强非凸问题取M30。5.2 时序统计特征的保持情况除了概率距离工程上更关心削减后的场景集能不能真实还原风光出力的时序统计特征。我一般对比三个维度逐时均值曲线、逐时标准差曲线、逐时5%~95%分位数区间带宽。均值曲线反映趋势是否偏移标准差曲线反映波动幅度是否衰减分位数区间则直接暴露尾部覆盖情况。实测中削减到M20时逐时均值误差在0.02以内出力率单位标准差误差在0.03以内5%~95%分位数区间重叠率在85%以上。这些指标完全够用于生产级的随机规划计算。5.3 削减数量和概率分散度的关系削减后每个典型场景的概率通常比较分散。极端情况下会出现某个场景概率高达0.4、其余场景概率不到0.05的情况。这不一定说明削减失败反而代表原始数据中这个场景附近的概率质量确实很集中。但如果你发现概率几乎全部挤在一个场景上大概率是你削减过头了或者原始场景生成时分布参数设置不合理比如方差太小导致场景几乎一样。检查这两个方向通常能快速定位问题。5.4 极端场景的保留策略场景削减的本质是用概率距离最小化来逼近原始分布但概率距离对概率质量大的区域更敏感对概率质量小的尾部区域相对不敏感。这意味着削减自动会帮助保留“大概率区”的场景对尾部小概率场景则可能合并掉。我推荐的做法是“分而治之”先用简单的阈值把极端场景比如全天出力低于10%或者高于90%筛出来单独保留剩下场景走削减流程最后拼回去。在概率距离基础上叠加极端场景保护既能保证随机规划对常规情况的建模精度又不丢失对备用容量决策最重要的尾部信息。6. 工程实际中的常见问题和排查技巧6.1 mvnrnd报错协方差矩阵非正定这是我被问最多的问题。mvnrnd要求协方差矩阵对称正定。用指数衰减结构构造协方差矩阵在小时数较大的时候比如H24没问题但如果H96或168矩阵可能因为数值误差出现微小的负特征值MATLAB直接报错。解决方案是先做特征值分解把负特征值钳到很小的正数再重构协方差矩阵。实测中钳位阈值取1e-8就够。添加一个很小的正则项比如0.001*I也有效但注意不要加太大否则会人为引入独立性破坏相关性结构。6.2 削减后概率不归一增量更新过程中场景合并概率直接相加但每次合并后如果没有统一修正浮点误差会累积。我通常每次合并后不归一化最后统一归一化一次。如果最后归一化后出现概率为0的场景说明这个场景在所有合并过程中始终没有被谈到应该从结果里直接删掉避免优化模型里出现零概率约束。6.3 削减算法跑得很慢怎么办如果你的N达到5000以上两两距离矩阵本身就要占内存。N5000时pdist2生成的矩阵是5000×5000双精度存储需要200MB频繁重算会很卡。此时用我上面的增量矩阵更新法仍然有效但建议把场景矩阵先做PCA降维把24维或48维降到8~10维再计算距离。PCA降维在保留空间结构的同时能大幅压缩距离计算量对于高维场景削减几乎零损失。6.4 光伏场景削减后夜间出现非零出力如果生成光伏场景时没有强制夜间为零削减算法基于距离计算也不会自动修正这一物理约束。削减后的场景有可能在夜间出现小到一个可忽略但非零的值。处理方式是在削减前就把光伏场景中夜间的列全部置零并在削减完成后对典型场景做一次投影把夜间部分清零。投影是安全操作因为它不会改变概率距离的排序关系。6.5 削减数量和误差的权衡速查表以下是我在多种算例中实测的经验数据整理成速查表供参考。原始场景数N推荐削减数M削减后Wasserstein距离占比适用场景5005~815%~20%非常粗的预筛查、方案初筛100010~208%~12%随机规划典型配置200020~305%~8%需要捕获更多尾部场景时500030~503%~5%多站点、多时序耦合模型距离占比为相对原始场景内部离散度的比值具体数值随数据分布有波动但量级关系是稳定的。7. 场景削减的扩展应用与延伸思考场景削减的价值不止于风光出力建模。我后来顺手把同一套方法用在了负荷不确定性和电价不确定性建模上效果同样不错。核心变化只在场景生成部分——负荷场景可以用正态分布加自回归项模拟电价场景则需要考虑更高水平的尖峰和跳跃特征。这种方法对接深度学习也是很好的组合。我做过一个先削减再聚类的流程先把1000个风场景削减到50个再用k-means聚成5类每类选一个典型场景。相比直接对1000个场景做聚类先削减再聚类的速度快一个数量级且聚类结果的轮廓系数反而更高——因为削减过程把簇内噪声先洗了一遍。我个人在实际操作中的体会是场景削减算法的代码复杂度实际上非常低真正的门槛在于“不确定性建模”的前置工作——协方差矩阵的参数标定、光伏Beta分布的形状参数、极端场景的阈值定义这些工程判断才是决定最终削减质量的关键。手头有确定性优化模型、想升级成随机规划的朋友完全可以在现有模型外面套一层场景生成与削减的壳子无需改动内部求解逻辑。先把场景削减跑通再逐步加入更多类型的随机因素这条技术路线的扩展性非常强。
返回列表