简介:面向光伏发电功率预测与电力系统调度研究需求,该资源提供一套完整的分布式光伏发电计及气象因子与出力预测方法的研究包。重点给出基于经验模态分解(EMD)、主成分分析(PCA)与长短期记忆神经网络(LSTM)组合的光伏功率预测模型,可帮助研究人员复现并改进多气象因子影响下的功率预测实验。包体共8个文件,包含4个MATLAB脚本(负责分解、特征提取、训练与预测等核心流程)、3个.mat数据文件(提供风速、温度、风向及发电功率等实测样本),另有1个内嵌子压缩包,整体仅116KB,小巧便携。目前已有208人学习下载,适合电力系统、新能源方向的高年级本科生与研究生用于论文复现、算法对比或课程设计。通过该包可快速掌握EMD降噪、PCA降维与LSTM时序建模在光伏出力预测中的完整代码实现,并结合实测数据验证模型精度。
1. 分布式光伏发电计及气象因子及出力预测:这份 zip 里到底装了什么
做分布式光伏发电计及气象因子及出力预测,最磨人的往往不是选哪个网络,而是数据进模型之前那些看不见的坑。这份资源是一套完整可跑的 MATLAB 实现:用经验模态分解(EMD)把风速、温度这类非平稳环境序列拆成多尺度分量,接着用 PCA 去冗余,再用 LSTM 做动态时间建模,数据来自山西某电站 8 个月的 5 分钟级实采。包里直接给出风速、温度、功率三份序列、三个输入组合不同的训练脚本和一个指标评估脚本。适合做电力预测毕设的学生、想快速搭功率预测 baseline 的算法工程师,以及要在调度侧评估误差的从业者。它直接解决的问题是:气象因子以什么顺序、什么形式进模型,以及评估结果怎么算才不翻车。
2. 数据与脚本结构:五个 .mat 加四个 .m,先对清单再动手
2.1 文件清单与变量约定:跑之前先 whos 一遍
| 文件 | 内容 | 关键变量/单位 | 用途 |
|---|---|---|---|
| gonglv5min.mat | 5 分钟功率序列 | P 或 gonglv5min,kW | 预测目标 |
| fengsu5min.mat | 5 分钟风速 | V 或 fengsu5min,m/s | 环境特征 |
| wendu5min.mat | 5 分钟温度 | T 或 wendu5min,℃ | 环境特征 |
| yucemin5.m | 纯功率滞后特征训练脚本 | — | 基线模型 |
| yucemin5_fengxiang.m | 加入风向的训练脚本 | — | 单因子对比 |
| yucemin5fengsuwendufengxiang.m | 风速+温度+风向全特征脚本 | — | 完整模型 |
| zhibiao.m | 性能指标计算脚本 | MAE/RMSE/MAPE/R² | 评估 |
不同版本的包里变量名可能不一样,第一次跑别急着改代码,先load之后用whos看变量名、类型和 size,再决定要不要统一。另外清单里没有独立的 fengxiang5min.mat,但两个脚本名都带_fengxiang,第一次跑大概率会卡在「风向数据在哪」这个问题上。打开脚本看前几行的load和赋值语句就能确认来源;如果包里的 mat 确实没带风向变量,常见做法是把风向编码成 sin/cos 两个分量补进特征,或者用同一时间轴的辐照度替代,别直接删掉这路特征。风向对上午、下午不对称的出力曲线是有解释力的,只是权重需要让模型自己去学。
2.2 读数与时间轴对齐:七万行数据先排好队
% 先确认变量名,再统一成列向量 load('gonglv5min.mat'); load('fengsu5min.mat'); load('wendu5min.mat'); % 常见变量名:P / gonglv5min, V / fengsu5min, T / wendu5min P = gonglv5min(:); V = fengsu5min(:); T = wendu5min(:); % 以最短序列为准截断,避免维度不匹配 n = min([numel(P), numel(V), numel(T)]); P = P(1:n); V = V(1:n); T = T(1:n); % 检查缺失值和异常值 fprintf('样本数 %d,NaN 行数 %d\n', n, sum(isnan(P)|isnan(V)|isnan(T))); % 5 分钟采样,8 个月约 288*244 ≈ 7 万个点逻辑说明:(:)把行向量或矩阵强制转成列向量,防止后面横向拼接时报维度错;min截断是最省事的对齐方式,代价是丢掉长序列尾部几十个点,对七万样本量来说无影响。参数上,5 分钟粒度意味着一天 288 个点,8 个月约七万点,这个体量喂给 LSTM 训练时间完全可接受。isnan检查是必做项,采集端掉点通常表现为 NaN 或 0,先查清楚再填。
注意:如果发现 NaN 超过总样本的 0.1%,不要用 fillmissing 直接填,先核对是不是时间戳错位导致整段值偏移,这种情况填了等于造假。
2.3 三个训练脚本怎么分工:消融实验已经帮你排好
三个脚本的输入端不同:yucemin5.m 只用功率历史值,不含任何气象因子;yucemin5_fengxiang.m 在功率基础上加风向;yucemin5fengsuwendufengxiang.m 加全量气象特征。这就是一套现成的消融实验,最终评估时把三者都跑完,对比 zhibiao.m 的输出,就能量化每个气象因子的边际贡献。
% 构造监督学习样本:过去 lookback 个时刻预测未来 horizon 个时刻 lookback = 12; % 12 个 5 分钟点 = 1 小时 horizon = 1; % 预测未来 5 分钟 seqs = {}; y = []; for k = lookback+1 : n-horizon+1 feat = [P(k-lookback:k-1)'; V(k-lookback:k-1)'; T(k-lookback:k-1)']; seqs{end+1} = feat; % 3×lookback 的特征矩阵 y(end+1) = P(k+horizon-1); end % LSTM 输入格式:每个样本是 numFeatures×numTimeSteps 的矩阵 % trainNetwork 接收 cell 数组,每个 cell 一个样本参数说明:lookback是记忆窗口,取 12 对应 1 小时,太短学不到日周期,太长样本数变少且训练变慢,常见取 6/12/24 三档对比;horizon=1是单步预测,改成 12 就是直接预测 1 小时后,误差会明显放大,一般先用单步验证模型结构对不对。feat的行是特征(功率、风速、温度),列是时间步,这个维度顺序不能反,sequenceInputLayer默认要求「特征 × 时间步」,拼反了训出来的模型完全不可用。
3. EMD 分解与 PCA 降维:把非平稳序列拆成 LSTM 吃得下的形状
3.1 EMD 解决什么问题:非平稳序列为什么会让 LSTM 白学
5 分钟功率序列里,云层遮挡造成分钟级高频波动,天气过程带来小时级中频成分,日升日落是 24 小时周期,这些叠加在一起就是典型非平稳信号。LSTM 的遗忘门擅长记规律,但面对均值、方差随时间漂移的序列,容易把短期波动当成规律硬拟合,训练集指标不错,换个天气状况立刻失灵。EMD 的价值在于它自适应地把序列拆成若干个本征模态函数(IMF)加一个残差,IMF 按频率从高到低排列:高频 IMF 对应云层快速变化,低频 IMF 加残差对应日周期和季节趋势。每个分量都平稳一些之后再去组建模,LSTM 学到的才是相对稳定的映射关系。
提示:EMD 不需要预设基函数,不像小波分解要纠结小波基和分解层数,这是它在这类气象序列上比小波更省心的原因。
3.2 EMD 在 MATLAB 里的调用方式与参数
% MATLAB R2018a 之后自带 emd,更老的版本需要第三方工具包 [imf_V, resid_V] = emd(V, 'MaxNumIMF', 8); % imf_V 是矩阵,每一列一个 IMF,列数由数据自适应决定 size(imf_V) % 看一眼拆出来几列 % 逐列 plot 观察分量尺度:前几列高频,后几列加残差是低频趋势逻辑说明:emd内部通过三次样条包络迭代筛分,返回的imf_V每列对应一个分量,resid_V是最后的单调残差。MaxNumIMF=8限制最多拆 8 个分量,防止把纯噪声也拆成独立 IMF;默认拆出数量取决于序列复杂度,8 个月的数据一般落在 5 到 8 个。另一个常用参数'SiftRelativeTolerance', 0.01控制筛分停止阈值,默认值多数场景够用,不用迷信论文里写的 0.05 或 0.001。分解前对序列两端做镜像延拓能有效抑制端点发散,这个坑单独放在避坑章节展开。
3.3 PCA 降维:特征从二十几维回到个位数
摘要里说的 5 种环境因素,每个序列经 EMD 拆出 5 到 8 个 IMF,拼在一起特征总数直接到 20 以上。但相邻 IMF 之间存在相关性,比如风速的高频分量和功率的高频分量在云层场景下是同步波动的,直接喂给 LSTM 既冗余又容易过拟合,这时候 PCA 的价值就出来了。
% 假设三个环境序列都已 EMD 分解,拼成特征矩阵 F = [imf_V, imf_T, imf_dir]; % imf_dir 来自风向序列分解 % 标准化:PCA 对量纲敏感,风速和温度单位不同不能直接混算 F = (F - mean(F)) ./ std(F); [coeff, score, ~, ~, explained] = pca(F); cumvar = cumsum(explained); k = find(cumvar >= 95, 1); % 累计方差贡献率到 95% F_pca = score(:, 1:k); % 降维后的特征矩阵 fprintf('主成分数量: %d, 累计贡献率: %.2f%%\n', k, cumvar(k));参数说明:explained是每个主成分解释的方差百分比,cumsum累加后取第一个超过 95% 的位置k。95% 是功率预测场景里的常见阈值,想严格一些取 98% 会保留更多原始信息但对抑制过拟合帮助不大;数据噪声大时 90% 也能用。score是投影后的主成分得分,后续 LSTM 输入用的是score(:,1:k)而不是coeff,这两个变量搞反是新手常犯的错。PCA 只对特征矩阵做,功率序列单独标准化,否则会泄漏预测目标信息,具体后果在避坑章节第四条细说。
3.4 LSTM 结构与超参:复现时按这个起点调
numFeatures = size(F_pca, 1); % 降维后的特征维度 numHidden = 64; layers = [ sequenceInputLayer(numFeatures) lstmLayer(numHidden, 'OutputMode', 'last') fullyConnectedLayer(1) regressionLayer]; options = trainingOptions('adam', ... 'MaxEpochs', 80, ... 'MiniBatchSize', 64, ... 'InitialLearnRate', 0.001, ... 'LearnRateSchedule', 'piecewise', ... 'LearnRateDropFactor', 0.5, ... 'LearnRateDropPeriod', 20, ... 'Plots', 'training-progress', ... 'Verbose', 0); net = trainNetwork(seqs, y, layers, options);逻辑说明:seqs是第 2.3 节组好的 cell 数组,y是对应的功率目标列。'OutputMode','last'表示只输出序列最后一个时刻的结果,正好匹配单步预测;如果改成预测未来多步,要把输出模式换成'sequence'并调整输出层结构。numHidden从 64 起步,数据量大可以试 128,但要配合lstmLayer里的'Dropout',0.2防止过拟合,hidden units 往上加不一定更好,这个参数很多时候是玄学。InitialLearnRate=0.001是 Adam 的标准起步值,loss 震荡就降到 3e-4;LearnRateDropPeriod=20表示每 20 个 epoch 学习率减半,配合MaxEpochs=80正好在训练后期精细收敛。训练时把'ValidationData'指到时间上靠后的验证集,盯着验证 loss 判断过拟合比只看训练曲线可靠得多。
3.5 三种特征输入的预期差异
这个包自带的三个脚本已经把对比实验排好了。按常见经验,纯功率基线在晴天表现尚可,阴雨天因为缺少外部信息误差明显放大;加风向的版本在 5 分钟级预测里贡献通常弱于风速和温度,风向对出力的影响更多体现在小时级以上尺度;加风速和温度后,RMSE 一般能比基线降 8% 到 15%。但这个数字依赖电站的地理位置和季节,摘要只给了「更高的精确度」这个定性结论,具体收益在自己数据上跑完 zhibiao.m 才能确认,别拿论文里的数字当自己的验收标准。
4. 避坑与排查:五条实测记录,从时间对齐到误差计算
4.1 时间轴与数据质量的两个坑
坑 1:horzcat 报维度不匹配,或者训练到一半 loss 变 NaN。
现象:把风速、温度横向拼进特征矩阵时直接报错;或者训练前几个 epoch 正常,某次迭代后 loss 变成 NaN 且不再恢复。
原因:5 分钟级数据在采集端掉点,三个 .mat 的样本数差几十到几百行;另一个常见原因是某列变量从 mat 里读出来是行向量(1×n),横向拼接时形状对不上。
解决:先whos确认每个变量的 size,统一用(:)转列向量;以最短序列截断,或者用interp1把差值的序列重采样到统一时间轴;对 NaN 用fillmissing(P,'previous')前向填充。千万别对功率序列做平滑滤波,云层遮挡的陡降是模型要学的有效信息,平滑掉等于给模型作弊。
坑 2:shuffle 时间序列,验证集指标漂亮得不像话。
现象:训练时随机打乱样本,验证集 R² 能到 0.98,模型部署到下一周数据上 R² 掉到 0.8 以下。
原因:相邻 5 分钟样本之间高度自相关,shuffle 之后训练集和验证集里混着彼此的近邻样本,模型在验证集上相当于做插值而不是预测,这是典型的时序泄漏。
解决:严格按时间顺序切分,前 6.5 个月训练、后 1.5 个月验证;trainingOptions里设置'Shuffle','never'。LSTM 的输入是 cell 数组,打乱 cell 之间的顺序影响不大,但打乱 cell 内部的时间步顺序等于破坏序列结构,数据构造那一步就要保证时间有序。
4.2 EMD 与 PCA 的两个坑
坑 3:EMD 端点飞翼导致首尾误差爆炸。
现象:分解出的第一个 IMF 在序列两端出现大幅摆动,幅值比中间高一个量级;预测结果在测试集开头和结尾段误差明显大于中间段。
原因:EMD 的包络估计用三次样条插值,端点处没有数据约束,样条包络在边界发散,端点效应会沿迭代过程向内传播。
解决:分解前做镜像延拓,把序列两端各翻转 200 个点左右接到头尾,分解完丢掉延拓段;或者训练时只取中间 90% 的数据,预测时对输出段做过渡加权。另一个思路是控制MaxNumIMF,分量少时端点效应传播范围相对小,多试几个取值对比首尾段的误差。
坑 4:把功率序列混进 PCA,预测峰值被削平。
现象:预测曲线整体滞后于真实值,峰值明显被削平,RMSE 比不做 PCA 还高。
原因:PCA 对特征做线性组合时,功率序列里日周期主导的方差会吃掉主成分中环境因子的分量,气象信息被当成冗余丢掉;同时降维过程隐式用到了功率信息,相当于特征构造阶段的标签泄漏。
解决:PCA 只作用于环境因子特征矩阵,功率序列单独做标准化;主成分数量用累计方差贡献率动态选择,不拍脑袋定成 2 或 3。检查方法很简单,投影后看前几个主成分的载荷系数,如果第一个主成分和功率序列的相关性异常高,说明构造阶段混入了目标信息。
4.3 评估口径的一个坑
坑 5:MAPE 在夜间功率接近零时爆炸。
现象:整体 MAPE 报出来 20% 出头,细看夜间段贡献了其中 90% 的误差;白天晴天段 MAPE 其实只有 6% 左右。
原因:MAPE 的分母是真实功率,夜间功率趋近 0,几 kW 的绝对误差除以接近 0 的功率,得到几百个百分点的相对误差,直接把整体指标带崩。
解决:评估时分段统计,只对P > 0.1 * max(P)的样本算 MAPE;主指标换成 MAE 和 R²,MAPE 作为辅助参考。zhibiao.m 里如果直接算 MAPE,建议加 epsilon 保护:mape = mean(abs((y_pred-y_true)./(y_true+eps))),eps 取 1 或 0.1 倍最大功率都行,量纲不同选法不同,自己心里有数即可。
5. 验证与落地技巧:用 zhibiao.m 评估,再改成滚动多步预测
5.1 zhibiao.m 怎么用:四个指标一起看
% 预测完成后,把反归一化后的 y_pred 和 y_true 传入评估 % 如果 zhibiao.m 是脚本,先看内部约定的变量名,对齐再运行 [mae, rmse, mape, r2] = zhibiao(y_true, y_pred); fprintf('MAE=%.2f kW | RMSE=%.2f kW | MAPE=%.2f%% | R2=%.4f\n', ... mae, rmse, mape*100, r2);逻辑说明:误差计算必须在物理量纲下做。如果网络输出是 [0,1] 归一化值,先反归一化回 kW 再调 zhibiao.m。四个指标各有侧重:MAE 反映平均偏差水平,RMSE 放大峰值误差,MAPE 看相对百分比,R² 看整体拟合度,单独看任何一个都可能误判。比如 RMSE 高但 MAE 低,说明误差集中在少数尖峰时刻,这时候要查是不是云层遮挡样本。
5.2 滚动多步预测:把单步模型变成小时级预测
steps = 12; % 预测未来 12 个 5 分钟点,即 1 小时 window = seqs{end}; % 最后一段历史特征,尺寸为 特征×lookback preds = zeros(steps, 1); for s = 1:steps preds(s) = predict(net, {window}); % 单步预测 window = [window(:, 2:end), preds(s)*ones(size(window,1),1)]; % 滚动窗口:丢掉最旧时刻,拼入新预测值 end参数说明:滚动窗口保持lookback长度不变,每预测一步就把最旧时刻丢出去,换成模型自身的预测值。这里有个明显的累积误差效应:第 1 步 RMSE 最小,第 12 步通常放大 2 到 3 倍,这是闭环预测的正常现象。代码里直接拿预测值拼窗口是简化写法,严格做法是把新预测值放回原始特征空间,重新走一遍标准化和 PCA 投影再拼回窗口,这样特征分布才一致。想改善多步精度,常见做法是训练时用 teacher forcing 或者在损失函数里对远期步长加权。
从那以后我每次拿到这类功率预测数据,都强制走一遍「时间对齐 → 时序切分 → EMD 端点检查 → 误差反归一化」四步,再谈模型选型;这套流程救过我好几次,希望帮到你。
本文还有配套的精品资源,点击获取