基于Weibull、Beta、Normal分布的风光负荷场景生成及K-means场景削减在电力系统规划中的应用
1. 为什么电力系统规划需要“场景”?
如果你玩过模拟经营类游戏,比如规划一座城市的电力供应,你很快就会发现一个头疼的问题:明天会刮多大的风?太阳有多晒?工厂和居民会用多少电?这些都不是板上钉钉的数字,而是充满了“也许”、“可能”和“大概”。
在真实的电力系统规划中,工程师们面临的正是这样一个充满不确定性的世界。传统的确定性规划,比如“假设明天风速是5米/秒,光照强度是0.7,负荷是1000兆瓦”,然后去设计电网,结果往往是一到实际运行就“翻车”。因为现实是,风速可能在2到10米/秒之间跳变,光照可能被一片云挡住,负荷更是随着人们的作息和工厂的订单起伏不定。用单一、固定的数据去做长期规划,无异于刻舟求剑。
所以,现代电力系统规划引入了一个非常关键的概念:场景。你可以把“场景”理解为一套完整的、可能发生的“未来天气+用电情况”剧本。我们不再只规划一种未来,而是生成成千上万个可能的未来剧本(场景),然后分析我们的电网方案在所有这些剧本下的表现。这样规划出来的系统,鲁棒性会强得多,能够应对各种可能的波动。
那么问题来了,怎么生成这些成千上万的、合理的“未来剧本”呢?总不能靠拍脑袋或者随机乱写吧。这就需要请出概率统计领域的几位“老演员”:Weibull分布、Beta分布和Normal分布。它们分别擅长刻画风速、光照和负荷的随机性。而生成的海量场景数据量太大,直接用于规划计算会“算到天荒地老”,所以还需要一位“剪辑师”——K-means聚类算法,来把几千个相似场景浓缩成几十个最具代表性的“典型场景”。
这个过程,就是风光负荷场景生成与削减。它不是什么空中楼阁的理论,而是实实在在能提升规划精度、降低投资风险、保障电网稳定运行的实用技术。接下来,我就带你一步步拆解,看看这几位“演员”和“剪辑师”是如何配合,为电力系统规划打造出一套高效工具的。
2. 三位“概率演员”:为不确定性画像
2.1 Weibull分布:捕捉“风”的脾气
风速是出了名的“善变”。为什么偏偏是Weibull分布来刻画它呢?我在处理风电场数据时深有体会。Weibull分布有两个关键参数:形状参数k和尺度参数λ。这两个参数就像调节旋钮,能让分布曲线呈现出各种形态。
- 形状参数k:它决定了风速分布的“胖瘦”和“偏态”。当k=1时,Weibull分布退化为指数分布,表示风速较小的情况居多;当k=2时,它就变成了瑞利分布,这在很多中等风况地区很常见;当k>3时,分布曲线开始越来越像我们熟悉的正态分布,意味着风速比较集中在一个范围内。在实际中,我们通过分析历史风速数据,用最大似然估计等方法就能把k和λ给“算”出来。
- 尺度参数λ:你可以把它理解为平均风速的一个“缩放器”,λ越大,整体风速水平就越高。
用Weibull分布生成风速场景,在Matlab里其实非常直观。假设我们已经从某个风场的历史数据中,拟合出k=2.1, λ=7.5。那么生成10000个可能风速场景的代码核心就是调用wblrnd函数:
% 定义Weibull分布参数
k = 2.1; % 形状参数
lambda = 7.5; % 尺度参数
num_scenarios = 10000; % 要生成的场景数
% 生成服从Weibull分布的随机风速(米/秒)
wind_speed_scenarios = wblrnd(lambda, k, [num_scenarios, 1]);
% 可视化:看看生成的风速分布长啥样
figure;
histogram(wind_speed_scenarios, 50, 'Normalization', 'pdf');
hold on;
x = linspace(0, max(wind_speed_scenarios)*1.2, 1000);
pdf_theoretical = (k/lambda) .* (x/lambda).^(k-1) .* exp(-(x/lambda).^k);
plot(x, pdf_theoretical, 'r-', 'LineWidth', 2);
xlabel('风速 (m/s)');
ylabel('概率密度');
title('基于Weibull分布的风速场景生成');
legend('生成场景的直方图', '理论Weibull分布曲线');
grid on;
运行这段代码,你会得到一张图,直方图(生成的数据)和红色的理论曲线会贴合得相当好。这证明我们生成的数据确实抓住了当地风的“脾气”。有了风速,再通过风机的功率曲线(风速与输出功率的对应关系),就能转换成风电功率场景,这才是规划中真正需要的数据。
2.2 Beta分布:描绘“光”的明暗
光伏发电看天吃饭,核心是太阳辐照度。辐照度通常被归一化到0到1之间(0代表黑夜,1代表理想的最大光照强度)。这个在[0,1]区间内波动的特性,正好撞到了Beta分布的“枪口”上。
Beta分布就像一位专门刻画比例和概率的画家。它有两个形状参数α和β。我常这么跟新手解释:
- α (alpha):可以粗略理解为“成功”的次数或积极因素。α越大,分布曲线越往1的方向挤。
- β (beta):可以粗略理解为“失败”的次数或消极因素。β越大,分布曲线越往0的方向靠。
当α和β都大于1时,分布是单峰的;当α=β=1时,它就变成了[0,1]上的均匀分布;当两者都小于1时,分布呈U型,意味着极端情况(极强光或极弱光)概率更高。通过分析历史光照数据,我们可以拟合出最适合的α和β。
在Matlab中,使用betarnd函数生成光照场景易如反掌:
% 定义Beta分布参数(示例值,需根据实际数据拟合)
alpha = 2.5;
beta = 1.8;
num_scenarios = 10000;
% 生成服从Beta分布的随机辐照度(范围0~1)
solar_irradiance_scenarios = betarnd(alpha, beta, [num_scenarios, 1]);
% 可视化
figure;
histogram(solar_irradiance_scenarios, 50, 'Normalization', 'pdf');
hold on;
x = linspace(0, 1, 1000);
pdf_theoretical = (x.^(alpha-1) .* (1-x).^(beta-1)) ./ beta(alpha, beta);
plot(x, pdf_theoretical, 'r-', 'LineWidth', 2);
xlabel('归一化辐照度');
ylabel('概率密度');
title('基于Beta分布的光伏辐照度场景生成');
legend('生成场景直方图', '理论Beta分布曲线');
grid on;
生成辐照度后,结合光伏板的面积、效率等参数,就能得到光伏出力场景。Beta分布的优势在于,它能很好地刻画阴天、多云、晴空等多种天气下光照的连续变化,比简单假设一个正态分布要准确得多。
2.3 Normal分布:把握“电”的脉搏
电负荷,也就是用户的用电需求,看起来最“杂乱无章”,但宏观上却最有“规矩”。这得益于统计学中伟大的中心极限定理。简单说,一个用户的用电行为是随机的,一个社区、一个城市、乃至一个区域,成千上万用户和设备的用电行为叠加在一起,其总和的波动就会趋向于一种稳定的、钟形的分布——这就是正态分布(Normal Distribution)。
正态分布只有两个参数:均值μ和标准差σ。μ代表了负荷的平均水平(比如一个城市的日常平均负荷),σ则代表了负荷的波动程度(σ越大,负荷起伏越剧烈)。在电力系统规划中,我们通常会对不同时段(如峰、平、谷)分别建立负荷模型,每个时段都有各自的μ和σ。
用Matlab生成负荷场景是最简单的:
% 定义负荷正态分布参数(示例:高峰时段)
mu_load = 1500; % 平均负荷,单位:MW
sigma_load = 120; % 负荷标准差,单位:MW
num_scenarios = 10000;
% 生成服从正态分布的随机负荷
load_scenarios = normrnd(mu_load, sigma_load, [num_scenarios, 1]);
% 可视化
figure;
histogram(load_scenarios, 50, 'Normalization', 'pdf');
hold on;
x = linspace(mu_load-4*sigma_load, mu_load+4*sigma_load, 1000);
pdf_theoretical = (1/(sigma_load*sqrt(2*pi))) * exp(-0.5*((x-mu_load)/sigma_load).^2);
plot(x, pdf_theoretical, 'r-', 'LineWidth', 2);
xlabel('电负荷 (MW)');
ylabel('概率密度');
title('基于正态分布的电负荷场景生成');
legend('生成场景直方图', '理论正态分布曲线');
grid on;
这里有个小坑我踩过:生成的负荷场景理论上可能出现负值(虽然概率极低),这在物理上是不可能的。在实际应用中,我们通常会对结果做一个截断处理,将负值设为0或者一个很小的正数。
3. 从“海量剧本”到“精选典型”:K-means场景削减实战
现在,我们有了分别代表风、光、负荷的成千上万个随机场景。如果把三者组合起来,一个完整的“风光负荷联合场景”就是这三个数的组合。比如[风速, 辐照度, 负荷]。生成10000个风速、10000个辐照度、10000个负荷,随机组合一下,理论上能产生海量的联合场景。但实际操作中,我们通常采用蒙特卡洛模拟,同步生成三者关联的序列(有时还需考虑它们之间的相关性),最终得到一个N行 x 3列的巨大矩阵,每一行代表一个未来可能的“状态”。
这个矩阵就是我们的“海量剧本库”。直接用它去做电力系统优化规划(比如机组组合、输电网扩展),计算量是灾难性的。想象一下,你要为十万个不同的“明天”都做一遍未来20年的电网投资决策计算,这根本不现实。
这时,就需要场景削减(Scenario Reduction)。它的目标是用少数几十个“典型场景”及其对应的发生概率,来近似代表原先成千上万个场景所蕴含的随机性信息。而K-means聚类算法,正是完成这项任务的利器。
3.1 K-means算法:如何找到“群演代表”?
你可以把K-means想象成一场“选秀”。我们有N个选手(原始场景),目标是选出K个C位出道(典型场景),并让其他选手归入最像的C位旗下。
它的工作流程非常清晰:
- 初始化:随机从N个原始场景中挑选K个,作为初始的“簇中心”(C位)。
- 分配:计算每一个原始场景到所有K个簇中心的距离(通常是欧氏距离),把它分配给距离最近的那个簇中心。这样,所有场景就被分成了K个组。
- 更新:对于每一个组,重新计算它的“簇中心”。这个新的中心就是这个组内所有场景点的平均值(质心)。原来的C位可能不够“中心”了,换一个更中心的。
- 迭代:重复第2步和第3步,直到簇中心的位置不再发生变化,或者变化非常小为止。此时,算法收敛。
最终,我们得到了K个最终的簇中心,它们就是削减后的典型场景。同时,每个簇里包含了多少原始场景,这个数量除以总场景数N,就是这个典型场景的发生概率。比如,一个典型场景代表了500个原始场景,那么它的概率就是500/10000 = 0.05。
3.2 Matlab实现:一行代码的威力与背后的陷阱
在Matlab中,实现K-means聚类简单到令人发指:
% 假设我们的联合场景数据是一个10000行,3列的矩阵scenario_data
% 列依次是:风速, 辐照度, 负荷
scenario_data = [wind_speed_scenarios, solar_irradiance_scenarios, load_scenarios];
% 设定要削减到的典型场景数量,比如K=10
K = 10;
% 使用kmeans函数进行聚类
% idx: 每个原始场景属于哪个簇的标签(1到K)
% C: K个簇中心的坐标,即我们想要的10个典型场景
% sumd: 每个簇内所有点到其中心的距离之和
% D: 每个点到所有簇中心的距离
[idx, C, sumd, D] = kmeans(scenario_data, K, 'MaxIter', 1000, 'Replicates', 10);
% 计算每个典型场景的概率
probabilities = zeros(K, 1);
for i = 1:K
probabilities(i) = sum(idx == i) / num_scenarios;
end
% 输出结果
disp('削减后的典型场景(簇中心):');
disp(C);
disp('对应的概率:');
disp(probabilities);
看起来很美,对吧?但这里有几个我踩过的“坑”,你必须注意:
- K值怎么选? 这是最核心的问题。K选大了,削减效果不好,计算量依然大;K选小了,代表性不够,会丢失关键信息。我常用的方法是画一个肘部法则(Elbow Method)图。计算不同K值下的簇内误差平方和(就是上面代码里的
sum(sumd)),这个值会随着K增大而减小。当减小趋势出现一个明显的“拐点”(像手肘一样)时,那个K值往往是一个好的选择。 - 量纲与权重:风速(m/s)、辐照度(0-1)、负荷(MW)这三个量纲和数值范围天差地别。如果不做处理直接聚类,负荷的微小波动(比如几十MW)就会完全“淹没”风速和辐照度的变化,聚类结果会严重偏向负荷。必须进行标准化(Standardization)或归一化(Normalization)。我习惯用
zscore进行标准化,让每个特征均值为0,标准差为1,站在同一起跑线上。scenario_data_normalized = zscore(scenario_data); % 标准化 [idx, C_normalized] = kmeans(scenario_data_normalized, K, 'MaxIter', 1000, 'Replicates', 10); % 注意:得到的C_normalized是标准化后的中心,如需原始量纲,需反变换 C_original = C_normalized .* std(scenario_data) + mean(scenario_data); - 初始化的随机性:K-means对初始簇中心很敏感,可能每次运行结果略有不同。Matlab的
kmeans函数提供了'Replicates'参数(如上例设为10),让它重复运行多次并选择结果最好的那次,这能有效提升稳定性。 - 结果评估:削减完了,怎么知道这K个场景好不好?除了看概率,还要看它们能否“还原”原始数据的统计特性。我会把原始数据和削减后场景(带概率)的均值、方差、相关系数矩阵拿出来对比,如果关键统计量匹配得很好,说明削减是成功的。
4. 在电力系统规划中如何应用这些“典型场景”?
生成了典型场景及其概率,我们的“弹药”就准备好了。在电力系统规划中,它们主要用在随机优化模型中。传统的确定性规划模型长这样:
最小化 总投资成本
约束:满足**某一个**特定场景下的电力平衡、线路安全等。
而引入场景后的随机规划模型则变成了:
最小化 总投资成本 + 期望运行成本
约束:满足**所有**典型场景(s=1,2,...,K)下的电力平衡、线路安全等。
其中,每个场景的约束都以其概率 weighted。
这就好比,以前你只为“晴天”这一种情况设计房子,现在你要设计一个房子,要能同时以不同概率应对“晴天”、“雨天”、“台风天”等多种情况,并且使得长期期望下的总成本(建造成本+维修成本)最低。
一个具体的应用例子是配电网中分布式光伏和储能的选址定容。规划者需要决定在哪些节点装多大容量的光伏和电池。使用我们的方法:
- 生成该地区全年的风光负荷典型场景(比如24个时段 * 10个典型日 = 240个场景)。
- 将这些场景及其概率输入到随机规划模型中。
- 模型会求解出最优的安装方案。这个方案不是在某个“平均日”最优,而是在所有可能出现的波动情况下,长期期望成本最低、可靠性最高的方案。
实测下来,这种方法比用单一“典型日”做规划,结果要“稳”得多。它能有效避免因低估可再生能源波动性而导致的投资不足,或因高估而导致的投资浪费,真正实现了在不确定性中寻找最优决策。
5. 进阶思考与避坑指南
走通了基本流程,我们还可以思考一些更深入的问题,这也是项目能否从“能用”到“好用”的关键。
如何考虑风、光、负荷之间的相关性? 现实中,大风天可能光照也强(晴天刮风),负荷也可能有日变化和季节变化规律。我们之前是独立生成三列数据,这忽略了它们之间的时空关联。更高级的做法是使用Copula函数或自回归移动平均(ARMA)模型等来生成具有相关性的时间序列场景。在Matlab中,可以先用历史数据拟合出它们的联合分布或相关系数矩阵,再进行抽样。
除了K-means,还有别的削减方法吗? 当然有。K-means属于“聚类类”方法,它追求整体代表性。还有一类“概率距离类”方法,如快速前代消除法(Fast Forward Selection) 和同步回代消除法(Backward Reduction)。它们的思路是直接衡量场景之间的“概率距离”,迭代地合并或删除那些“相似”的场景,直到剩下指定数量的场景。这类方法有时在保留概率分布特性上更有优势。在实际项目中,我通常会两种方法都试试,对比一下削减后场景的统计保真度。
计算效率的权衡。场景生成和削减本身也需要计算时间。对于超大规模系统,可能需要采用并行计算(Matlab的parfor)来加速蒙特卡洛模拟。在K-means聚类时,对于海量数据(比如百万级场景),可以考虑先用小样本跑一遍肘部法则确定K值,或者使用Mini-Batch K-means等更快的变种算法。
最后,分享一个我的个人经验:永远不要迷信模型输出,要回头做验证。生成削减后的典型场景,一定要把它们放回到一个简化版的规划或运行模型里跑一遍,看看关键指标(如失负荷概率、线路阻塞小时数、总成本)和用大量原始场景跑出来的结果是否接近。如果偏差较大,就要回头检查分布参数拟合是否准确、K值选择是否合理、标准化处理是否得当。数据和模型是工具,工程师的判断和验证才是灵魂。这个过程虽然繁琐,但能帮你避开很多潜在的坑,确保你的规划方案既先进又可靠。
更多推荐
所有评论(0)