
一聊到风光出力随机性搞电力系统优化的同行第一反应往往是“头大”。风电和光伏的出力像过山车一样波动今天凌晨的大风天和明天下午的晴空天完全不是同一个运行工况。可问题在于不管是做机组组合、经济调度还是规划阶段的可靠性评估需要的是一组能代表各种典型情况的确定性输入——这就是场景生成和场景消减要干的活。简单说风光出力场景生成是把历史数据和概率特性变成一批“有可能发生的出力曲线”场景消减则是把这批曲线压缩成少数几条最有代表性的“典型日”让优化模型既能算得动又不至于把极端风险漏掉。这篇文章我从实际做模拟优化项目的角度把场景生成、消减的原理、选型逻辑、具体实现和踩过的坑完整梳理一遍。适合正在做新能源并网仿真、电力系统随机优化、或者研究风光出力建模的研究生和工程师参考也欢迎只想知道“这几个算法到底怎么选”的同行直接跳到自己需要的章节。1. 场景生成与消减到底解决什么问题1.1 为什么优化模型“怕”随机性电力系统优化模型的核心是求解一个目标函数比如发电成本最小、弃风弃光最小、碳排放最少然后给出一组机组启停和出力安排。传统确定性模型里负荷和出力都是固定数值模型能直接求解。可一旦把风电、光伏装进模型问题就变了——风光的出力不是确定值而是随机变量。如果只取期望值代入模型算出来的方案往往在大多数情况下可行但遇到极端低出力或高出力场景就会出问题低出力时系统可能旋转备用不足高出力时可能出现大规模弃电甚至潮流越限。更麻烦的是电力系统调度是“先决策后看到随机实现”的过程——你要在知道明天实际风况之前决定机组的启停状态这就是典型的两阶段随机规划问题。场景法的基本思路就是把随机变量的连续分布离散化成有限个场景每个场景代表一种可能的风光出力时序并赋予一个发生概率。优化模型在这种场景集上求解相当于同时考虑了“多种未来”因此能得到相对稳健的决策方案。场景生成的任务就是“怎么合理地离散化”场景消减的任务是“离散化之后怎么压缩规模”。1.2 场景在电力系统模拟优化中的角色场景在整个模拟优化流程里处于承上启下的位置。上游是风速、辐照度等原始气象数据要经过数据清洗、归一化、时序建模才能变成出力场景下游是机组组合、经济调度、可靠性评估等优化问题场景的质量直接决定优化结果的工程可信度。我在项目里最直观的感受是优化模型本身再精致如果场景集生成得稀烂结果一样没法看。比如你生成10000个场景塞进机组组合模型算三天三夜得到一个解但场景消减做得太狠把关键的晚高峰大风光场景删掉了那么解虽然在场景集内最优实际运行起来可能直接拉闸限电。场景不是优化模型的“配角”它本身就是决策质量的地基。2. 场景生成方法怎么选2.1 基于统计采样的生成路线统计采样是入门最常用的方法核心思想是从历史出力数据或者概率分布模型中抽样生成大量候选场景。以风电出力为例常用做法是先对历史风速数据拟合成威布尔分布或者经验分布然后用蒙特卡洛抽样产生风速序列再通过风机功率曲线把风速转换成出力。光伏则通常用Beta分布拟合辐照度再叠加云遮挡模型来修正出力。如果只考虑单站且不考虑时序相关性这种方法实现起来非常简单写几十行Python就能跑。但统计采样有一个明显短板它默认各时段之间相互独立生成出来的出力曲线前后波动会非常剧烈和实际风电出力的平滑爬坡特性差得很远。实际风电场出力具有很强的自相关性——前一时刻出力高下一时刻大概率也高一片云飘过来光伏出力下降后也需要一段时间恢复。直接用独立抽样生成的场景时序上“碎”得离谱下游优化模型看到的是现实中几乎不存在的出力曲线。2.2 基于时序模型的生成路线为了保住时序相关性就需要上时间序列模型。风力发电出力场景生成里最经典的是ARIMA模型它的优势在于可以直接刻画时间序列的自回归和滑动平均结构。光伏出力则常和晴雨状态挂钩先用马尔可夫链模拟天气状态转移再在每个状态内拟合出力分布。还有一种思路是Copula方法先用边缘分布分别描述风速和辐照度的分布特性再用Copula函数把它们的相关性结构耦合起来。这个方法在考虑“风电场和光伏电站空间相关”时特别有用。比如在同一个风带上建了三个风电场它们的出力不可能完全独立——一个风带的大风过程会同时影响三个场Copula可以从数据里学到这种联合分布的尾部相关性生成的场景自然带有空间联动特征。实际工程里我建议先对原始出力序列做归一化和去趋势处理再进行时序建模。很多人直接拿原始数据拟合结果模型把季节性趋势和随机波动混在一起生成出来的场景要么整体偏高要么整体偏低概率分布完全失真。2.3 基于数据驱动的生成路线这两年深度学习在场景生成领域也火起来了主流代表是生成对抗网络GAN和变分自编码器VAE。GAN做场景生成的基本逻辑是训练一个生成器输入随机噪声向量输出一条完整的风光出力时序同时训练一个判别器让它分辨“真实历史出力曲线”和“生成器生成的假曲线”。两者互相对抗生成器逐渐学会生成以假乱真的出力场景。VAE则走的是另一条路把历史场景压缩进一个低维隐空间再从隐空间采样解码出新场景。这类方法最大的优势是能自动学习高层特征比如出力曲线的爬坡段、夜间风电大发的形态、晴天光伏的倒U型曲线而不需要手动建模相关性。但实际落地时要注意GAN训练非常不稳定很容易出现模式崩塌——生成器生成的100条曲线长得几乎一模一样多样性完全丧失。VAE相对稳但生成结果的细节可能偏模糊尤其是出力突变点经常被平滑掉。我自己的项目里数据驱动方法一般用在“历史样本不足以覆盖所有运行情况”的场景下作为数据增强手段。如果历史数据本身就有三五年、覆盖了各种极端气象完全可以用更轻量的统计或时序模型搞定没必要上大模型毕竟电力行业的优化计算讲究可控、可解释。3. 场景消减算法的核心与取舍3.1 为什么生成完还要消减假设你用蒙特卡洛抽样生成了一万个风光出力场景每个场景都对应一条48时段或96时段的时序曲线。理论上场景越多越接近真实概率分布但优化模型规模撑不住——机组组合里的启停变量本来就多再乘以场景数求解复杂度指数上升。举个例子一个中等规模的区域电网有30台机组96时段机组组合的混合整数规划问题单场景求解可能只要几十秒但1000个场景的随机机组组合变量数量暴增到数百万级一般商用求解器也很难在可接受时间内收敛。这时候就必须做场景消减用一小部分典型场景去近似原场景集的概率分布。场景消减的目标可以概括成一句话在保持概率分布和时空相关性损失最小的前提下用尽量少的场景代表尽量多的信息。它不是简单“抽几条代表曲线”而是有严格数学定义的问题——一般转化为概率距离最小化问题。3.2 K-Means聚类的用法与坑K-Means是场景消减里最容易上手的算法。做法是把每条出力曲线当作高维空间的一个点维度就是时段数比如96维然后运行K-Means聚类把相似曲线聚成K类用每个类的质心作为典型场景用类内样本占比作为该场景的概率。我的实操经验是K-Means适合场景数量大、且曲线形态差异明显的场景集。比如把“风电大发型”“光伏主导型”“早晚双峰型”这类形态差异大的曲线分开效果一目了然。但有两个致命的细节必须注意。第一个问题是K-Means用均值作为质心这会抹平极端峰值。比如某类里有两条曲线一条晚峰出力900MW一条晚峰出力500MW均值后变成700MW——这个代表场景既不代表高风况也不代表中风况处在一种“中间态”。对调度优化来说这种中间态是最坑的因为它让系统看起来“压力不大”实际运行时却可能扛不住真正的900MW大风。第二个问题是K-Means对时间对齐极度敏感。如果两条爬坡曲线的峰值时段差了几个小时欧氏距离会算得非常大聚不到一类里但其实它们代表的运行风险是相似的。如果有条件可以考虑用动态时间规整DTW距离替代欧氏距离或者先把曲线对齐到同一天气过程再聚类。3.3 同步回代缩减法SR实操比K-Means更贴合场景消减原始定义的是同步回代缩减法Simultaneous Backward Reduction。这个方法的思路不是聚类求均值而是迭代地删掉一个“最不重要”的场景同时把它的概率转移给距离它最近的另一个场景直到剩下的场景数达到目标值。每一步选择删除哪个场景的标准是“概率距离乘积最小”——即让删除场景与替代场景之间的概率距离增量最小。算法实现上需要维护场景之间的距离矩阵和概率向量每删一个场景就更新一次矩阵。虽然计算复杂度比K-Means高但结果的理论性质更好它能保证消减前后场景集的概率分布距离最小化。我用Python实现过一轮核心逻辑大致是import numpy as np from scipy.spatial.distance import cdist def simultaneous_backward_reduction(scenarios, probabilities, target_count): # scenarios: shape (n_scenarios, time_steps) # probabilities: shape (n_scenarios,) n len(scenarios) probs probabilities.copy() idx list(range(n)) dist_matrix cdist(scenarios, scenarios, metriceuclidean) while len(idx) target_count: min_cost np.inf del_idx -1 nearest_idx -1 # 对每个场景找到替代代价最小的删除方案 for i in range(len(idx)): for j in range(len(idx)): if i j: continue # 删除场景i替代场景j的代价 cost probs[idx[i]] * dist_matrix[idx[i]][idx[j]] if cost min_cost: min_cost cost del_idx i nearest_idx j # 删除场景概率转移给最近场景 probs[idx[nearest_idx]] probs[idx[del_idx]] del idx[del_idx] return scenarios[idx], probs[idx]实际使用时要控制消减比例通常建议从几百个原始场景消减到20~50个典型场景。再少的话概率分布形状会走样尤其是长尾的极端场景大概率会被删掉。另外每次迭代都重新计算整个距离矩阵代价比较高工程上一般只更新和删除场景相关的距离行能快很多。3.4 消减质量怎么评估很多同行做完消减就直接丢给优化模型这一步是不负责任的做法。场景消减后一定要做质量评估否则你根本不知道信息损失了多少。常用指标包括消减前后场景集的Wasserstein距离或Kantorovich距离、各时段出力均值和方差的偏差、极端场景覆盖度比如历史10%分位的出力是否还在场景集里、时序自相关系数的保留程度。我在项目中积累的经验是先看均值和方差的偏差偏差控制在5%以内才放心再看消减后场景中是否保留了“最坏情况”场景——可以主动把历史出力最低的几条曲线单独挑出来检查消减后它们是否仍然存在。如果极端场景被削掉了即使整体统计指标很好看调度结果也不可信因为优化模型会把压力完全集中在剩下那些“好日子”上系统性低估运行风险。4. 把场景接入电力系统优化模型4.1 两阶段随机机组组合的基本形态生成和消减完场景之后下一步就是把它接入优化模型。电力系统里最常见的场景应用场景是随机机组组合Stochastic Unit Commitment和两阶段随机经济调度。两阶段模型的逻辑是第一阶段在知道风光出力之前做机组启停决策因为启停需要时间必须提前决定第二阶段看到每个场景的风光出力后在给定启停状态下做经济分配。目标函数是所有场景下的期望运行成本包括煤耗成本、启停成本、弃电惩罚和失负荷惩罚。模型的标准形式可以写成决策变量机组启停状态 u_it第一阶段、机组出力 p_it、弃风量、切负荷量第二阶段目标函数min Σ_t Σ_i (启动成本 运行成本) Σ_s prob_s × Σ_t (弃风惩罚 切负荷惩罚)约束条件系统功率平衡、机组出力上下限、爬坡约束、最小启停时间、备用约束、潮流约束4.2 约束条件怎么写功率平衡约束是一切的底线。每个场景每个时段系统中所有机组出力加上风光出力等于负荷加上网损。这里要注意的是风光出力在场景里已经是“最大可用出力”实际出力可以向下调整——这就是弃风弃光的来源。机组爬坡约束在随机模型中要特别小心。很多初学者把爬坡约束写成每个场景独立满足这在物理上没错但忽略了同一机组在相邻时段处于不同场景时的爬坡耦合关系。实际上机组爬坡是随时间连续变化的物理过程场景切换只发生在模型里物理世界并不会瞬时跳变。严谨的做法是对每个相邻时段对校验所有场景组合之间的出力差是否满足爬坡限制——这一下子就让约束数量爆炸但得到的解才是真实可行的。备用约束也不能只按期望场景设置。我见过一个真实案例场景消减后的平均出力看起来充足备用也按最大单机容量设置但消减遗漏了某条持续低出力场景实际运行时备用全部耗尽最终切了一部分负荷。后来在约束里增加了针对低出力场景的备用充足性校验问题才解决。4.3 从场景到调度决策的闭环流程在实际项目中场景生成和消减不是一锤子买卖而是要和优化模型形成闭环。我的标准做法是这样第一步用历史数据训练场景生成模型生成500~1000个候选场景第二步用同步回代缩减法消减到20~50个典型场景并记录每个场景的概率第三步把这些场景输入两阶段随机机组组合模型求解第四步拿到调度结果之后反查——哪些时段哪些场景出现了备用紧张或弃电严重如果某个场景频繁触发约束边界说明这个区域还需要补充场景第五步回到场景集针对性补充该时段附近的样本重新消减、重新求解。这样做一轮下来场景集和优化模型能够互相校验比“生成一次就用到天荒地老”靠谱得多。尤其是调度结果在某个场景下异常激进或异常保守时多半不是模型错了而是场景集里缺少了平衡该风险的代表样本。5. 常见问题与参数调整经验5.1 消减后调度结果偏乐观怎么办调度结果偏乐观的典型表现是期望成本很低但一拿到实际运行数据就对不上实际弃风量和切负荷都比预期高。这个问题八成出在场景消减删掉了极端场景上。我的排查思路是先画出消减前后场景集的出力包络线。如果消减后场景集的最大出力明显低于原始场景集说明高峰场景被削了弃风风险会被低估反之最小出力抬高了备用风险会被低估。解决办法不是简单增加场景数量而是把极端场景单独保留下来再对剩余场景做消减最后合并。这样相当于人为保证了极端场景的覆盖率。还有一种做法是在目标函数里加风险度量项比如用条件风险价值CVaR替代期望成本把尾部风险显式建模进优化模型。这样即使场景消减偶尔漏掉极端情况CVaR项也会让调度方案更保守防止系统性低估。5.2 场景数量K怎么选这是被问最多的问题。K值太小场景代表性不足优化结果偏乐观K值太大计算规模爆炸求解时间指数增长。我在实际项目里一般这样选先用肘部法则看K-Means聚类误差的拐点得到一个粗略范围然后取K10、20、30、50分别做消减比较消减前后场景集的距离指标变化。当K增加到某个值后距离指标下降明显变缓就说明信息损失已经接近饱和没必要再加。经验上区域电网做96时段机组组合20~30个场景是比较平衡的选择如果计算资源充足可以取50个场景。还有一点要注意场景数量不能只看绝对数还要看每个场景的概率分布。如果消减后某个场景概率超过了0.15说明原始场景集里有大量样本长得很像这个场景过于“主导”会让优化结果偏向该种运行方式。需要检查原始场景是不是真的如此集中还是生成模型多样性不足。5.3 时序特征被消减破坏怎么办消减后的场景有时会出现出力曲线“失真”——前一时刻还在爬坡后一时刻突然掉到谷底和原始历史曲线完全不是一个风格。原因是对场景做距离计算时用了逐点欧氏距离它不包含时序形状信息所以被合并到一起的场景在形态上可能并不相似。解决办法有两个方向一是距离计算换成DTW距离它允许曲线在时间轴上轻微错位匹配更符合出力爬坡过程的相似性判断二是消减后做一次时序平滑修正比如对质心应用滑动平均或者保持原始场景中形状最常见的曲线作为代表。我个人更倾向于用原始场景中距离质心最近的曲线作为代表场景而不是直接用质心这样时序特征不会因平均而衰减。5.4 相关性问题怎么处理单一风电场或光伏电站的场景生成相对简单难的是多个场站之间的空间相关性。比如两个风电场处于同一风带它们的出力变化是联动的单独生成再拼接相关性会彻底丢失。处理相关性比较实用的做法是先做主成分分析PCA或者经验正交函数分解把多个场站的出力分解成若干互相正交的空间模态和时间系数对时间系数做场景生成再重构出场站出力序列。这个方法保留空间相关性的同时大大降低了生成难度。近两年Copula方法也很流行它能显式建模场站间的非线性相关性尾部相关性的刻画比PCA更准确但计算和调参复杂度也更高。我的建议是如果项目周期紧先用PCA构建降维空间再做场景生成快速出结果如果是要发论文或者做长期规划评估值得花时间上Copula模型。我在实际运行中体会最深的一点是场景生成和消减这一套东西看似是优化模型的“前置处理”实际上直接决定优化结果的工程可信度。花在场景质量上的功夫远比你想象的要值得。最后再分享一个小技巧做完消减后千万别急着把原始场景丢进回收站。保留一份原始场景集每次调试完新模型都可以拿它做对照——什么时候消减后场景和原始场景的结果差得不可接受了你才知道算法哪一步走偏了。这套对照习惯让我在不少项目里少走了大弯路。