1. 为什么风光发电需要“场景生成”
第一次看到“当风光发电遇上薛定谔的猫”这个标题时,我差点笑出声——这俩东西怎么凑到一起了?但仔细琢磨,这个比喻其实精准得可怕。
做过新能源功率预测或电力系统调度的人都知道,风光出力的不确定性是绕不开的坎儿。光伏电站明天上午10点的出力到底是多少?风电场后天凌晨的出力曲线长什么样?在真实出力数据“观测”之前,它就像那只既死又活的猫,同时处于“大发”和“小发”的叠加态。而蒙特卡洛场景生成,就是对这个叠加态做大量随机观测,用一组概率场景去逼近可能的未来,从“测不准”到“测概率”。
先说说这个需求的真实背景。电网调度和电力市场交易天然需要前瞻性——我要提前安排火电启停、储能充放电、跨区输电计划。过去我们依赖单一的点预测结果:明天最高负荷多少、新能源出力多少,按一个确定值安排。但实际情况是,风光出力受气象过程影响极大,点预测误差动辄20%-30%,极端天气下误差更大。你按一个确定值去做计划,实际运行偏差一大,就得靠备用容量硬扛,成本高不说,还有安全风险。
这几年新能源装机规模突飞猛进,新能源渗透率持续走高,电力系统的随机性陡增。单一确定性预测已经不足以支撑精细化的调度决策,业界转向场景法(Scenario-based Approach):用一组带概率的出力场景替代单一预测值,把不确定性显式地带进优化模型。这里面的核心问题就是——如何生成高质量、贴合实际的相关性场景?这就轮到蒙特卡洛方法登场了。
这套方法论的核心适用人群很明确:新能源功率预测工程师、电力系统调度运行人员、研究风光不确定性建模的算法工程师、储能容量配置与微电网规划设计人员。无论你处在哪个环节,场景生成都是连接“预测结果”和“优化决策”的桥梁。
我记得自己刚接触这个领域时,被“场景生成”这个概念绕了不少弯路——以为就是加个随机噪声生成一堆曲线,后来才明白,真正的问题在于:你生成的场景集是否在概率意义上忠实还原了真实出力的统计特性?如果还原不了,下游的优化结果就是空中楼阁。这篇文章我会把自己从建模、采样到相关性处理的完整实操路径拆开讲,希望能帮你少踩几个坑。
2. 核心设计拆解:从“不确定性”到“概率场景”
2.1 薛定谔的猫与风光出力的叠加态
薛定谔的猫这个思想实验,本质是在讨论“观测之前的系统状态”。把这个逻辑移植到风光发电上:在明天的日出之前,某光伏电站的出力曲线并不是一个确定值,而是所有可能出力的概率叠加——晴天可能是满发,阴天可能是低发,阵雨天气可能是间歇性波动。
电力调度面对的尴尬在于:真实出力只能等到“观测”发生(明天太阳真的升起)才能确定,但调度决策必须在“观测”之前就做出来。这正是场景生成存在的根本意义:既然无法消除不确定性,就把可能性完整地带入决策过程。
我们团队在实际项目中,常常用一句话概括这个逻辑:场景生成不是让预测更准,而是让决策更稳。与其赌一个点预测值然后祈祷不要偏差太大,不如准备100条可能的出力曲线,让优化器在所有这些可能性中找到期望收益最大、风险可控的调度方案。
这一思路在行业里已有成熟应用:随机机组组合(Stochastic Unit Commitment)、鲁棒优化(Robust Optimization)、储能容量置信度评估等,全部依赖前端的场景输入。场景质量直接决定了优化结果的有效性,这也是为什么场景生成绝不是“拍脑袋加个噪声”的简单活计。
2.2 蒙特卡洛方法的本质逻辑
蒙特卡洛方法的核心思想,用一句话说就是:通过大量随机抽样,用频率逼近概率。
放到风光出力场景生成场景里,它的操作链条是这样的:
第一步,建立风光出力的概率模型。你要知道光伏/风电出力在某个时刻服从什么分布——不同天气类型下分布的形态完全不同。
第二步,从分布中随机抽样,得到大量可能的出力值。成千上万次抽样后,样本的统计特征会趋于模型的真实期望——这就是大数定律在起作用。
第三步,对抽样结果做相关性处理。这里有个容易忽略的细节:下一时刻的风光出力与上一时刻高度相关,你抽样时不能每个时刻独立抽,必须把时序相关性、风光之间的相关性都考虑进来,否则生成的就是“白噪声序列”,完全没法用。
第四步,场景缩减。抽个5000条场景喂给优化模型,计算量爆表。业界通常把场景缩减到几十条,保留概率信息的同时保证计算可行。
这一整套流程下来,本质上是在回答一个问题:在当前预测信息和历史统计规律的约束下,未来风光出力最可能的概率空间长什么样?
2.3 为什么不用简单随机抽样
很多人刚上手时图省事,直接对预测曲线加高斯噪声,反复加个几百次就拿出来当场景集用。项目初期我踩过这个坑,这个做法在低渗透率、对精度要求不高的场景下勉强能看,但一遇到极端天气或者高比例新能源接入,立刻露怯。
原因有三层:
第一,高斯噪声是独立同分布的,完全没有捕捉到时序自相关性。真实的风光出力曲线是平滑波动的,不会一秒钟从满发跌到零再跳回满发。你拿白噪声场景去做调度,优化器会以为出力波动可以极其剧烈,给出的调度方案过于保守。
第二,简单加噪声的扰动幅度是固定的,无法刻画不同天气过程下不确定性程度的差异。晴天的光伏出力波动小,多云天波动大,雷暴天甚至可能剧烈跌落。固定幅度的噪声把这种差异性完全抹平了。
第三,单一站点加噪声勉强能模拟,但风电场群、光伏电站群之间的空间相关性完全无法刻画。实际运行中,一片区域的风电场出力有很强的同调性——大风过程来了,整个区域的风机一起大发。这个相关性如果不建模,多站点联合场景就是失真的。
所以专业的场景生成一定是从“统计建模+抽样+相关性控制”这个完整链条来做的,而不是简单加噪声。下面我会把每一步的原理和关键参数讲透。
3. 实操过程:从数据清洗到场景生成全流程
3.1 数据准备与气象分型
开始建模之前,先把数据底子打好。这是整个流程里最容易被轻视、但对最终场景质量影响最大的一环。
我们需要的数据包括三类:历史出力数据、历史气象再分析数据、数值天气预报(NWP)数据。出力和气象数据用来建模,NWP数据用来确定“当前处于什么样的气象条件”。
数据清洗这一步有几个关键动作:
剔除异常数据。风光电站运行中难免有停机检修、限电、通信故障等情况,这些数据会严重污染统计模型。我常用的方法是:出力超过装机容量105%的直接剔除,连续零出力超过6小时的标记为停机(夜间光伏除外),NWP与实测偏差超过3倍标准差的标记为异常。
处理限电问题。这是国内新能源场站普遍存在的痛,调度限电会导致实际出力低于可用出力,直接用受限数据建模会低估发电能力。有条件的场站建议用同区域不受限时段的出力-辐照度关系反推受限时段的可用出力。
气象分型。这一步直接决定建模效果。你会发现,不同天气类型下出力的概率分布特征差异巨大:晴天光伏出力曲线平滑,Beta分布拟合效果好;多云天气出力波动剧烈,双峰分布甚至混合分布才有解释力。风电也类似:大风过程、小风过程、阵风过程的出力特性完全不一样。
我的做法是先用NWP数据做K-means聚类,把历史时段分成若干典型气象类型,然后分别对每个类别建模。这样每类场景的统计特征都足够干净,生成出来的场景物理意义也更清晰。
3.2 出力概率分布建模
分布建模是核心中的核心。光伏和风电的出力分布特性差异很大,建模方法也不同。
光伏出力的理论分布是Beta分布,这是一个挺好的起点。Beta分布定义在[0,1]区间上(归一化后的出力),形态由两个形状参数α和β控制,可以呈现均匀、单峰、偏态等多种形态,恰好匹配光伏出力的特性。
参数估计用极大似然估计法即可。假设某气象类型下有N个归一化出力样本x₁, x₂, …, xₙ,Beta分布的似然函数为:
L(α,β) = Π xᵢ^(α-1) · (1-xᵢ)^(β-1) / B(α,β)
对似然函数取对数后求偏导并令其为零,通过牛顿迭代法解出α和β的估计值。实际操作中可以直接调开源统计库,几分钟就能出结果。
风电出力的情况复杂一些。严格来说风电出力是风速的非线性函数,从风速分布可以推导出力分布。风速通常用两参数Weibull分布描述,出力与风速之间存在三段式功率曲线关系:切入风速以下出力为零,额定风速以下出力随风速近似立方增长,额定风速以上出力恒定。
但从工程角度,不少项目直接对风电出力本身做分布拟合。好处是绕开了风速-出力非线性变换带来的误差传播,坏处是出力在0和额定值处有明显的概率堆积——低于切入风速时出力为零,高于额定风速时出力恒为额定值,连续分布模型很难刻画这两个堆积点。
一个高效的解法是用混合分布:用一个离散概率质量表示零出力事件(概率p₀)和满发事件(概率p₁),中间段用连续分布拟合。这个“离散+连续”的混合模型在工程实践中表现远好于单一连续分布。
当然,选了哪种分布,都要做拟合优度检验。常用的有K-S检验和A-D检验。K-S检验对分布中心区域的偏差敏感,A-D检验对尾部偏差更敏感——风光出力场景恰恰关注极端情况,所以A-D检验更值得参考。检验不通过就换模型,不要硬凑。
3.3 分层抽样方法:LHS与Sobol序列
分布模型建好后,进入抽样环节。这里有个关键选择:直接用简单随机抽样(蒙特卡洛)还是用更高级的分层抽样方法?
简单随机抽样的效率问题在于:抽样点是随机撒的,会有大量区域样本过密、某些尾部区域样本稀疏。要拟合出分布尾部的统计特征,需要抽非常多样本,计算代价大。
我强烈推荐拉丁超立方抽样(LHS,Latin Hypercube Sampling)作为默认选项。LHS的原理是把[0,1]区间均匀分成N层,每层恰好抽一个样本,这样就保证了样本在概率空间均匀覆盖,尾部特征也能有效保留。
具体到实操:假设我们需要生成M个场景、T个时刻,LHS的操作过程是:
对每个时刻t(t=1,2,…,T),生成M个[0,1]区间上的分层样本:先把[0,1]区间分成M等份,每份里随机取一个值,然后对M个值做随机排列。这样每个时刻的M个采样值在[0,1]上均匀分布且无重叠。然后用分布函数的逆变换F⁻¹(u)把均匀样本映射到出力分布空间。
你可能会问:为什么每个时刻的样本要随机排列?因为如果不打乱顺序,所有时刻的分层位置都一样,会造成各时刻抽样之间的虚假强相关。随机排列保证了时刻间的独立性,相关性问题后面用专门的方法处理。
LHS相比简单随机抽样,在相同样本量下方差显著更小。一个直观的经验:想达到同样的分布拟合精度,LHS需要的样本量大约只有简单随机抽样的三分之一到二分之一。在场景生成这个场景下,意味着用更少的场景量就能得到同样可靠的概率覆盖。
如果追求更高质量的分布覆盖,可以考虑Sobol序列——这是一种低差异序列,比LHS的均匀性更好,且序列是确定性的,可复现性强。但Sobol序列的实现细节比LHS复杂,初学者建议先从LHS入手。
3.4 时序相关性与空间相关性处理
抽样完成后,你会得到一堆“各时刻独立抽样”的散点序列。这时候直接拼接成场景是行不通的——真实的风光出力是平滑连续变化的,不是每个时刻独立跳变的。不加处理直接上送的结果就是一堆毛刺状曲线,物理上完全不成立。
业界标准的处理方法是Cholesky分解相关性的引入。核心思路是:先估计出各时刻出力之间的相关系数矩阵Σ,然后用Cholesky分解把独立抽样序列变换成具有目标相关性的序列。
具体做法可以这样理解:假设Z是独立标准正态抽样序列(LHS抽样后通过正态逆变换得到),我们要得到相关的正态序列Y,使得Y的相关系数矩阵等于目标矩阵Σ。对Σ做Cholesky分解得到下三角矩阵L,满足Σ = LLᵀ,则Y = LZ就具有目标相关性。
用哪个矩阵做相关系数矩阵?标准做法是用历史出力数据计算时序相关系数矩阵。但直接算会有问题:实际出力的相关性是非平稳的——晴天光伏出力前后时刻相关性极强,阴天相关性就弱很多,全天固定一个相关系数矩阵会失真。
一个务实的做法是分时段处理:把一天分成若干典型时段(例如按小时粒度分24个时段),(或者按气象类型分别估计相关系数矩阵),每个时段内的时序相关性分别建模。分块处理虽然牺牲了一点精度,但工程上完全够用,而且大大简化了计算。
还有一个必须注意的点:光伏出力存在“硬边界”约束——日出前出力恒为零,日落后出力恒为零,白天出力非负且有装机上限。直接对正态空间的相关序列做逆变换,可能出现负数或超过上限的情况。处理方法是截断处理或采用带边界的分布变换,实操中我常用的做法是生成后在物理边界处做clip操作,然后再用事后平滑处理。
空间相关性同样重要。多个风电场之间的出力联动由大气运动过程驱动,相关性可能高达0.7-0.9。如果你只做单站点独立场景,捕捉不到这种联动,那下游的多站点联合优化就无从谈起。多站点相关性的处理类似时序相关性:先估计站点间相关系数矩阵,用Cholesky分解(或特征分解)施加到抽样序列上。这里有一个更精细的进阶选项:Copula函数建模,它可以刻画非线性的尾部相关性——极端天气下风电场群同时满发或同零出力的概率远高于正态假设下的估计值。
3.5 场景缩减:从上千条到几十条
抽样5000条场景直接丢给随机优化模型是不现实的,计算时间会爆炸。因此需要一个**场景缩减(Scenario Reduction)**步骤。
业界常用的方法是同步回代消除法(Simultaneous Backward Reduction),思路是:从初始场景集中逐步删减场景,每次删除一个对整个场景集概率分布影响最小的场景,并把被删场景的概率累加到与之最相似的保留场景上,直到剩余场景数达到预设目标。
算法核心公式是Kantorovich距离——衡量两个场景之间的“距离”。对两个场景ξ和ξ',距离定义通常取:
d(ξ, ξ') = [Σᵢ |ξᵢ - ξ'ᵢ|ᵖ]^(1/p)
实操中p取1或2,对应曼哈顿距离或欧氏距离,你可以认为这就是“两条出力曲线的差异程度”。
每次迭代选择使场景集概率距离增加最小的场景删除,并做概率转移。贪心算法实现简单,效果好,计算量也在可接受范围内。
从5000条缩减到50条,概率信息的损失控制在什么水平?业界经验值是:缩减后的场景集与原场景集的Kantorovich距离增量不超过3%-5%时,对下游优化结果的影响可以忽略。
k-means聚类也是一个常用思路——把5000条场景聚成50类,取每类质心作为代表场景,每类的样本占比作为场景概率。k-means的优点是实现简单、速度快,缺点是聚类中心可能不是实际存在的场景,会丢失一些物理约束信息(比如峰值位置、爬坡速率)。同步回代消除法保留实际场景,物理意义更可靠。
3.6 场景树构建进阶思路
前面讨论的是静态场景集(scenario fan)——假设我们只知道当前状态,对未来不确定性的模拟。但在真实调度中,信息是逐步更新的:今天做明天的计划时只有今天的预测,明天早上做日内滚动计划时预测已经更新。这个时序信息更新过程可以用**场景树(scenario tree)**来建模。
场景树的结构是:根节点是当前状态,每个节点分叉出多个子节点表示下一阶段可能的出力状态,不同阶段的节点通过条件概率连接。生成场景树的关键是从历史数据中估计转移概率——给定当前出力状态,下一时刻转移到各状态的概率。
实操中,一种高效的做法是:先把连续的出力空间离散化成若干状态区间,然后基于历史时序数据统计状态转移频次,得到转移概率矩阵。生成场景树时,从根节点出发按概率抽样逐步展开即可。
还有一种进阶思路是分位数回归场景树:用NWP的预测值作为协变量,对不同分位点分别建模,得到条件分位数曲线——直接把“当前天气预报”和“未来不确定性范围”关联起来。这个方法对预测信息的利用更充分,生成的场景树条件性更强。
场景树在随机动态规划、多阶段随机机组组合中应用广泛,如果你做的是日内滚动调度,值得深入研究这条技术路线。
4. 一个完整实战案例:风光联合场景生成
理论讲得再多,没有完整跑通一遍等于白讲。这里分享一个我近期做的实操项目,从数据到最终场景输出的完整链条,你可以直接参考复现。
4.1 项目背景与参数设定
模拟项目X:某区域电网需要评估新能源渗透率提升对系统调峰的影响,需要生成该区域未来24小时的风光联合出力场景集。
基础参数:
- 风电场A:装机容量200MW,历史出力数据3年,时间分辨率15分钟
- 光伏电站B:装机容量150MW,历史出力数据3年,时间分辨率15分钟
- NWP数据:气象预报结果,时间分辨率1小时,细化为15分钟
- 场景需求:24小时场景,时间分辨率1小时(24个时刻),最终输出100个场景
这个参数设定基本代表了典型的区域评估类项目——不需要特别高的时间分辨率,但需要足够的场景量来覆盖不确定性空间。
4.2 分步实现与关键代码
第一步,数据预处理。加载3年历史数据,清洗异常点,将出力归一化到[0,1]区间,标记气象类型。
第二步,气象分型聚类。对NWP特征(辐照度、云量、风速、风向、温度)做K-means聚类,设定K=5。这个K值是个经验选择,试过K=3到K=8,K=5时每类样本量充足且统计特征差异明显。聚类结果用轮廓系数验证,轮廓系数应该高于0.5才算分型有效。
第三步,分布建模。对每个气象类型分别拟合风光出力分布。光伏用Beta分布,风电用混合分布。
第四步,LHS抽样+相关性处理。核心代码如下:
import numpy as np from scipy.stats import beta, norm # 抽样参数 n_scenarios = 5000 T = 24 # 24个时刻 # LHS抽样:生成[0,1]均匀分层样本 def lhs_sample(n_samples, n_dims): samples = np.zeros((n_samples, n_dims)) for dim in range(n_dims): # 每层随机取值 u = (np.arange(n_samples) + np.random.uniform(0, 1, n_samples)) / n_samples np.random.shuffle(u) samples[:, dim] = u return samples # 生成LHS均匀样本 u_pv = lhs_sample(n_scenarios, T) u_wind = lhs_sample(n_scenarios, T) # 通过逆变换得到Beta分布样本(光伏) # 假设Beta参数为alpha=3.2, beta=2.1 alpha_pv, beta_pv = 3.2, 2.1 pv_samples_raw = beta.ppf(u_pv, alpha_pv, beta_pv) # 光照硬边界处理:加入日出日落约束,夜间出力置零 solar_hours = np.zeros(T) solar_hours[6:18] = 1 # 假设06:00-18:00有效光照 pv_samples = pv_samples_raw * solar_hours # 风电混合分布抽样 # 零出力概率 p0=0.15,满发概率 p1=0.05 p0, p1 = 0.15, 0.05 u_wind_zero = u_wind[0, :] < p0 # 判断零出力 u_wind_full = (u_wind[0, :] >= p0) & (u_wind[0, :] < p0 + p1) wind_inter = ~(u_wind_zero | u_wind_full) # 中间段用Beta分布拟合 wind_samples_temp = beta.ppf((u_wind[0, :] - p0) / (1 - p0 - p1), 2.0, 2.5) wind_samples = np.where(u_wind_zero, 0, np.where(u_wind_full, 1, wind_samples_temp))这段代码核心做了三件事:LHS均匀分层采样、通过逆变换把均匀样本映射到目标分布、对光伏做了光照边界约束。但注意,目前每个时刻的抽样是独立的,未加入时序相关性。
时序相关性的引入:
# 计算历史数据的时序相关系数矩阵 # hist_data形状: (n_samples, T) corr_matrix = np.corrcoef(hist_data.T) # Cholesky分解 L = np.linalg.cholesky(corr_matrix) # 把独立正态样本转换为相关正态样本 # 先把均匀分布样本转为正态样本 z_pv = norm.ppf(u_pv) z_wind = norm.ppf(u_wind) # 施加相关性 z_pv_corr = z_pv @ L.T z_wind_corr = z_wind @ L.T # 再转回均匀分布样本 u_pv_corr = norm.cdf(z_pv_corr) u_wind_corr = norm.cdf(z_wind_corr) # 最终映射到出力分布 pv_final = beta.ppf(u_pv_corr, alpha_pv, beta_pv) * solar_hours这里有一个容易被忽略的细节:Cholesky分解需要相关矩阵为正定矩阵,但历史数据算出的相关系数矩阵偶尔会出现非正定情况(尤其是时刻数多、数据量不足时)。处理办法是加一个小的对角扰动:corr_matrix += np.eye(T) * 1e-6,这在实际项目中能避免很多数值问题。
第五步,场景缩减。用同步回代消除法把5000条场景缩减到100条。核心逻辑是迭代计算场景间的距离矩阵,删除对整体分布影响最小的场景,并把其概率转移给最近的保留场景。
# 场景距离矩阵计算(欧氏距离) from scipy.spatial.distance import cdist def scenario_reduction(scenarios, n_retain): n_scen = len(scenarios) probs = np.ones(n_scen) / n_scen # 初始概率均匀 while len(scenarios) > n_retain: # 计算距离矩阵 dist_matrix = cdist(scenarios, scenarios, metric='euclidean') np.fill_diagonal(dist_matrix, np.inf) # 排除自身 # 计算每个场景删除后造成的概率距离增量 cost = np.zeros(len(scenarios)) for i in range(len(scenarios)): # 找到与场景i最近的场景j j = np.argmin(dist_matrix[i]) cost[i] = probs[i] * dist_matrix[i][j] # 删除成本最低的场景 idx_delete = np.argmin(cost) j = np.argmin(dist_matrix[idx_delete]) # 概率转移 probs[j] += probs[idx_delete] # 删除场景 scenarios = np.delete(scenarios, idx_delete, axis=0) probs = np.delete(probs, idx_delete) return scenarios, probs这里值得专门提醒一下:概率转移是同步回代消除法的关键细节,被删场景的概率必须加到它最近的保留场景上,否则缩减后的总概率不为1,场景集的概率质量会损失。
第六步,场景可视化与统计检验。这一步不可省略,我通常会做三个检查:
看曲线形态是否合理。真实场景应该平滑连续,无剧烈跳变;光伏场景夜间出力全零、白天平滑变化;风电场景有波动但变化速率合理。
看分布拟合是否准确。把缩减后场景集的各时刻分位数与原始历史数据的分位数对比,误差控制在5%以内算合格。
看相关性保持。计算缩减后场景集的风光相关性、时序自相关性,与历史数据对比。如果相关性偏移过大,需要调大保留场景数或优化缩减策略。
这里的代码只是核心逻辑演示,实际工程中需要考虑的因素更多,比如多站点的联合抽样、Copula模型、条件分位数回归等,这些我下面逐步展开讲。
4.3 风光相关性处理的关键细节
风光联合场景里,风电和光伏之间的相关性是一个微妙但必须处理的问题。从气象物理过程看,光伏出力和风电出力天然存在一定负相关性——晴天时光伏大发但风往往较小,阴雨大风天气时风大但光伏出力弱。这个相关性在不同地区、不同季节强度不一。
处理方式与前面类似:构造风光联合出力序列,计算协方差矩阵(维度为风光总时刻数),做Cholesky分解施加联合相关性。但这里必须注意一个实操中的“坑”:风光出力的量纲差异很大——200MW风电场和150MW光伏电站的出力波动幅度不同,直接算相关系数矩阵可能掩盖真实关系。建议先各自归一化到[0,1],再计算Pearson相关系数,施加相关性后再按各自装机容量反算回实际出力值。
另一个方案是用Copula模型描述风光出力的联合分布。Copula函数的优势是把边际分布与相关性结构解耦——边际分布随便选,相关性结构单独建模。t-Copula相比高斯Copula有更厚的尾部,能捕捉极端天气下风光同时极端出力的联合概率,这对于风险评估类应用价值很大。
4.4 场景质量评估与验证
生成完场景别急着用,先做一波质量评估。我通常用以下三类指标:
统计覆盖性指标:检验场景集是否在概率意义上覆盖了真实出力的可能范围。做法是取历史上某段时间的真实出力,计算它在生成的场景集中处于什么分位水平。如果真实出力经常落在场景集的5%分位以下或95%分位以上,说明场景集的不确定性范围被低估了,需要调整分布参数或增加场景量。
误差分布指标:把场景集各时刻的期望值与真实值比较,计算平均绝对误差和均方根误差。场景期望值本质上等价于一个概率预测,误差应该与专业的概率预测方法的CRPS分数(连续排序概率分数)相当。CRPS越低越好,它同时衡量了锐度(不确定性范围的紧凑性)和校准度(不确定性范围的准确覆盖)。
经济性指标:这个指标最直观——把生成的场景接入下游调度模型,看与真实场景下运行结果的目标函数偏差。偏差在可接受范围内(通常5%-10%)说明场景集对决策的支持是有效的。
如果评估不通过,逐层排查问题:数据清洗是否彻底?分布拟合是否准确?相关性系数矩阵是否陈旧?场景缩减是否过度?很多时候问题出在看似不起眼的数据预处理环节,而不是高级算法环节。
5. 常见问题与避坑经验
5.1 场景生成结果“太规整”
常见情况是生成的光伏场景曲线张张相似,变化模式单一,阴雨天场景和晴天场景区分度不够,或者风电场景的波动幅度明显偏小。
这种问题通常是分布建模时把所有气象类型混在一起拟合导致的。解决办法就是前面说的气象分型——先聚类再分别建模。如果做完分型高级模型仍“太规整”,就要检查是不是相关性矩阵过强了。实操里我发现一个规律:历史数据时段过长(比如3年混合)计算出的平均相关性往往会“稀释”极端场景的形态。建议对每类气象分别估计相关系数矩阵,并且在生成极端天气场景时直接用极端天气时段的相关系数矩阵。
5.2 初始场景数量如何确定
很多人问我:为什么抽5000条而不是1000条?其实这个数字不是固定的,取决于下游使用方式和计算资源。
如果你直接使用场景集(不走缩减),那初始场景数就是你最终使用的场景数,需要平衡计算耗时和代表性。一般来说,50-200条可直接使用的场景是普遍可接受的范围。
如果你做缩减,初始场景数可以大一些。经验是初始场景数应该是目标保留场景数的30-50倍,这样缩减算法才有足够的“素材”从中挑出代表性场景。5000条对应100条的保留目标,符合这个比例关系。
初始场景数过少有代表性不足的问题,初始场景数过多则计算距离矩阵(O(n²)复杂度)会让内存和计算时间爆炸。5000条的规模,距离矩阵大约200MB内存,还算可接受。
5.3 风机出力“零堆积”处理不当
风电出力的一个明显特点是零出力概率高(无风时段)和满发概率高(大风时段)。如果用连续分布硬拟合,这两端的概率估计会严重偏差。场景生成后你会发现:零出力场景的比例明显少于实际,或者满发场景缺失。
解法就是前面说的混合分布:零出力、中间段、满发三部分分别建模,同时用离散概率控制两端质量。具体概率值随时间变化,比如夜间风速通常较大,满发概率更高;白天风速可能较小,零出力概率更高。建模时可以对每个时刻分别估计p₀和p₁,然后用平滑曲线做后处理。
5.4 场景缩减后的概率失真问题
场景缩减贪心算法的输出结果有一个潜在坑:概率分布会逐渐“偏离”原始场景集。某些中间概率场景被保留但概率被累积得过高,或者极端场景被完全删除。
规避方法有两种:一是缩小缩减率,不要一口吃成胖子——从5000直减到50的失真一定大于分步缩减(比如先减到500再减到100)的失真,分步处理整体也更稳定;二是缩减后做一次概率再校准——用缩减后的场景集重新计算各分位数,与原始场景集对比,对偏差过大的分位数做局部概率修正。
这个方法在很多开源工具里没有被直接支持,但工程上非常实用。样本概率本身就是离散估计,来源是场景数的频率逼近,缩减后适当校准并不会破坏物理一致性。
5.5 多站点联合场景的维度灾难
多站点场景生成时,相关系数矩阵的维度是“站点数×时刻数”,维度一大,协方差矩阵的参数估计就非常不稳定。比如5个站点、24个时刻,协方差矩阵就是120×120,要稳定估计需要海量历史数据,而且Cholesky分解在这类高维非正定问题上的数值稳定性很差。
务实的方案是两步走:先做空间相关建模,再做时序相关建模。空间相关用Copula或PCA(主成分分析)压缩维度,识别出区域出力变化的主导模式;时序相关性在降维后的主成分空间里建模。这样把“站点×时刻”的二维相关结构分解成更可控的低维问题,工程上可靠得多。
还有一个偷懒但有效的做法:按区域聚合。如果下游应用不是特别要求单站点分辨率的联合优化,可以把同一区域的风电场/光伏电站聚合为一个虚拟电站,大大降低维度。聚合后的场景一次生成,计算量小,稳定性高,在很多区域级评估项目中完全够用。
6. 实战心得与进阶建议
写到这里,把我自己的体会和踩坑经验做个总结分享。
蒙特卡洛场景生成这件事,入门门槛并不高——会调库、会写基本代码就能跑通流程。但要做得好,关键不在算法多先进,而在对物理过程的理解和对细节的把控。我见过太多团队在分布拟合上花大力气,却在数据清洗上草草了事,结果模型再高级也救不回输入数据的质量问题。数据清洗和气象分型做不好,后面所有环节都是在放大错误。
还有一个容易被忽视的要点:场景生成不是“一锤子买卖”。气象过程是非平稳的,分布参数和相关矩阵需要定期更新。我见过不少项目上线时效果很好,跑了半年后场景质量明显下滑——原因就是模型参数还停留在几个月前的统计特征上。建议建立滚动更新机制,每季度或半年重新估计一次分布参数。
如果你研究得更深,有几个进阶方向值得跟踪:
- 生成式模型:最近两年,扩散模型和生成对抗网络被尝试用于场景生成,在处理高维复杂时空相关性方面潜力不小。生成图像成功应用的那套模式,本质是在高维空间学到数据分布的隐变量表达。不过说实话,这些方法目前的可解释性和稳定性还比不上传统统计方法。
- 条件生成:不满足于“生成通用的可能场景”,而是“给定NWP条件生成对应场景”。分位数回归、Transformer类序列模型都是可选方案,核心价值是让场景集与当天的具体气象预报对齐,预测条件性更强,比无条件的场景集更利于下游决策。
- 在线场景生成:与滚动优化配合,每个调度周期重新生成场景,实时性与计算效率的权衡下,LHS+快速场景缩减仍然是多数团队的选择,但算法实现细节上还有很多优化空间。
我们回到标题。薛定谔的猫告诉我们,量子系统在观测前处于叠加态,观测本身改变了系统的状态。风光出力没有量子效应那么玄妙,但逻辑是相通的——在你“观测”(获取真实出力数据)之前,未来的出力分布是概率的、叠加的。蒙特卡洛场景生成做的事情,就是对这个叠加态做足够多次“虚拟观测”,让决策者在真实“观测”到来之前,就已经对所有可能的结果做好了准备。
我做场景生成项目这几年,一个最深的体会是:这个方向的价值不在于算法本身多精妙,而在于它让电力系统的决策从“基于一个预测赌未来”升级为“基于概率分布管理风险”。这个转变背后,是新能源渗透率提升带来的必然需求——我们无法消除风光的不确定性,但可以学会与不确定性共处,而蒙特卡洛场景生成,就是共处的工具箱里最趁手的那把扳手。
最后分享一个小技巧:如果你是刚开始接触这个方向,不要一上来就追求花哨的高级模型,把Beta/Weibull拟合、LHS抽样、Cholesky相关、同步回代缩减这四板斧练熟,已经能解决现实中80%的问题。在此基础上再逐步引入Copula、分位数回归、场景树等高级方法,循序渐进的路径是最稳的。