在新能源并网仿真和电力系统随机调度里,绕不开一个问题:怎么把风电和光伏的出力不确定性,用数学上可处理的形式描述出来。我自己的习惯是,别一上来就上神经网络或者复杂的深度学习模型——很多工程场景下,两个经典分布就够用:风速用Weibull分布,归一化后的光照强度用Beta分布。这套组合建模方法在风资源评估、光伏发电模拟、储能容量配置和随机潮流计算里都用得上,适合做新能源功率预测、电力系统规划仿真的工程师和研究生参考。下面这篇就围绕这套组合的完整流程展开:为什么选这两个分布、参数怎么估、Matlab怎么实现、怎么判断拟合得好不好,以及我实际踩过的几个坑。
1. 为什么风速用Weibull、光强用Beta:物理依据与参数直觉
1.1 风速数据长什么样,Weibull分布怎么对上号
风速分布有几个很明显的特点:右偏、下限贴零、存在小概率的强风事件。大量风电场的实测数据都指向同一个结论,风速的统计分布在绝大多数时段能用Weibull分布描述。这背后有物理逻辑,风速可以看成大量尺度不同、方向各异的湍流脉动叠加后的结果,类似材料强度里“最弱链”模型的极值统计思路,最终落到了Weibull这种形式,而不是简单的高斯钟形曲线。
Weibull分布的概率密度函数是:
f(x) = (k/c) · (x/c)^(k-1) · e^(-(x/c)^k)
其中c是尺度参数,k是形状参数。形状参数k的物理含义很直接:当k小于1时,曲线单调递减,风速大概率集中在很低值;k=1时退化为指数分布;k在2到3之间时曲线有一个明显的单峰,表示中等风速概率最大;k越大,峰越窄、风速越集中。尺度参数c则决定整体量级,约等于平均风速附近的一个尺度指标。
实用中,风电场风速的k通常在1.5到3.5之间,c在6到10 m/s之间。不过这不是固定值,不同地形、不同季节差异很大。知道k和c之后,不光能估计平均功率,还能算特定风速区间的概率,比如“风速落在风机切入风速3 m/s到切出风速25 m/s之间的时间占比”,这是评估年发电量的基础。很多风资源评估软件里,最终给出的结果核心就是这一对参数。
1.2 光照和光伏出力的边界约束,让Beta分布成为自然选择
光伏出力本质上由光照强度决定,两者近似线性。光照强度天然有上下界:夜里是0,晴空最大值受地理纬度、季节和大气质量限制。把光照强度或光伏出力除以额定容量,就得到一个落在[0,1]区间内的随机变量。Beta分布恰好就是定义在(0,1)区间上的连续分布族,概率密度函数是:
f(x) = [x^(α-1) · (1-x)^(β-1)] / B(α, β)
其中B是Beta函数,α和β是两个形状参数。Beta分布的形状极其灵活:α大于1、β大于1时是单峰分布;α等于β时左右对称;α小于1、β小于1时呈U型,说明大量时间落在两端;α等于β等于1时退化为均匀分布。这种灵活性让它能描述光伏出力最常见的两个特征,一是大量夜间零出力,二是中午时段接近满发。
用一个训练模型时的类比:如果数据被限制在0到1之间,你却用一个定义在整个实数轴上的分布去拟合,相当于让模型去学习一个它天生不支持的边界条件。Beta分布就不用做这个痛苦的事,它的支撑集天然匹配。
1.3 为什么不是正态分布,也不是直接用经验分布
我经常看到有人拿正态分布去拟合光伏出力,这个做法在工程上很危险。正态分布定义在整个实数轴上,会给出负的风速或负的光照强度,物理上说不通。当然你可以做截断处理,但截断之后归一化常数、矩估计公式都要跟着改,麻烦得多。
经验分布函数(ECDF)倒是拟合得准,但它没有参数化的外推能力,也没有连续的密度表达式,不方便嵌入随机优化、鲁棒优化这类数学模型。选择参数化的Weibull和Beta,本质上是“在物理合理性和数学可处理性之间取平衡”,这也是两个分布成为行业主流的原因。
2. Weibull与Beta参数估计:三种方法、一套Matlab代码
2.1 矩估计:先给一个粗算起点
矩估计的思路简单直接,用样本均值和方差去匹配理论均值和方差。Weibull的矩估计需要解非线性方程,但工程上有一个近似公式:
k ≈ (σ/μ)^(-1.086)
c ≈ μ / Γ(1 + 1/k)
这里的Γ是伽马函数,μ是样本均值,σ是样本标准差。这个近似公式在k等于1.5到4的区间内足够准,非常适合用来做迭代算法的初值。Beta分布的矩估计更直接,可以用下面这两个公式:
α = μ · (μ·(1-μ)/σ² - 1)
β = (1-μ) · (μ·(1-μ)/σ² - 1)
不过有个前提:样本方差σ²必须小于μ·(1-μ),否则算出来的α、β是负的,没有意义。实际数据一般满足这个条件,但如果样本里混入了大量边界值(0或1),方差会突然变大,这时候需要先清理边界数据再估计。用Matlab实现矩估计的代码如下:
% Weibull矩估计近似公式 mu_w = mean(wind_clean); std_w = std(wind_clean); k_mom = (std_w / mu_w)^(-1.086); c_mom = mu_w / gamma(1 + 1/k_mom); % Beta矩估计 mu_s = mean(solar_clean); var_s = var(solar_clean); alpha_mom = mu_s * (mu_s * (1 - mu_s) / var_s - 1); beta_mom = (1 - mu_s) * (mu_s * (1 - mu_s) / var_s - 1);2.2 极大似然估计:正式建模的首选
极大似然估计(MLE)在统计性质上更优,Matlab也直接给了现成函数,这是我最推荐的正式建模方式。风速数据可以直接用wblfit,光强数据归一化之后用betafit。核心代码很短:
% 风速Weibull参数估计 [param_w, ci_w] = wblfit(wind_clean); c = param_w(1); % 尺度参数 k = param_w(2); % 形状参数 % 光强Beta参数估计,需要先归一化 solar_norm = solar_data / P_rated; % 除以额定容量 solar_clean = solar_norm(solar_norm > 0 & solar_norm < 1); [param_s, ci_s] = betafit(solar_clean); alpha = param_s(1); beta = param_s(2);有一个细节我必须提醒。wblfit返回的第一个参数是尺度c,第二个是形状k,跟文献里习惯写的(k, c)顺序正好相反。我早期就因为在代码里把这两个参数写反过,拟合曲线的峰完全错位,折腾了大半天才反应过来。拿到参数后建议先打印出来看一眼,尺度参数应该在风速量级附近,比如6到10,如果跑出来形状参数是6到10而尺度参数是2,八成就是顺序搞反了。
betafit返回的置信区间ci_s是一个2×2矩阵,第一列是α、β的置信区间,第二列对应另一个参数。在写报告的时候,这个置信区间可以直接用来说明参数估计的可靠性。
2.3 概率图法:快速检查和给审稿人看
对Weibull分布做双对数变换,可以得到一条直线关系:
ln[-ln(1 - F(x))] = k · ln(x) - k · ln(c)
所以把样本的经验CDF变换之后画出来,如果数据点沿着一条直线排列,说明Weibull拟合是合理的。直线的斜率就是k,截距可以反推c。Matlab里专门有wblplot函数来画这个概率图,散点贴得越直,说明分布选得越对。我拿到风速数据的第一件事,不是跑wblfit,而是先跑wblplot,这个习惯帮我避免了很多无效拟合。如果概率图上点明显弯成了S形,说明数据本身可能混了多种风况,这时候拟合出参数也没意义,不如先按风向或季节分组。
Beta分布没有现成的概率图函数,但可以画分位数-分位数图,把样本排序后的经验分位数和理论Beta分布分位数画在一起,偏离对角线越远说明拟合越差。画图代码也很简单:
figure; subplot(1,2,1); wblplot(wind_clean); title('Weibull概率图'); subplot(1,2,2); theoretical_quantiles = betainv((1:N-0.5)/N, alpha, beta); empirical_quantiles = sort(solar_clean); plot(theoretical_quantiles, empirical_quantiles, 'o'); hold on; plot([0 1], [0 1], 'r--'); xlabel('理论分位数'); ylabel('经验分位数'); title('Beta Q-Q图');3. 组合建模的两种思路与代码实现
3.1 独立采样:默认做法,简单且足够用
组合建模最常见的做法,是假设风速和光照彼此独立,分别从拟合好的Weibull和Beta分布中抽取样本,再合成联合场景。Matlab里各有一行核心函数:
rng(42); N = 10000; wind_scene = wblrnd(c, k, [N, 1]); solar_scene = betarnd(alpha, beta, [N, 1]) * P_rated;这样生成的wind_scene和solar_scene就是N个风电、光伏联合出力的随机场景,可以直接喂给蒙特卡洛潮流计算或者储能容量优化模型。独立采样成立的前提,是风速和光照的相关系数较小。实际站点看,风速和光照的相关系数通常在±0.3以内,不同季节、不同地形差异很大。如果只做粗略的容量配置评估,这个假设完全够用。但如果是做极端场景分析,比如要模拟“连续阴雨天且大风”这种极端组合,独立采样会低估联合事件出现的概率,需要引入相关性。
3.2 考虑相关性的Copula耦合:把两个分布“粘”起来
如果需要更严谨地刻画风速和光照之间的相关性,可以用Copula函数把两个边缘分布耦合起来。Copula的核心思想是:先把每个变量通过各自的CDF映射到[0,1]均匀空间,这一步相当于把不同量纲、不同分布的数据都拉到同一个“标准赛道”上;然后在均匀空间里用相关系数矩阵描述变量之间的相依结构;最后从Copula联合分布采样,用逆CDF变换回物理量。Matlab代码如下:
% 把历史数据各自映射到均匀空间 u_wind = wblcdf(wind_clean, c, k); u_solar = betacdf(solar_clean, alpha, beta); % 估计Gaussian Copula的相关系数矩阵 rho = copulafit('Gaussian', [u_wind, u_solar]); % 从Copula采样 N = 2000; u_cop = copularnd('Gaussian', rho, N); % 逆变换回物理空间 wind_cop = wblinv(u_cop(:,1), c, k); solar_cop = betainv(u_cop(:,2), alpha, beta) * P_rated;这个代码最容易被忽略的地方是u_wind和u_solar必须严格在(0,1)开区间内。如果数据里含有0或1,比如光伏归一化后出现0,或者风速数据里出现0,CDF值会是0或1,copulafit就会报错。所以进入Copula计算之前,要先做边界处理。另外,选择Gaussian Copula还是t-Copula也有讲究。Gaussian Copula尾部独立,适合相关性较弱、没有明显极端共现的场景。t-Copula有尾部相关性,能够刻画“大风和弱光同时出现”这种极端组合,但估计参数需要的样本量更大。工程上如果样本量不足5000,直接用Gaussian Copula更稳定。
3.3 场景数量和质量评估:别一股脑抽十万个
生成场景数量不是越多越好。普通蒙特卡洛采样,样本量建议5000到10000才够稳定。但如果你要把每个场景都带入潮流计算,10万个场景的计算量会很可观。这时候可以用拉丁超立方采样(lhsdesign)来减少样本量,同样的样本数下覆盖更均匀,200个LHS场景的覆盖效果往往能媲美5000个普通蒙特卡洛场景。我实际跑储能配置优化时,就是先用LHS抽500个场景做预优化,再用5000个蒙特卡洛场景做验证,效率和精度都兼顾了。
生成场景后一定要做质量评估。核心指标有三项:均值、方差、相关系数。用corrcoef分别计算原始数据和场景数据的相关系数矩阵,偏差超过0.05就要检查是不是Copula参数估计出了问题。还有一个容易漏掉的是分位数检验,特别是95%分位数和5%分位数,这两个值决定了系统极端场景下的安全裕度,比均值更能暴露问题。
4. 拟合优度检验:K-S、卡方与概率图的正确用法
4.1 K-S检验的原理与Matlab写法
K-S检验的原理是比较经验CDF和理论CDF之间的最大纵向距离,这个距离就是K-S统计量。统计量越小,说明拟合越好。Matlab里用kstest实现,关键是把理论CDF以“样本值加理论累积概率”的成对数组传进去:
[h_w, p_w, ks_w] = kstest(wind_clean, 'CDF', ... [wind_clean(:), wblcdf(wind_clean(:), c, k)]); [h_s, p_s, ks_s] = kstest(solar_clean, 'CDF', ... [solar_clean(:), betacdf(solar_clean(:), alpha, beta)]);注意,样本数据必须是列向量,否则kstest会报维度错误。这里有个统计上的陷阱:用同一份数据先估参再做K-S检验,p值会偏乐观,因为参数是从数据里学出来的,模型天然“见过”这些数据。严谨的做法是bootstrap修正或者Lilliefors检验,但工程上做风电、光伏分布拟合时,大家普遍直接用这个简化版K-S检验,只要K-S统计量明显小于临界值,结果就可以接受。所以在报告里,不要只写“p>0.05,通过”,最好把统计量本身也列出来。
4.2 卡方拟合检验的完整步骤
卡方检验适合大样本情况,核心思路是把数据分箱,比较每个箱内的观测频数和理论频数。步骤分四步:
- 把数据分成若干个区间,算出落在每个区间的观测频数。
- 用拟合好的理论分布计算每个区间的理论概率,乘以总样本数得到理论频数。
- 合并期望频数小于5的相邻区间,避免统计量不稳定。
- 计算卡方统计量,查自由度为“有效箱数减参数个数减1”的卡方分布。
Matlab核心代码:
edges = linspace(min(wind_clean), max(wind_clean), 21); obs = histcounts(wind_clean, edges); p_theory = diff(wblcdf(edges, c, k)); exp_count = sum(obs) * p_theory; % 合并期望频数小于5的箱 valid = exp_count >= 5; chi2stat = sum( (obs(valid) - exp_count(valid)).^2 ./ exp_count(valid) ); df = sum(valid) - 3; % 减去2个估计参数和1个总样本约束 p_chi2 = chi2cdf(chi2stat, df, 'upper');这里要注意,箱数的选择没有统一标准。箱太少会丢失分布形状信息,箱太多又会让期望频数过小。我习惯先用直方图看一下数据范围,然后选择20到30个箱,再根据合并规则调整。卡方检验对分箱方式很敏感,换一组边界结果可能就从“通过”变成“拒绝”,所以它更适合作为K-S检验的补充,而不是唯一判断依据。
4.3 图形诊断:三张图看穿拟合问题
统计检验给的是一个量化结论,但图形能告诉你问题出在哪个位置。我从这三个图开始看:
第一张是直方图叠加理论PDF。这是最直观的,一眼能看出峰值位置是否对齐、尾部是否拖得不够。第二张是Weibull概率图,用wblplot画,重点看两端有没有偏离直线。第三张是P-P图或Q-Q图,把经验分布和理论分布的累计概率做对比。P-P图对中间段敏感,Q-Q图对尾部敏感,两个都画最好。
一个真实案例:某地区风速数据用全年样本拟合Weibull后,直方图看峰值吻合得很好,但Weibull概率图两端都翘起来了,说明数据中存在比Weibull预测更多的极端低风速和极端高风速事件。后来我按季节拆分,冬季和夏季分别拟合,概率图就正常了。这个案例说明,如果图形诊断不过关,优先怀疑数据混了不同子总体,而不是急着换分布函数。
5. 实战中踩过的坑与避坑清单
5.1 Beta分布最经典的坑:0和1不能直接进betafit
betafit要求样本严格在(0,1)开区间内。光伏数据每天都有大量0(凌晨和夜间)以及可能有1(满发时段),直接传进去,函数会返回NaN或者Inf。这不是数据有问题,而是Beta分布的支撑集就不包含端点。我见过不少同学卡在这一步,以为是数据下载错了。处理边界有三条路:
- 直接剔除边界值,最简单,适合边界值占比较小的情况。
- 用零膨胀Beta模型(Zero-Inflated Beta),把0或1作为单独的一个离散概率,剩余部分用Beta分布建模。这个模型更严谨,适合光伏数据里夜间时段占比很大的场景。
- 折中方案是对边界值加或减一个极小量,比如1e-6,让数据落进开区间。这个做法能保留样本量,但会让分布估计略微偏置,尤其是当边界值占比超过10%时,偏置不可忽视。
5.2 全年数据会被季节混合“污染”
拿全年8760小时数据直接拟合,得到的分布会呈现一个方差偏大、峰更宽的形态。因为冬季和夏季的风速分布有明显差异,混在一起之后,单峰Weibull模型会被“稀释”成一个更平的峰。我的做法是按季节甚至按月份分别拟合,给每个时段一组独立参数。时序仿真里按月份切换参数,精度会有明显提升。Beta分布也有这个问题,夏季光照强、晴空概率大,冬季弱得多,硬用一个参数组合描述全年,误差很大。
5.3 光伏数据的归一化基准:除以额定还是除以最大
这是很多人忽略的细节。除以额定容量,符合物理意义,但可能出现“超发”数据,也就是归一化值大于1,比如温度较低、辐照较高的时段,光伏组件实际出力可能略超额定值。这会让Beta拟合变差。除以实测最大值,所有数据都落在[0,1]内,但会掩盖“某些时段高发率低”的信息。我的建议是优先除以额定容量,出现大于1的值时单独判断是超发还是数据异常。如果只是为了建模出力分布做随机抽样,两种基准都能用,但写报告时一定要说明清楚用的是什么基准。
5.4 K-S检验在大样本下的敏感性问题
样本量超过5000之后,K-S检验对任何理论分布都几乎能拒绝原假设,因为大样本下经验分布和理论分布的微小偏差都会被检测出来。这时候不要只看p值,要重点看K-S统计量本身,以及它和临界值的相对大小。另一个可行思路是把数据按年度或季节切分成多个子样本,分别做检验,看是否有连续多个子样本都拒绝原假设,这样既能利用大样本的信息,又避免单次检验过度敏感。
5.5 顺手的一个小技巧:先画图,再估参
我每次拿到风速数据,第一件事不是跑wblfit,而是先跑wblplot。如果概率图上点明显弯成S形,说明数据本身可能混了多种风况,比如局地切变、尾流影响,或者数据来源跨了多个地形区域。这时候就算拟合出参数也没有实际意义,不如先按风向、季节或地形分组。这个习惯帮我避免了很多无效拟合。Beta分布也是一样,先画直方图看形状,如果出现明显的双峰,说明数据里有异常时段,需要排查数据清洗逻辑。
另外一个经验是,无论用哪种检验方法,都要和图形结合着看。统计量只是把偏差压缩到一个数字上,图形能直接告诉你偏差在头部、中部还是尾部。尾部偏差对风电光伏建模尤其重要,因为极端天气下的出力场景才是电力系统安全运行最关心的。把图形诊断作为第一道关卡,把K-S或卡方检验作为第二道量化关卡,两层都过了,这个分布拟合才敢真正用到生产环境里。
我在实际项目里比较常用的是“先分季节拟合参数,再在时序模拟里按月份切换参数”的组合方式。风电光伏联合出力场景生成之后,拿去跑储能容量配置和线路潮流风险评估都很顺。还有一个经验是,Copula耦合时不要只看相关系数绝对值大小,要同时观察生成的联合散点图。有时候相关系数差不多,但散点形态完全不同,尤其是尾部方向,对极端场景影响很大。这套Weibull加Beta的组合不是什么高深模型,但胜在稳定、解释性强,在工程场景里够用好用。