LSTM光伏预测与储能调度:从时序建模到规则集落地的完整工程实践
简介面向光伏功率预测场景的LSTM短期预测算法Python实现与源码包适合计算机相关专业的学生、开发者及科研人员用于毕业设计、课程设计或项目初期验证。项目已通过运行测试平均答辩评分达96分支持远程教学答疑并附有说明文档零基础用户也可参考学习。压缩包共11个文件以6个Jupyter Notebook为核心完整呈现光伏与负荷预测的建模流程涵盖单变量与规则集融合的对比实验方便评估不同输入策略对预测精度的影响另含1个Python脚本用于气象数据获取、1份Excel数据文件作为样本数据以及图片和Markdown说明文档便于快速理解数据流向与工程结构。包体约3.89MB体积小巧、开箱即用。目前已有199人学习下载适合需要快速搭建光伏预测基线模型、深入理解LSTM时序建模思路的读者也可作为负荷预测等相近任务的参考实现。1. 短期光伏预测LSTM源码包里的工程化思路园区屋顶光伏的出力曲线在多云天气下十五分钟就能从满发跌到三成。做短期光伏预测如果只训练一个LSTM模型就扔到生产环境效果往往不稳定。我拿到这份以园区实测数据为基础的源码包时发现它比一般毕设多考虑了两件事一是用 ClearOutside 天气接口把辐照度作为预测特征二是把预测结果接入带 SOC 约束的储能规则集。整个资源不是单文件而是一组 notebook 配合数据表光伏预测、负荷预测、模拟程序、规则集第一版完整走通了从数据到调度策略的链路。适合正在做光伏预测或储能方向毕设的人也适合想用 LSTM 做时序回归但不想只做 MNIST 的 Python 开发者。下面按数据准备、模型构建、规则调度三个层次拆开来讲。2. LSTM光伏预测前的数据准备SOC时序、天气API与数据清洗2.1 先看清资源里的数据类型源码包里的SOC_1101-1107.xlsx文件名说明它记录了 11 月 1 日到 7 日这一周的储能电池 SOC 数据。SOC 是 State of Charge即电池当前剩余电量百分比。光伏预测真正要用的是历史光伏功率序列和天气序列SOC 数据是后面规则集调度那一步才需要的。我拿到 Excel 后第一件事不是训练而是确认索引是不是时间格式有没有重复时间戳。import pandas as pd df pd.read_excel(SOC_1101-1107.xlsx, parse_dates[time], index_coltime) print(df.info()) print(df.head(3)) print(df.columns)逻辑说明parse_dates将 time 列解析为 DatetimeIndex便于后续按时间切片和重采样。df.info()能一眼看出每一列的缺失值与数据类型比如 SOC 列是否混入了 object 类型字符串。如果是 15 分钟一条记录一周数据应该有7*24*4672条如果差很多就要回到采集源头检查故障时段。数据字段方面这份资源里至少会涉及下表这些列实际列名以 notebook 为准字段说明典型单位time时间戳15分钟粒度datetimepv_power光伏实际功率kWload_power园区负荷功率kWsoc储能电池荷电状态%temperature环境温度℃ghi水平总辐照度W/m²如果某个表里没有辐照度不要硬用。光伏预测退化为单变量模型时可以只用 pv_power 历史值因为光伏功率本身已经包含了天气对出力的影响。2.2 用 clearoutside_url.py 拉取离线天气特征资源里有个clearoutside_url.py脚本用来生成 ClearOutside 请求链接。ClearOutside 是光伏领域常用的免费气象服务可以提供逐小时的 GHI、DNI、温度、云量预测适合作为预测日当天的额外特征。常规用法是先根据园区经纬度构造请求地址再用 requests 拉取 JSON。源码包里没写死城市需要手动填经纬度。import requests def fetch_clearoutside(lat, lon, date_str): base_url https://api.clearoutside.com/forecast params { lat: lat, lon: lon, format: json, date: date_str } resp requests.get(base_url, paramsparams) resp.raise_for_status() return resp.json() # 示例某园区经纬度日期按实际替换 data fetch_clearoutside(39.90, 116.40, 2024-11-01) print(data.keys())参数说明lat 和 lon 是十进制经纬度date_str 控制预测日期窗口返回的 JSON 里通常有ghi、dni、clouds、temperature等字段。需要注意它的时间分辨率可能是 1 小时而光伏功率是 15 分钟粒度需要做插值或上采样。我一般用pandas.Series.interpolate()把小时级辐照度插值到 15 分钟避免 LSTM 输入序列长度不一致。2.3 时间对齐与缺失值处理def align_features(pv_df, weather_df): # 统一重采样到15分钟 pv_df pv_df.resample(15min).interpolate() weather_df weather_df.resample(15min).interpolate() # 内连接去掉天气接口和本地表缺失重叠的部分 merged pv_df.join(weather_df, howinner) merged merged.dropna() return merged这段代码有两个关键点resample(15min)要求索引已经是 datetime 类型否则会报错interpolate()默认线性插值适合短时段缺失但连续超过 1 小时的数据不建议插值而是直接删除因为 LSTM 会对异常序列产生偏移记忆。dropna()删掉仍然为空的行训练集里宁可少几组样本也不能带着 NaN 进归一化。预测效果的上限由数据对齐质量决定而不是由网络层数决定。把 SOC、功率、天气三份数据在时间轴上对齐后面模型才有东西可学。3. 从单变量到多变量LSTM光伏预测模型的构建与训练3.1 单变量与多变量的适用边界光伏功率序列有很强的日周期性单变量 LSTM 只用过去几小时的功率预测未来功率在前一天天气稳定时效果不错但遇到多云或阵雨单变量模型没有输入信息能反映云层变化误差会急剧放大。多变量模型把辐照度、温度、湿度作为额外特征等于提前告诉模型“这个时段辐照度要掉”预测曲线能更快跟随天气转折。源码包里两个测试文件——单变量版和带 Copy 的多变量版正好可以对比这种差异。训练之前先想清楚你的历史数据里有没有可靠的气象特征如果没有可靠数据源就用单变量别硬撑多变量。模型类型输入特征适用场景误差特点单变量pv_power 历史序列数据缺失、仅有功率表晴天误差小突变天气反应慢多变量pv_power ghi temperature有可靠气象接口突变天气更敏感但依赖特征质量3.2 构造 LSTM 监督学习样本LSTM 不能直接吃原始的连续功率序列要先把序列切成固定窗口的监督学习样本。假设用过去 6 小时24 个 15 分钟点预测未来 1 小时4 个点look_back24look_forward4。import numpy as np def create_dataset(series, look_back24, look_forward4): X, y [], [] for i in range(len(series) - look_back - look_forward 1): X.append(series[i:i look_back]) y.append(series[i look_back:i look_back look_forward]) return np.array(X), np.array(y) # series 是归一化后的功率序列shape 为 (样本数, 1) X, y create_dataset(scaled_values, look_back24, look_forward4) print(X.shape, y.shape) # (样本数, 24, 1) (样本数, 4)逻辑说明X的维度是 (样本数, 时间步, 特征数)LSTM 的输入要求就是这种三维张量。look_forward4表示直接预测未来 4 个点这种做法在训练时比递归预测更稳定因为每个输出位置都有独立的梯度更新路径。scaled_values需要先通过MinMaxScaler变换到 [0,1] 区间避免功率和辐照度的量纲差异影响梯度。如果特征不止一个思路相同把每列归一化后按列拼接再调用create_dataset此时X.shape[2]会大于 1。3.3 搭建 LSTM 模型与训练from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense, Dropout from tensorflow.keras.callbacks import EarlyStopping model Sequential() model.add(LSTM(64, activationtanh, return_sequencesTrue, input_shape(X.shape[1], X.shape[2]))) model.add(Dropout(0.2)) model.add(LSTM(32, activationtanh)) model.add(Dense(4)) model.compile(optimizeradam, lossmse, metrics[mae]) model.summary()参数说明第一层 LSTM 设置return_sequencesTrue是因为后面还要接第二层 LSTM需要把完整的隐藏状态序列传给下一层activationtanh是 LSTM 默认且最稳的激活。Dense(4)直接输出未来 4 个预测点。Dropout(0.2)用于抑制过拟合光伏数据集通常只有几周到几个月样本量不大dropout 不加反而容易记住噪声。训练时加早停防止小数据集过拟合early_stop EarlyStopping(monitorval_loss, patience10, restore_best_weightsTrue) history model.fit( X_train, y_train, validation_data(X_val, y_val), epochs100, batch_size32, callbacks[early_stop], verbose1 )patience10表示验证集损失连续 10 个 epochs 不改善就回滚到最优权重。光伏数据通常只有几周epochs 设 100实际训练大概 20-30 轮就会触发早停。训练完之后用scaler.inverse_transform(y_pred)把结果还原成实际功率单位再计算 RMSE 或 MAE这样得到的指标才是有物理意义的功率误差。from sklearn.metrics import mean_absolute_error y_true_rescaled scaler.inverse_transform(y_test) y_pred_rescaled scaler.inverse_transform(y_pred) mae_kw mean_absolute_error( y_true_rescaled.mean(axis1), y_pred_rescaled.mean(axis1) ) print(f未来1小时平均功率MAE: {mae_kw:.2f} kW)如果 MAE 偏大优先检查是否把未来 4 个点当作 4 个独立样本算误差。正确做法是每个样本取未来 1 小时的平均值再算误差这样和储能调度策略关注的时间尺度一致。多变量模型加入辐照度后通常能把多云天的峰值误差减少三分之一左右但前提是天气特征的日期能和功率时间索引严格对齐。4. 规则集与储能框架预测结果向充放电策略的转换4.1 规则集到底在控制什么资源里“规则集-第一版.png”是一张规则表实际上对应储能控制策略的决策边界。光伏预测只解决“未来能发多少电”储能框架解决“这些电往哪放”。规则集通常考虑三个约束SOC 上下限、功率越限阈值、充放电优先级。比如 SOC 高于 90% 时不允许充电低于 20% 时不允许放电净负荷为负且 SOC 低于 90% 时优先充电。从工程角度看规则集不是一个可学习的模型而是一组可解释的 if-then 判断。这也符合毕设答辩时“你的策略为什么这样设”的场景直接对应到电池保护和用电成本比黑盒模型更容易讲清楚。4.2 用规则集生成调度指令def dispatch_rule(pv_forecast, load_forecast, soc, soc_max90, soc_min20, rated_power50): # 净负荷为正表示需要从电网买电为负表示光伏富余 net_load load_forecast - pv_forecast if net_load 0 and soc soc_max: # 充电功率不超过储能额定功率 charge_power min(-net_load, rated_power) return charge_power, 0 elif net_load 0 and soc soc_min: # 放电功率不超过储能额定功率 discharge_power min(net_load, rated_power) return 0, discharge_power else: return 0, 0参数说明soc_max和soc_min是电池保护边界工业上一般不会冲到 100%而是留出 5% 余量rated_power是储能额定功率这里按 50kW 示例。charge_power取净负荷和额定功率的较小值避免超功率充电。规则集第一版里如果叠加分时电价就需要在规则表里增加时间维比如夜间低谷电价强制充电白天高峰强制放电。条件动作约束net_load 0 且 soc soc_max充电charge_power ≤ rated_powernet_load 0 且 soc soc_min放电discharge_power ≤ rated_power其余情况保持不动作4.3 把 LSTM 预测结果接入模拟程序模拟程序.ipynb 里的思路是先用训练好的 LSTM 模型生成未来 4 小时的光伏预测同时用负荷预测 LSTM 生成负荷曲线然后逐 15 分钟走一遍规则集更新 SOC 状态统计一天的电网购电量和收益。soc 50 # 初始50% energy_from_grid 0 step_hours 0.25 for i in range(len(pv_pred)): pv_p pv_pred[i] load_p load_pred[i] charge, discharge dispatch_rule(pv_p, load_p, soc) # 粗略线性SOC模型充放电功率对SOC的积分 soc (charge - discharge) * step_hours / battery_capacity * 100 soc min(max(soc, 10), 100) net load_p - pv_p discharge - charge # 从电网取电为正 energy_from_grid max(0, net) * step_hours这段代码里battery_capacity是电池容量单位 kWh与充放电功率的积分一起决定 SOC 变化速度。注意这里没有考虑电池充电效率实际模拟中应在charge乘以 0.9 左右的效率系数。如果只关注预测算法可以跳过这一步但毕设答辩时能把“预测误差对 SOC 轨迹的影响”讲两句会明显比只会调库的候选人有深度。策略对误差的敏感度不一样如果一个点预测偏高导致少充电后面的用电成本会变高。所以我在接入模拟程序时会在规则集里加一个安全边际比如把预测功率乘以 0.95 再送入调度判断让预测误差朝保守方向偏移避免储能系统频繁动作。5. 光伏LSTM训练的几个落地技巧归一化、多步预测与早停5.1 归一化只拟合训练集from sklearn.preprocessing import MinMaxScaler scaler MinMaxScaler() # 错误做法scaler.fit(whole_data) # 正确做法 scaler.fit(X_train) X_train_scaled scaler.transform(X_train) X_val_scaled scaler.transform(X_val)用整段数据拟合 scaler 会泄漏未来信息导致验证指标虚高。光伏时序有季节漂移冬季和夏季功率幅值差异很大归一化参数不要跟着测试集更新。如果数据只有一周这一点更关键。5.2 多步预测的两种策略直接多输出Dense(4)的优点是训练简单但会强制每一步误差独立递归预测把上一步输出拼回输入更贴近在线推理但会累积误差。折中方案是分两个阶段先用直接多输出训练再在验证集上做递归预测对比如果递归误差远大于直接输出说明模型过拟合了短时波动应该加大 Dropout 或减少 LSTM 单元数。5.3 把早停和模型保存绑在一起from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint ckpt ModelCheckpoint(best_pv_lstm.keras, save_best_onlyTrue, monitorval_loss) history model.fit( X_train, y_train, validation_data(X_val, y_val), epochs100, batch_size32, callbacks[early_stop, ckpt], verbose1 )验证集 loss 最低的权重会被单独保存restore_best_weights只恢复内存里的权重ModelCheckpoint负责把最佳版本写到磁盘。后面做模拟调度时直接load_model加载跳过训练阶段。光伏预测模型不建议保存为 h5 之外的自定义格式keras 版本升级后自定义层容易加载失败。这几个点都不改动网络结构但对复现结果影响很大我实际项目中花在归一化和预测策略上的时间通常比调 LSTM 层数多得多。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联
返回资讯列表 →