资讯动态

MATLAB实现LSTM风速预测:从数据预处理到ELM对比的完整实战

发布时间:2026/10/13 21:42:44 来源:尧图企业网站定制
简介基于LSTM的MATLAB短期风速预测项目面向风能领域研究人员、气象数据分析者及时间序列建模学习者提供了从数据处理到模型训练评估的完整代码参考。压缩包内含13个文件其中7个m脚本实现LSTM、ELM等模型的构建、训练与预测流程3个mat文件保存数据集与归一化参数2个xlsx收录沧州气象与污染日度数据另有1个md说明文档整体仅149KB轻量易部署。目前已有1858人学习下载具备一定的参考价值。项目覆盖数据划分、LSTM网络搭建、Adam优化、误差评估与结果可视化等关键环节并附带ELM模型对比实验便于读者在不同算法间横向比较也为风电场运营决策或相关课程设计提供了可直接运行的MATLAB实现。1. 用LSTM在MATLAB里做短期风速预测先别急着训练风速预测和普通回归不一样今天凌晨的风速往往会影响到明天上午的风速这种时间上的“记忆”是传统BP网络和SVM很难吃进去的。LSTM长短期记忆网络天然就是干这个的它通过输入门、遗忘门、输出门把历史信息有选择地保留下来特别适合处理风速这种有明显自相关的时序数据。这份LSTM-regression-master资源就是一套完整的MATLAB实现从沧州气象站和污染监测站的日度数据出发做了归一化、数据集划分、LSTM训练、反归一化、误差分析还带了一个ELM极限学习机对比模型。适合正在做毕业设计、风电功率预测项目或者想抄一套能跑的时序预测代码来改的从业者。你拿到的不是一个黑匣子是能直接打开看每一步怎么算的源码包。2. 拆包与数据预处理LSTM吃进去的到底是什么2.1 资源包里每个文件是干什么的先别急着跑LSTM.m把压缩包解开后对着文件清单摸一遍底。只看名字就能猜出作者的实验逻辑沧州气象日度数据.xlsx和沧州污染日度数据.xlsx是原始数据data_lstm.mat是处理好的LSTM输入输出对outputps.mat是反归一化用的参数LSTM2.m和LSTM.m是主脚本LSTM_updata_weight.m是手动更新权重的版本ELM.m、elmtrain.m、elmpredict.m是极限学习机对比实验Untitled2.m大概率是画图或者做误差分析的辅助脚本。文件作用沧州气象日度数据.xlsx原始气象特征含风速等变量沧州污染日度数据.xlsx污染浓度特征可拼接做多变量输入data_lstm.mat已划分好的训练/测试数据集LSTM.m / LSTM2.m主训练脚本两版写法不同LSTM_updata_weight.m自定义权重更新训练循环ELM.m / elmtrain.m / elmpredict.mELM基线模型outputps.matmapminmax反归一化参数README.md作者自己的说明这里有一个关键点容易被忽略沧州气象日度数据.xlsx和沧州污染日度数据.xlsx是Excel文件而主脚本里加载的是data_lstm.mat。说明作者已经把原始Excel处理成了MATLAB能直接读的.mat格式。你拿到手后如果改了数据源一定要自己走一遍xlsread再生成新的.mat或者直接在脚本里把load换成xlsread否则会报“文件不存在”或者数据维度不匹配的错误。2.2 归一化与数据集划分mapminmax的正确用法风速预测里最常见的翻车点就是忘记反归一化。LSTM内部用的是tanh和sigmoid激活函数输入输出范围在0~1或者-1~1之间收敛最快如果你把原始风速比如沧州冬季大风天能到15m/s以上直接喂进去损失函数会震荡得很厉害。作者用了mapminmax这是MATLAB里做归一化最常用的函数。% 加载原始数据 data xlsread(沧州气象日度数据.xlsx); wind_speed data(:, col_idx); % col_idx是风速所在列 % 归一化到 [0, 1] [wind_norm, ps] mapminmax(wind_speed, 0, 1); % 划分训练集和测试集比如前80%训练 train_len round(length(wind_norm) * 0.8); train_data wind_norm(1:train_len); test_data wind_norm(train_len1:end); % 构造LSTM输入用过去 lag 个时刻预测下一个时刻 lag 5; XTrain []; YTrain []; for i 1:train_len - lag XTrain [XTrain, train_data(i:ilag-1)]; YTrain [YTrain, train_data(ilag)]; end XTrain XTrain; YTrain YTrain;ps这个结构体里存了归一化的最小值xmin和缩放因子gain后面预测完必须用mapminmax(reverse, YPred, ps)把它还原成真实风速不然你画出来的预测曲线和实际风速永远对不上。lag是滑动窗口长度也就是用过去几个时刻的风速来预测下一时刻。这个值不是随便定的风速数据如果是日度采样lag5意味着用过去5天预测明天如果你做的是小时级预测lag可能要拉大到12甚至24。数据划分的比例也是敏感参数。80%训练、20%测试是默认做法但风速有时间依赖性不能随机打乱后划分必须按时间顺序切分。如果你发现测试集误差特别大先检查是不是把时序打乱了。2.3 原始Excel转成.mat的一站式脚本data_lstm.mat是作者已经处理好的版本但你要用自己的数据就必须走一遍转换流程。我一般会写一个独立的预处理脚本避免每次改数据都要重新打开主脚本。% 读取气象和污染两个表 weather xlsread(沧州气象日度数据.xlsx); pollution xlsread(沧州污染日度数据.xlsx); % 合并特征假设各列已经对齐 features [weather, pollution]; % 缺失值处理用前向填充 for col 1:size(features, 2) for row 2:size(features, 1) if isnan(features(row, col)) features(row, col) features(row-1, col); end end end % 取风速列作为预测目标其他列作为特征 target features(:, wind_col); inputs features(:, setdiff(1:end, wind_col)); % 保存成mat save(data_lstm.mat, inputs, target);缺失值用前向填充是时序数据的常见做法因为风速不会突然从10m/s跳成0前一个时刻的值是最合理的估计。如果你发现数据里有大段的NaN前向填充就不够用了需要做线性插值fillmissing(features, linear)这属于数据质量问题的兜底方案。3. 在MATLAB里把LSTM跑起来从trainNetwork到自定义权重更新3.1 标准训练路径LSTM.m里做了什么主脚本LSTM.m走的是MATLAB深度学习工具箱的标准路线sequenceInputLayer定义输入维度lstmLayer定义隐藏单元数fullyConnectedLayer接回归输出regressionLayer指定损失函数。这套组合是时序回归任务的固定配方。% 定义LSTM网络结构 numFeatures size(XTrain, 2); % 输入特征维度 numHiddenUnits 50; % 隐藏层神经元数 layers [ sequenceInputLayer(numFeatures) lstmLayer(numHiddenUnits, OutputMode, last) fullyConnectedLayer(1) regressionLayer]; % 训练选项 options trainingOptions(adam, ... MaxEpochs, 200, ... InitialLearnRate, 0.005, ... LearnRateSchedule, piecewise, ... LearnRateDropFactor, 0.2, ... LearnRateDropPeriod, 50, ... MiniBatchSize, 32, ... Verbose, 0); % 训练 net trainNetwork(XTrain, YTrain, layers, options);注意OutputMode这个参数它决定LSTM层的输出方式。预测单个风速值时用last只返回最后一个时间步的输出如果是做序列到序列的预测比如预测未来多天风速就要改成sequence。这是新手最容易选错的地方选错之后维度对不上报错信息还很晦涩。InitialLearnRate设成0.005看起来比默认值0.001激进一些但风速数据量不大沧州日度数据撑死几千条大一点的学习率收敛更快配合piecewise的下降策略每隔50轮学习率降为原来的0.2倍可以避免后期震荡。训练完之后保存模型和归一化参数这是个好习惯。下次加载直接load(lstm_net.mat)就能预测不用重新训练% 保存模型和参数 save(lstm_model.mat, net, ps, lag);3.2 LSTM_updata_weight.m手动更新权重到底在更新什么这个文件是整套资源里含金量最高的部分。MATLAB的trainNetwork是个黑匣子你只知道损失在降但看不到梯度怎么流、权重怎么更新。LSTM_updata_weight.m把训练循环拆开了核心是计算预测值和真实值的误差然后用梯度下降更新权重矩阵。% 手动训练循环核心是权重更新 for epoch 1:max_epochs % 前向传播计算LSTM输出 [h, c] lstm_forward(XTrain, W_ih, W_hh, b_h); y_pred h * W_hy b_y; % 计算损失均方误差 loss mean((y_pred - YTrain).^2); % 反向传播计算梯度 d_loss 2 * (y_pred - YTrain) / length(YTrain); d_W_hy h * d_loss; d_b_y sum(d_loss); % 更新权重学习率乘以负梯度 W_hy W_hy - lr * d_W_hy; b_y b_y - lr * d_b_y; % 记录损失 loss_history(epoch) loss; end这段代码里的lstm_forward是作者自己写的LSTM前向传播函数里面包含遗忘门、输入门、输出门和记忆单元的状态更新。如果你真想搞懂LSTM的机制把这几个门矩阵的维度打印出来看一遍比看十篇理论文章都管用。手动更新权重还有一个实际好处你可以中途修改学习率、加正则化项、甚至做梯度裁剪这在trainNetwork里都是预设好的不好干预。梯度裁剪在风速预测里特别重要。风速数据偶尔会有极端值台风、寒潮一个异常样本产生的梯度会把积累了几个epoch的权重直接冲垮损失变成NaN。如果你发现训练到一半loss突然变成NaN99%是梯度爆炸加上梯度裁剪就能解决。3.3 反归一化、误差指标和画图预测完别急着交差训练完之后最关键的几步预测、反归一化、算误差、画图。预测用predict函数输入测试集的特征输出归一化后的预测值然后用之前保存的ps参数反归一化。% 预测 YPred_norm predict(net, XTest); YPred mapminmax(reverse, YPred_norm, ps); YTest_real mapminmax(reverse, YTest_norm, ps); % 计算误差指标 rmse sqrt(mean((YPred - YTest_real).^2)); mae mean(abs(YPred - YTest_real)); r2 1 - sum((YTest_real - YPred).^2) / sum((YTest_real - mean(YTest_real)).^2); % 画对比图 figure; plot(YTest_real, b-, LineWidth, 1.2); hold on; plot(YPred, r--, LineWidth, 1.2); legend(实际风速, 预测风速); xlabel(时间步); ylabel(风速 (m/s)); title([LSTM预测结果 RMSE, num2str(rmse), R^2, num2str(r2)]);RMSE和MAE反映绝对误差水平R²反映模型对风速波动的解释能力。风速预测里R²不算太高很正常因为风速本质上是混沌的能解释60%以上的方差就已经有实用价值了。画图的时候把两条曲线叠在一起如果预测曲线比实际曲线“平滑”很多说明模型只学到了低频趋势高频波动没抓住这时候需要增加numHiddenUnits或者缩短lag。4. 避坑与常见问题风速预测最容易翻车的五个点4.1 预测结果整体滞后一拍现象预测曲线和实际曲线形状相似但整体右移了一个时间步RMSE看着还行但峰值永远对不上。原因用过去lag个时刻预测下一个时刻的训练方式本质上假设系统是Markov的而LSTM学到的最优策略往往就是“复制上一时刻的值”因为风速自相关性强这样损失最小。解决检查lag取值日度数据lag5也许不够把lag增大到7或10试试。更有效的方法是不要只预测下一个时刻改成预测未来k个时刻的序列强制模型学到趋势而不是复制。4.2 loss曲线震荡剧烈或者直接变成NaN现象训练初期loss在下降但某一轮之后loss突然变成NaN或者在某个值附近来回震荡下不去。原因学习率太大导致权重的更新步长跨过了最优区域另一个常见原因是数据里有NaN或者极端值前向传播时梯度爆炸。解决先检查训练数据里有没有NaN用isnan(sum(XTrain,2))扫一遍。然后降低InitialLearnRate到0.001或0.0005。如果loss还是NaN在trainingOptions里加上GradientThreshold, 1这是全局梯度裁剪能直接砍掉爆炸的梯度。4.3 归一化之后忘记反归一化现象预测误差大得离谱RMSE上百画出来的预测曲线在0到1之间实际风速却是个位数到十几。原因这是最基础的错误但也有不少人踩——训练时归一化了好几个不同的数组把ps覆盖了或者用了不同的归一化函数比如normalize和mapminmax混用反归一化时参数对不上。解决把mapminmax得到的ps保存成独立的mat文件只用它做反归一化。我通常会在脚本开头统一管理全部用mapminmax(x, 0, 1)不允许中途换归一化方式。4.4 用trainNetwork训练时内存溢出现象数据量只有几千条但训练时MATLAB提示内存不足。原因MiniBatchSize设置太大或者输入数据是cell数组形式的sequence每条序列长度不一致导致补齐时急剧膨胀。解决把MiniBatchSize从64降到16或8。还可以考虑用padsequences统一序列长度或者每次训练时随机抽取一部分数据做batch而不是一次性全量送入。4.5 实验对比不公平现象LSTM的RMSE比ELM还差但你觉得模型没调好。原因ELM在这个资源里是基线模型但ELM在训练前有随机初始化权重的特性如果你只跑一次就下结论很可能LSTM那次运气不好初始化到了一个差的局部最优。解决每个模型跑10次取平均和标准差同时保证训练集测试集划分一致。数据划分的随机种子要固定用rng(42)在脚本开头设定。这也是为什么资源包里有ELM.m——对比实验必须可复现。5. 用ELM做基线对比怎么证明LSTM真的更好5.1 跑通ELM基线模型资源包里有elmtrain.m和elmpredict.m这是极限学习机的标准实现。ELM的核心思想是输入层到隐含层的权重随机初始化且固定不变只训练输出层的权重。它训练速度快到几乎不用等但预测能力理论上不如LSTM能捕捉长期依赖。% 用同样的归一化数据训练ELM [IW, B, LW, TF, TYPE] elmtrain(XTrain, YTrain, 20, sig, 0); YPred_elm elmpredict(XTest, IW, B, LW, TF, TYPE); % 反归一化 YPred_elm_real mapminmax(reverse, YPred_elm, ps); % 计算ELM的误差 rmse_elm sqrt(mean((YPred_elm_real - YTest_real).^2));elmtrain的参数依次是训练输入、训练输出、隐含层节点数这里是20、激活函数sig表示sigmoid、正则化系数0表示不正则化。跑完之后你会看到ELM也能出结果而且速度飞快但误差通常比调好参数的LSTM大——尤其在中长期的波动预测上。5.2 判断LSTM是否真的赢了拿两个模型的RMSE、MAE、R²放在一张表里对比同时记录训练耗时。如果你的LSTM经过调参后RMSE比ELM低10%以上说明LSTM确实学到了时序依赖如果只低5%以内而且训练时间是ELM的几百倍那就要考虑你的数据量是否足够支撑LSTM的复杂度。以沧州日度数据为例一年只有365条三年也就1000来条。LSTM在这种小样本场景下很容易过拟合训练集误差很低测试集误差反而比ELM高。这是时序预测里一个很现实的问题——深度学习模型是数据饥渴型的样本量不够时简单模型反而占优势。资源包同时提供LSTM和ELM就是为了让你在对比中看清这一点。5.3 模型输出作为决策支持预测结果往哪用风速预测的最终目的是给风电场运营、电网调度做参考。预测结果可以作为一个输入进入功率预测模型或者直接用于评估未来24小时的风电出力区间。实操中我习惯把预测值和真实值作为一个数据表导出方便后处理系统直接读取。从那以后我每次拿到一个MATLAB时序预测项目都强制自己先跑一遍基线模型再调LSTM否则根本分不清预测误差是模型结构造成的还是超参数没调好。LSTM能记住风速的“惯性”但记住不等于预测准验证一个模型的真实水平永远要靠和简单模型做残酷对比。这份资源帮你省掉了自己写ELM和反归一化的时间剩下的精细活就看你在对比里能不能沉住气。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑