光伏电站短期发电功率预测:从数据准备到LSTM模型部署全指南
发布时间:2026/9/25 2:13:31来源:尧图网络
简介光伏电站短期发电功率预测是电力调度与稳定运行的关键环节。这份压缩包基于长短期记忆网络与支持向量机结合构建预测模型覆盖数据收集、预处理、模型训练与多步预测完整流程适合新能源发电、电力系统方向的研究者及工程师参考。资源共78个文件体积1.97MB包含C、Java、Python、MATLAB等语言源码以及可执行程序、数据文件mat、xls、文档和配套工具种类多样方便按需选用。压缩包内提供吉林通化柳河光伏电站实测数据、长短期记忆网络与支持向量机组合模型的MATLAB脚本、libsvm工具包、模型说明书及运行说明可直接复现基于序列学习与非线性回归的功率预测实验。已有1662人学习该资源同样适合作为教学与科研中理解光伏功率预测建模、调参与评估的实践案例。1. 光伏电站短期发电功率预测为什么“看天吃饭”是个算法题光伏电站短期发电功率预测本质上是在回答一个问题未来24小时到72小时我这个站到底能发多少电。做过电站运维的人都有这种体验——中午一朵云压过来功率十几分钟内从满发掉到两成更头疼的是日前上报的发电计划被电网考核偏差大了要扣钱比停机损失还疼。短期预测就是把这个“看天吃饭”的过程变成可量化的数字用来申报计划、安排储能和检修。下面按一条可复现的路线讲先界定“短期”到底指哪个窗口再理数据、选模型用LSTM跑通最小链路最后讲部署后的避坑。2. 定义短期与数据准备先搞清楚预测到底要解决哪一段2.1 短期的定义超短期、短期、中长期的时间窗口与用途在光伏功率预测领域时间尺度不是拍脑袋定的而是跟着调度业务走。业内一般把预测分成三档超短期指未来0到4小时分辨率做到15分钟甚至5分钟主要用于储能充放电策略、AGC指令跟踪和实时功率平滑短期指未来1到3天分辨率通常是1小时部分省份要求15分钟上报用于日前发电计划申报、电力交易和检修窗口安排中长期指未来一周到一个月只关心电量总量用于融资评估和年度发电量测算。这个标题里的短期发电功率预测指的就是中间这一档。它跟超短期最大的不同在于超短期可以用当前功率和最近一小时趋势外推夜里也能做短期要跨过夜晚、跨过第二天的未知天气光靠历史功率外推完全不行必须有数值天气预报NWP的辐照度和云量输入。这也是很多团队第一次做短期预测时翻车的地方——拿超短期的思路套短期数据里没有NWP模型在下午到次日上午这段窗口基本是瞎猜。预测类别时间窗口分辨率主要用途关键输入超短期0~4小时5~15分钟储能调度、AGC跟踪实测功率、地基辐照仪短期1~3天1小时或15分钟日前计划申报、电力交易NWP、历史功率、实测气象中长期周~月日或月发电量测算、检修规划气候统计、历史发电量这里有个容易被忽略的点短期预测的考核口径通常是“针对一个固定预测时刻的误差”比如早上8点上报当天剩余时段的功率曲线。这意味着模型在一天里只需要运行一次或两次不需要像超短期那样高频滚动。工程实现上短期模型往往做成“收到NWP后启动预测、输出未来24到72小时曲线”的批处理任务。2.2 数据源与采集频率SCADA、气象站、NWP各管哪一段先把数据家底盘清楚。光伏电站短期功率预测需要三类数据源SCADA系统里的实际发电功率、站内气象站实测、外部NWP预报。三者各自管一段缺一个都会让模型变成“半瞎”。SCADA功率数据是训练标签也承担历史功率特征。电站常见的采集频率是1分钟、5分钟或15分钟一条。要注意的是功率数据里混着停机、限电、逆变器故障这些非自然因素建模前必须打标记或剔除。站内气象站提供辐照度、温度、湿度、风速采集频率通常1到5分钟。辐照度计分总辐射表和直接辐射表工程上多数电站装的是总辐射表测量的是水平面总辐照度这个量正好和光伏组件接收的能量最相关。NWP是短期预测的“眼睛”提供未来几天的辐照度、云量、温度、风速等格点预报。国内商业NWP产品的网格分辨率常见3公里、9公里时间分辨率1小时或3小时每天更新0时、6时、12时等多个时次。数据源关键字段典型频率在模型里的角色SCADA实际功率、逆变器状态1~15分钟训练标签、历史功率特征气象站辐照度、温度、湿度、风速1~5分钟实测气象特征NWP辐照度、云量、温度、风速1~3小时每日多时次未来时段的必要输入卫星/地基云图云团位置与运动分钟级超短期可选增强数据接入时最常踩的坑不是字段缺失而是时间对齐。SCADA时间戳是采集时刻气象站是整点平均NWP是模式起报时刻加预报时效三个时间对齐必须统一到一个时间网格上。我一般统一用UTC存储展示层再转本地时间避免夏令时和跨时区把光照时段整个错位。2.3 建数据集的细节单位、时区、晴天/阴天样本怎么标数据集的建设顺序比模型重要得多。第一件事是统一单位功率一律用MW或kW辐照度用W/m²温度用℃风速用m/s。为了模型跨电站复用功率最好除以装机容量得到0到1之间的标幺值预测结果再乘回去。第二件事是定时间网格把三路数据都重采样到同一个整点比如15分钟一个点。重采样时用前向填充不要用线性插值把NWP的3小时值硬插成15分钟那会造出不可能出现的渐变云况。第三件事是处理夜间样本。夜间功率接近零辐照度为零如果训练数据里夜间样本占一半模型会把注意力全放在“输出零”白天峰值的误差反而被掩盖。常见做法是加一个光照时段掩码或者用辐照度阈值把训练样本限定在白天。但注意验证时要用全时段数据因为你真正上线时不可能只在白天预测。还有一个技巧给样本加天气类型标签时不要用“晴/多云/阴/雨”这种一轮定生死的硬标签NWP回顾资料的天气类型在电站尺度上经常不准几公里外的云团就能让标签从“晴”变成“多云”。我会保留逐小时云量、辐照度变异系数作为连续特征天气类型只在分析误差时用来分组。数据集里还要预留相似日检索的索引字段。按年积日、天气类型、日最高温度、日累计辐照度建一个简单的检索表后续做相似日融合时直接用。这个索引不参与模型训练但能省不少重复造轮子的功夫。提示建模前先跑一份数据质量报告统计每个字段的缺失率、重复时间戳、夜间非零功率占比、辐照度超过物理上限的异常点。这些指标比模型选型更能决定预测精度也方便后续定位问题在数据还是模型。3. 选模型前先看边界物理模型、统计模型与机器学习该怎么分工3.1 物理模型和统计模型的边界不适合做“短期”的地方很多人一开始会问为什么不用物理模型物理模型确实存在而且工程上有它的位置。它根据太阳天文辐射、组件倾角、组件I-V特性和温度系数算出“理想晴空功率”。问题是实际功率受云遮挡、灰尘、组件老化、逆变器限功率影响物理模型算出来的是一条漂亮的光滑曲线跟实际运行数据差得远。物理模型更适合做两件事一是作为机器学习的基线或特征二是判断数据异常——当实际功率明显低于晴空功率很多、又没有对应的云况记录数据十有八九有问题。统计模型里最常被提起的是持续法也叫persistence。它的预测值就是当前功率或上一时刻功率在超短期预测里是极难打败的对手因为光伏功率在5到15分钟尺度上惯性很强。但放到短期预测持续法毫无办法傍晚时刻它预测今天晚上的功率等于现在第二天上午它预测的还是现在完全跨不过去。ARIMA、卡尔曼滤波这类时间序列方法也一样对辐照度的非平稳突变基本无能为力。所以短期预测现在的主流是机器学习或混合模型把NWP、实测气象、历史功率都作为特征让模型自己去学非线性关系。这里有一个选型原则先看预测窗口再选模型。预测窗口在4小时以内优先试持续法和轻量回归预测窗口超过24小时必须把NWP放进来机器学习几乎是唯一现实选择。3.2 机器学习建模路线特征、模型、训练/验证划分机器学习做短期预测路线可以分成四步特征工程、模型选择、训练验证划分、评估。特征工程是第一位的。按重要性排NWP辐照度通常是最重要的单特征其次是历史同时刻功率然后是站内实测辐照度、温度、湿度、风速最后是时间编码。时间特征不要用整数小时1到24直接喂进去模型学不出“23点和0点相邻”这种周期性要转成sin/cos编码def cyclical_encoding(hour, doy): hour_rad 2 * np.pi * hour / 24 doy_rad 2 * np.pi * doy / 365 return (np.sin(hour_rad), np.cos(hour_rad), np.sin(doy_rad), np.cos(doy_rad))这样24小时和0点之间的距离是连续的模型不会把周期割裂。太阳高度角也可以直接由经纬度和时间算出来很多工程上直接把它当特征效果比单纯时间编码更稳定。模型选择上第一版建议先用LightGBM或XGBoost训练快、好调参、能处理特征缺失。如果追求序列依赖再换成LSTM或CNN-LSTM。LSTM适合捕捉“过去1小时功率的上升趋势”CNN适合提取局部窗口的模式两者组合在云量突变场景会好一些但代价是训练时间和调参复杂度上升。训练/验证划分是这条路线里最容易被做错的一步。绝对不能随机打乱数据做KFold那等于把未来信息泄漏进训练集。要用时间顺序划分先用前70%做训练中间15%做验证最后15%做测试测试集必须是模型从未见过的连续时间段。超参数调优要在验证集上做测试集只允许最后用一次。还有人会问为什么不用滚动验证因为第一版更重要的是快速看可行性固定划分足够等模型要上线前再用滚动回测补一轮。3.3 混合模型的具体组合方式NWP修正、相似日、误差序列工程上真正能用起来的往往是混合模型核心思路不是搞玄学而是把不同信息源的优点拼起来。我常用的组合有三种。第一种是残差学习。先跑一个晴空物理模型得到晴空功率再让机器学习模型去预测“实际功率减晴空功率”的残差最后把晴空功率加回去。这么做把模型从复杂的绝对功率预测问题里解放出来只需要拟合云和温度造成的偏差学习难度大幅降低。第二种是相似日加权。针对预测日的天气类型、季节、温度和辐照度特征从历史库里挑出最相似的几天用它们的功率曲线做加权平均再与主模型输出融合。相似日的选择要算欧氏距离K一般取3到10。这个方法的本质是给模型提供“同类天气下实际长什么样”的样本对NWP云量不准的场景特别有帮助。第三种是多模型堆叠。把LightGBM、LSTM、持续法各自输出作为特征再训练一个简单的岭回归或线性回归来融合。这招是我的后悔药单模型效果不够时不换框架先叠加一层融合往往能把整体MAE再压掉5%到10%。最后还可以对残差序列做一次指数平滑或简单移动平均专门修正模型系统性偏差。注意堆叠时基学习器要在同一时间网格上否则特征时间戳对不齐融合层学到的是错位关系。4. 用LSTM跑通一条最小可运行链路特征、滑窗、训练与评估4.1 数据预处理与滑窗样本构建到了动手环节。我用一个最小可运行的LSTM方案把从CSV到评估指标的链路串起来。假设电站数据已经重采样成15分钟一条字段包括time、power、irradiance、temperature、humidity。先读进来做基础清洗并构造时间特征import pandas as pd import numpy as np df pd.read_csv(pv_station.csv, parse_dates[time]) df df.sort_values(time).drop_duplicates(subsettime, keeplast) # 辐照度物理下限修正功率负值归零 df[irradiance] df[irradiance].clip(lower0) df[power] df[power].clip(lower0) hour df[time].dt.hour df[time].dt.minute / 60 doy df[time].dt.dayofyear df[sin_hour] np.sin(2 * np.pi * hour / 24) df[cos_hour] np.cos(2 * np.pi * hour / 24) df[sin_doy] np.sin(2 * np.pi * doy / 365) df[cos_doy] np.cos(2 * np.pi * doy / 365) # 滞后特征15分钟前和1小时前 df[power_lag15] df[power].shift(1) df[power_lag60] df[power].shift(4) feature_cols [sin_hour, cos_hour, sin_doy, cos_doy, irradiance, temperature, humidity, power_lag15, power_lag60] df df.dropna(subsetfeature_cols [power])这段代码做了四件事排序去重、物理约束修复、周期时间编码、构造滞后特征。辐照度用0作为下界功率负值归零是电站数据的常规清洗。滞后特征是当前功率预测未来功率的关键窗口shift(1)表示上一时间步如果重采样频率不是15分钟shift(4)对应的实际时间间隔要重新算。注意清晨时段的power_lag60会取到前一夜的数据所以时间特征很重要它告诉模型当前是几点。按时间顺序划分训练集、验证集、测试集并做滑窗。这里训练集只保留白天样本验证和测试保留全时段from tensorflow.keras.preprocessing.sequence import TimeseriesGenerator train_end int(len(df) * 0.7) val_end int(len(df) * 0.85) train_df df.iloc[:train_end] train_df train_df[train_df[irradiance] 5] # 仅训练白天样本 val_df df.iloc[train_end:val_end] test_df df.iloc[val_end:] seq_len 6 # 6个时间步15分钟一条即用过去1.5小时预测下一时刻 batch_size 64 def make_gen(data): return TimeseriesGenerator( data[feature_cols].values, data[power].values, lengthseq_len, batch_sizebatch_size, shuffleFalse ) train_gen make_gen(train_df) val_gen make_gen(val_df) test_gen make_gen(test_df)TimeseriesGenerator会按顺序取history序列和目标值shuffle必须设False否则时间顺序被打乱等于人为制造数据泄漏。因为训练集只保留白天train_gen内部的时间是不连续的但每个滑窗内的序列本身是连续采样的LSTM靠时间特征能感知时段。seq_len6表示输入过去1.5小时想覆盖更长的历史可以加大到12或24但序列太长训练会变慢而且光伏功率在15分钟粒度下太久远的趋势对下一时刻帮助有限我一般用6到12之间。4.2 LSTM模型结构与训练参数模型用两层LSTM加Dropoutfrom tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense, Dropout from tensorflow.keras.callbacks import EarlyStopping model Sequential([ LSTM(64, return_sequencesTrue, input_shape(seq_len, len(feature_cols))), Dropout(0.2), LSTM(32, return_sequencesFalse), Dropout(0.2), Dense(16, activationrelu), Dense(1) ]) model.compile(optimizeradam, lossmse, metrics[mae]) early_stop EarlyStopping(monitorval_loss, patience5, restore_best_weightsTrue) history model.fit(train_gen, validation_dataval_gen, epochs30, callbacks[early_stop], verbose1)第一层LSTM加了return_sequencesTrue因为要输出完整序列给第二层第二层只输出最后一个时间步再接全连接层。Dropout放在LSTM输出之后防止模型死记训练集里的云况突变。loss用mse会让模型更照顾大误差样本适合爬坡场景如果数据异常值多可以用mae模型会更稳健。EarlyStopping盯val_losspatience设为5意思是验证误差连续5个epoch不下降就停restore_best_weights保证拿回最优权重。这个网络规模对几十到上百MW的电站够用如果数据量很大、特征又多可以把第一层单元数加到128。4.3 模型评估MAE、RMSE、MAPE 到底该看哪个训练完成后预测并评估注意目标值对齐pred model.predict(test_gen) y_true test_df[power].values[seq_len:] # 对齐预测目标起始位置 mae np.mean(np.abs(y_true - pred.flatten())) rmse np.sqrt(np.mean((y_true - pred.flatten()) ** 2)) nmae mae / installed_capacity * 100 # 装机容量MW print(fMAE{mae:.2f} MW, RMSE{rmse:.2f} MW, nMAE{nmae:.1f}%)y_true的取法是初学容易错的地方TimeseriesGenerator生成的预测序列比原序列短seq_len因为开头几个样本缺少完整历史所以对齐要从seq_len开始切。评估指标不是选一个就完事。MAE最直观向电站汇报“平均偏差多少MW”用它RMSE会放大高峰时段和爬坡时刻的大误差适合在模型对比时拉开差距MAPE在功率接近零时分子分母都小会给出可怕的大数不要对光伏功率直接用MAPE。工程上更推荐归一化MAE也就是把MAE除以装机容量或当日峰值功率得到可以跨电站比较的百分数。指标计算方式适合场景注意MAE平均绝对值误差向业务汇报最直观RMSE均方根误差模型选型对比对大误差敏感nMAEMAE / 装机容量跨电站比较推荐用MAPEMAE / 真实值几乎不适合光伏零功率附近会爆炸还要分天气类型和分时段看误差。把测试集按小时分组画一条“时刻-平均绝对误差”曲线通常中午误差最大因为辐照度峰值附近功率绝对值大绝对误差自然大。按天气类型分组更关键晴天误差小、多云天误差大如果多云天的nMAE是晴天的三倍说明模型还没学会云量突变下一步要加大NWP云量特征权重而不是简单堆模型。5. 短期功率预测的避坑清单时间对齐、天气标签与归一化泄漏5.1 历史功率与气象特征时间不对齐现象模型训练loss收敛得很好测试时误差很大尤其是中午时段画散点图发现辐照度和功率峰值错开了半小时到一个小时。原因SCADA功率是采集瞬间值气象站是分钟平均NWP是预报时效三者的时间戳语义本来就不一致。有人直接把三个表按时间索引join结果数据量大的表把另一个表的未来值拉到当前行。解决所有数据先重采样到统一时间网格15分钟整点或1小时整点前向填充。合并前单独画一条“某天功率和辐照度曲线”肉眼确认峰值是否在同一时刻。我还在工程链路里加了一个自动校验每天统计辐照度与功率的相关系数低于0.9就告警多半是时间对齐出了问题。5.2 晴空模型当作基准导致的乐观偏差现象测试集整体MAE很好看可一到多云天模型“很自信地错”输出接近晴空功率而实际功率只有一半。原因数据集里晴天样本占多数模型学到的最优策略就是偏向晴空输出或者特征里缺少云量信息模型根本不知道有云。解决用NWP的云量、辐照度变异系数作为特征让模型能区分云况按天气类型分组评估而不是只看整体指标如果数据充足晴天和多云天分开建模上线时按当天NWP云量选择模型。这个坑之所以隐蔽是因为整体指标骗人。5.3 天气类型标签容易“伪准确”现象按“晴/多云/阴/雨”分组训练每组验证指标都挺好上线后预测曲线在天气类型切换时跳变剧烈。原因天气类型来自NWP回顾资料网格分辨率是公里级电站尺度只有几百米标签和实况经常对不上而且硬标签把渐变的天况切成了台阶模型在边界处无所适从。解决不要用硬标签当训练目标或唯一特征。改用逐小时的云量、辐照度变异系数、直射比这些连续量。天气类型只作为误差回溯的分组维度不参与模型输入。如果你确实想用相似日也要用连续特征算距离别用类型字符串做匹配。5.4 NWP时效与采样频率不匹配现象每天只取一次0时次NWP做预测到了下午发现实际云况早就变了预测曲线还停留在早上的判断。原因NWP发布有延迟0时次的数据往往凌晨3点才能拿到而且当天更晚时次比如12时次、18时次的更新你没接。短期预测的输入必须是“截至预测时刻能真实拿到的最新NWP”不是论文里理想化的未来时次。解决数据接入时记录每个NWP字段的可用时间戳按“可用时间小于等于预测时刻”过滤。预测任务每天跑两到三次分别用0时次和12时次。模型训练时也按这个规则构造特征否则训练用了未来信息上线后精度必崩。5.5 归一化参数泄漏现象训练误差极低测试误差高出几个档次或者模型预测的功率峰值普遍被压低。原因对全量数据fit了标准化scaler测试集的均值和标准差参与了训练更隐蔽的是用全局最大功率做归一化而这一年里只有少数几天达到峰值绝大多数样本被压缩到很小的区间模型很难区分不同强度的晴天。解决只在训练集上fit scaler验证和测试集只用transform。归一化可以用峰值的滚动百分位比如滚动过去90天的95%分位数避免全年峰值主导。预测端反归一化要用同一个scaler对象不要在每次预测时重新fit。5.6 爬坡事件评估被整体MAE掩盖的风险现象整体MAE达标但调度部门反馈“预测曲线在云团过境时完全跟不上”考核照样被扣分。原因爬坡事件在时间轴上占比很小对MAE的贡献也小但它恰恰是电网调度最关心、最容易引发限电或考核的时刻。整体指标把风险平均掉了。解决单独统计“最大爬坡率时段”的预测误差把功率变化绝对值超过装机容量5%/15分钟的片段抽出来算RMSE和最大偏差。这类时刻的误差来源主要是NWP云团速度不准改进方向是给超短期预测加地基云图或卫星云团外推而不是继续调主模型的超参数。注意如果以上几条排查都做完了精度还不行先别动模型回头查数据时间戳和特征版本。很多“模型退化”其实是数据管道悄悄变了不是模型参数飘了。6. 把模型部署到电站后滚动更新、可信区间与模型退化排查6.1 预测结果的后处理与可信区间模型输出不能直接当上报值要做两层后处理。第一层是物理约束预测功率截断到0和装机容量之间防止个别时点出现负功率或超容量。第二层是给运行人员一个区间而不是一个点。最简单的办法是用最近30天同天气类型的误差分位数生成80%预测区间err y_true - y_pred lower np.quantile(err, 0.1) upper np.quantile(err, 0.9) pred_lower np.clip(pred lower, 0, capacity) pred_upper np.clip(pred upper, 0, capacity)误差分布经常不对称用分位数比假设正态分布更稳。这个区间对储能决策特别有用区间宽说明明天的天况不确定储能策略要留余量。6.2 滚动更新与模型再训练策略部署后不要每天全量重训成本高且容易引入数据漂移。我习惯用近30天数据做周级滚动微调训练集和验证集的划分时间点保持固定这样每次重训后的指标可比。设置一个退化触发条件连续3天nMAE超过历史同期均值1.5倍就手动重训并检查数据管道。模型版本和特征版本要一起记录否则回头看历史预测效果时分不清是模型改坏了还是特征改坏了。6.3 用误差分布表快速排查模型退化最后是验证方法。我会维护一张逐日误差表记录每天的分时段MAE、峰值功率偏差、NWP版本、天气类型。排查退化时按顺序看三件事先看数据是否有缺口和延迟再看NWP是否升级或停更最后检查特征计算代码和scaler版本。我自己吃过一次亏模型上线一个月后精度突然持续下降查了两天才发现是站内辐照度计换了一个传感器读数整体偏高8%模型照样训练整个预测跟着偏移。后来我在数据入库时加了一条“与上一周均值对比”的自动告警这个夜里爬起来查黑匣子的经历再没重演过。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网