简介:本资源是一套面向计算机、电子信息工程及数学等专业本科生的风电功率预测实践方案,聚焦于利用多变量输入实现单步短期功率预测,解决风能并网中因间歇性带来的调度与稳定性难题。资源提供完整的Matlab实现代码(适配2014a/2019a/2024a),融合时空卷积网络(TCN)与双向门控循环单元(BiGRU)优势,兼顾局部时序特征提取与长程依赖建模能力,并支持风速、风向、温压湿及历史功率等多源数据联合输入。压缩包共15个文件,含8个核心m脚本(如MAIN.m主流程、data_process.m数据预处理、calc_error.m误差评估)、4张结果可视化png图、2个实测风电场xlsx数据表及1个asv备份文件,总大小4.38MB,结构清晰、参数化设计、注释详尽,便于课程设计、期末大作业与毕业设计快速复现与二次开发。已有136人学习下载,可直接运行、灵活调参、深入理解模型架构与电力系统预测逻辑。 做风电功率预测的同行应该都有体会,功率序列波动大、影响因素多,光看历史功率曲线很难猜中下一秒的变化。我之前用LSTM和GRU做过几版,效果能看,但一到风速突变、天气转折的时候,误差就明显放大。后来把TCN和BiGRU拼在一起,做成多变量输入的单步预测模型,在MATLAB里完整跑通,精度和平稳性都有比较明显的提升。这篇文章把整个方案的思路、数据准备、模型搭建、代码实现和踩坑记录都放出来,想复现的朋友可以直接照着做,尤其是准备做时序预测但还没理清“TCN到底怎么搭”“BiGRU在MATLAB里怎么实现”这些细节的,这篇笔记应该能帮你省不少时间。
先说清楚这个方案解决的问题。风电功率预测本质上是回归任务,输入是一段历史时间窗内的多个物理量,输出是未来某个时刻的功率值。我用的输入包括风速、风向、温度、气压、历史功率等,输出就是一列功率预测值。TCN负责提取时间窗口内的局部特征,BiGRU负责进一步挖掘输入序列的双向时序依赖,最后的全连接层把隐层特征映射成功率。整个建模过程都在MATLAB环境下完成,后面我会给出代码骨架和调参经验。
1. 风电功率预测问题与整体方案设计
1.1 为什么非要做功率预测
风电功率的随机性由气象条件主导,风速、风向、温度、气压、湍流强度都在变,输出功率并不稳定。电网调度需要提前知道未来一段时间风机能发多少电,才好安排火电启停和备用容量。预测精度不够,要么多备火电造成浪费,要么功率偏差超过调度标准被考核,风电场损失收益。这个需求是实打实的,不像很多学术课题离工程太远,功率预测模型做好之后可以直接接进场站的能量管理平台。
从时间尺度上分,超短期预测一般是指未来15分钟到4小时,短期预测是未来1到3天,中期预测是未来一周甚至更久。风电功率预测研究的重点通常集中在超短期和短期,因为这两个时间尺度对调度最直接。单步预测在超短期场景里用得最多,输入过去一到两小时的数据,预测下一个时刻的功率,模型可以跟着滚动窗口一直运行。
1.2 单步预测、多变量输入意味着什么
单步预测用过去一段窗口的特征预测下一时刻功率,实时性好,可以滚动外推。多变量输入意味着除了历史功率,还输入NWP(数值天气预报)或实测的风速、风向、温度、气压等。因为功率对气象响应有明显滞后和非线性,只用历史功率属于单变量时序预测,相当于“用过去猜未来”,在天气突变时很难跟上。多变量输入等于给模型提供了“提前量”和因果线索,让模型有机会学到风速变化之后功率会怎么变。
我先选择单步预测而不是多步,原因很直接:单步是基础,多步预测误差会累积,前一步错后一步错,模型结构测试阶段先用单步验证特征有效性,更可控。等单步模型跑稳了,再往上叠滚动预测或者seq2seq结构,才不容易被误差累积问题干扰判断。这是做时序预测的一个通用方法论,先把单点精度打到足够好,再去处理多步外推的不确定性。
1.3 为什么选用TCN-BiGRU这套组合
传统RNN/LSTM的问题是串行计算慢,长序列容易出现梯度问题,模型对长时间依赖的建模并不是天生擅长。TCN(时间卷积网络)用因果膨胀卷积叠加残差块,能够以较少的层数覆盖很长的感受野,训练可以并行,计算效率高。但TCN本质上对“时间顺序”的建模是隐式的,如果要更显式地挖掘双向时间依赖,可以在TCN输出之后接入BiGRU。
BiGRU(双向门控循环单元)擅长提取序列的双向上下文特征,参数比LSTM少,训练速度更快。在TCN之后加BiGRU,属于“先局部后全局”的建模思路:TCN负责捕捉多尺度局部模式和气象输入之间的短期耦合关系,BiGRU再对TCN输出序列从正向和反向两个方向做时序依赖建模,最终通过全连接层输出预测值。这个组合在多个功率预测文献里的效果优于单独TCN或单独BiGRU,原因正是两种结构互补:TCN擅长规则化卷积和感受野控制,BiGRU擅长门控记忆和双向上下文。简单来说,TCN相当于“先看局部规律”,BiGRU负责“再串一遍全局顺序”。
2. 数据准备与预处理——做预测最重要的基本功
2.1 数据字段与来源
我用的数据集是风电场SCADA系统导出的历史运行数据加NWP数据,核心字段如下表:
| 字段名 | 含义 | 是否作为输入 |
|---|---|---|
| time | 时间戳 | 否 |
| wind_speed | 轮毂高度风速 | 是 |
| wind_dir | 风向(0-360°) | 是 |
| temp | 环境温度 | 是 |
| pressure | 气压 | 是 |
| humidity | 相对湿度 | 是 |
| power | 实际功率 | 是(历史窗口) |
| target_power | 预测目标 | 标签 |
采样间隔一般是10分钟或15分钟,超短期预测惯用10min粒度。原始数据里有停机、限电、通讯中断造成的记录,需要先清洗。我在代码里留了数据读取接口,不管你的数据是CSV还是Excel,统一读成表格再按列名操作。
2.2 缺失值和异常值处理思路
缺失值处理分两种情况:小段缺失(连续少于3个点)用线性插值;长段缺失直接删除对应样本,不要把插值用在功率剧烈变动的缺口上,否则模型会学到假规律。风电功率在爬坡段变化很快,线性插值补出来的数据是直线上升,这一小段样本会让模型误以为爬坡都是线性的,实际预测时会低估变化速度。
异常值我用两个判据并记录剔除数:风速大于切入或切出风速但功率不为0,或功率超过额定值的1.2倍,基本是采集异常。处理之后做一次滑动平均平滑,窗长为3,但平滑强度不能太大,不然容易把功率爬坡的细节抹掉。这里有个取舍:平滑能去掉传感器毛刺,但也可能削掉真实的变化特征,所以我一般只做一个很轻的平滑。
2.3 归一化:每个特征单独归一化
归一化是深度学习的必修课。通常用min-max归一化或z-score。实测下来,如果数据存在明显的离群点,min-max会把大多数正常数值压在一个很小的区间,反而影响训练表现;建议先用分位数(比如1%和99%分位)做截断再min-max,或者直接用z-score。我在代码里默认提供min-max和z-score两种,想要换只要改一个参数。
特别提一句风向处理。风向是0到360度的环形变量,直接输入0和360两个数值,模型会以为它们相距很远,实际上它们是同一个方向。我习惯把风向拆成sin和cos两个特征,相当于把角度映射到单位圆上,距离就合理了。这个细节很多人第一次做会忽略,但它对预测精度的影响比想象中大。
2.4 构建多变量滑动窗口样本
构造输入X和标签y的思路:假设窗口长度是win_size,特征维度是fea_dim,那么每个样本的X形状是[win_size, fea_dim],y是一个标量,代表下一时刻的功率。MATLAB里我先把所有特征按时间顺序排成矩阵,然后用循环从第win_size+1行开始切窗口,每切一个窗口就对应一个标签。
窗口长度我测试过6/12/24/48这几种,10分钟粒度下win_size=12(过去2小时)是一个比较平衡的取值;太短顶不住气象滞后,太长会增加TCN感受野压力而且训练变慢。具体到不同风场,最优窗口会有差别,建议先跑一组对比实验再定。我这里说的窗口长度是通过滑动窗口样本数量、训练耗时和预测误差三个维度一起评估的,不是拍脑袋定的。
3. TCN-BiGRU模型结构和参数设计
3.1 TCN模块的三件套:因果卷积、膨胀卷积、残差连接
TCN的核心是三件套:因果卷积、膨胀卷积、残差连接。因果卷积保证t时刻只用到t及之前的输入,不偷看未来,这是时序预测的基本要求。膨胀卷积给卷积核加上间隔d,让感受野随层数指数增长,两层膨胀d=1和d=2叠加,就能看到更远的过去信息。残差连接把输入和卷积输出相加,避免深层网络退化,同时让梯度传递更稳。
感受野的经验公式要记住:receptive_field = 1 + (kernel_size - 1) * sum(dilation_factors)。比如kernel_size=3,dilation=[1,2,4,8],那感受野 = 1 + 2*(1+2+4+8) = 31个时间步。这个参数需要根据窗口长度去配,最好让感受野覆盖整个输入窗口,否则模型在时间维上“看不全”输入信息,预测能力会受限制。
3.2 BiGRU模块:比LSTM轻量,但需要处理MATLAB的限制
GRU比LSTM少了输出门和细胞状态,参数少、训练快。双向GRU把序列从前后两个方向各跑一遍,然后拼接或相加两个方向的隐状态,这样每个位置的表示都包含整个窗口的“前文”和“后文”信息。在风电功率场景里,过去的功率状态和未来的变化趋势都对当前时刻有影响,双向建模确实能提升特征表达能力。
这里要提醒一个MATLAB实现的坑:深度学习工具箱里的bilstmLayer封装的是BiLSTM,不是BiGRU。严格区分时需要用自定义层,或者用dlnetwork配合自定义网络结构。我后面给出的代码里会写两种方案,第一种用trainNetwork快速跑通,第二种用dlnetwork实现严格意义的BiGRU。如果只是做工程对比,第一种够用;如果做研究发表,建议用第二种。
3.3 全局结构与超参数配置参考
我推荐一组基准参数,供第一次复现使用:
| 参数 | 推荐值 | 说明 |
|---|---|---|
| 窗口大小 win_size | 12 | 对应120分钟历史 |
| 输入特征维度 | 5~8 | 风速、风向sin/cos、温度、气压、湿度、历史功率等 |
| TCN卷积核大小 | 3 | 常见值,不宜过大 |
| TCN通道数 | 32/64 | 首层32,加深层64 |
| 膨胀系数 | [1,2,4,8] | 根据窗口调整 |
| BiGRU隐层单元数 | 32或64 | 单向GRU的隐单元数×2 |
| Dropout | 0.2~0.3 | 防止过拟合 |
| 输出层 | 1个神经元 | 回归任务 |
| 损失函数 | MSE | 回归任务默认 |
| 优化器 | Adam,学习率1e-3 | 可配合学习率衰减 |
| Batch size | 32或64 | 训练集样本多可以64 |
| Epochs | 50~100 | 早停阈值 patience=10 |
这套参数在几个公开数据集上都跑得动,不是最优但方向对。真正的调参空间其实集中在TCN通道数、膨胀系数和BiGRU隐单元数这三块。学习率我建议先从1e-3开始,Loss下降太慢就调到3e-3,验证集开始抖动就降到3e-4,这种粗调比固定一个值跑到结束要快得多。
3.4 为什么TCN和BiGRU放一起能提升
单独TCN,即使卷积感受野够大,它本质是对局部模式的加权组合,缺少门控机制去决定“哪些过去信息需要记住、哪些该忘掉”;单独BiGRU,对输入序列从头到尾做双向编码,但输入是原始的连续变量,没有经过多尺度特征提取,长序列建模时也会吃力。组合以后,TCN先做特征提取和降维,BiGRU再在特征序列上做时序整合。
我自己对比过的实验里,TCN-BiGRU的组合在突变时段比单独TCN的RMSE低5~10%,比单独BiGRU低3~6%。这个提升幅度在功率预测领域算很可观了。换个角度看,这也说明两类结构确实在提取不同维度的信息,组合起来覆盖了“局部细节”和“全局依赖”两个层面的特征。
4. MATLAB实现全过程
4.1 环境与工具箱
我用的是MATLAB R2022a/R2023b,需要安装Deep Learning Toolbox(深度学习工具箱)和Statistics and Machine Learning Toolbox(统计和机器学习工具箱)。另外,自定义训练循环会用到dlarray和dlgradient,这些都在深度学习工具箱里。版本太老,比如R2019b之前,dlnetwork支持不足,建议还是用新版本。
4.2 文件结构与主流程
压缩包里的代码我不建议所有内容堆在一个脚本里。推荐按功能拆分,这样调试起来不用从头跑:
| 文件 | 作用 |
|---|---|
| load_data.m | 读取CSV/Excel并清洗 |
| preprocess.m | 归一化、构建滑动窗口样本 |
| build_network.m | 构建TCN-BiGRU网络结构 |
| train_model.m | 自定义训练循环 |
| predict_model.m | 用训练好的模型做预测并反归一化 |
| evaluate_model.m | 计算指标、绘图 |
4.3 数据读取和预处理代码
我直接给出一段能跑通主流程的代码骨架,你拿到后把文件名和列名换成自己的数据就行:
% main.m clear; clc; rng(42); % 1. 读取数据 data = readtable('wind_farm_data.xlsx'); % 列: time wind_speed wind_dir temp pressure power % 2. 缺失值插值 data.power = fillmissing(data.power, 'linear'); data.wind_speed = fillmissing(data.wind_speed, 'linear'); % 3. 异常值粗筛 invalid = (data.wind_speed < 0) | (data.power < 0) | (data.power > 2200); data(invalid, :) = []; % 4. 风向转为sin/cos,避免0/360跳变 wind_dir_rad = deg2rad(data.wind_dir); data.wind_dir_sin = sin(wind_dir_rad); data.wind_dir_cos = cos(wind_dir_rad); % 5. 构造特征矩阵 featVars = {'wind_speed','wind_dir_sin','wind_dir_cos','temp','power'}; Xraw = table2array(data(:, featVars)); Yraw = data.power; % 6. 归一化(z-score,按列) muX = mean(Xraw); sigX = std(Xraw); Xnorm = (Xraw - muX) ./ sigX; muY = mean(Yraw); sigY = std(Yraw); Ynorm = (Yraw - muY) / sigY; % 7. 构建滑动窗口样本 winSize = 12; [X, Y] = buildWindows(Xnorm, Ynorm, winSize); % 8. 按时间顺序切分训练/验证/测试 % 前70%训练,中间10%验证,最后20%测试 numSamples = size(X, 1); idxTrain = 1:floor(0.7*numSamples); idxVal = floor(0.7*numSamples)+1:floor(0.8*numSamples); idxTest = floor(0.8*numSamples)+1:numSamples; XTrain = X(:,:,idxTrain); YTrain = Y(idxTrain); XVal = X(:,:,idxVal); YVal = Y(idxVal); XTest = X(:,:,idxTest); YTest = Y(idxTest);这里的buildWindows函数就是滑动窗口切片的核心,逻辑很简单:从第winSize+1行开始,每次取前面winSize行作为输入,当前行的功率作为标签。有一点要注意,我切分数据时是按时间顺序切,不是随机打乱,这个顺序对于时序预测模型是必须的。
4.4 网络搭建代码:快速版和严格版
如果走trainNetwork路线,可以搭一个快速验证版(注意bilstm是BiLSTM,严格BiGRU需要自定义循环):
% build_network_lite.m numFeatures = size(XTrain, 2); lgraph = layerGraph(); tempLayers = [ sequenceInputLayer(numFeatures, 'Name', 'input') convolution1dLayer(3, 32, 'Padding', 'causal', 'DilationFactor', 1, 'Name', 'conv1') reluLayer('Name', 'relu1') convolution1dLayer(3, 32, 'Padding', 'causal', 'DilationFactor', 2, 'Name', 'conv2') reluLayer('Name', 'relu2') bilstmLayer(32, 'OutputMode', 'last', 'Name', 'bilstm') dropoutLayer(0.2, 'Name', 'dropout') fullyConnectedLayer(1, 'Name', 'fc') regressionLayer('Name', 'output')]; lgraph = layerGraph(tempLayers);这个版本里convolution1dLayer是二维卷积?不对,这里其实是深度学习工具箱里的一维卷积层,它支持DilationFactor参数,在时间维度上做因果卷积只要把Padding设为causal即可。输入层用sequenceInputLayer,所以XTrain要按[特征数, 序列长度, 样本数]的格式组织。
如果是严格的BiGRU,需要走自定义训练循环。核心思路是:用dlarray组织数据,自己写前向传播函数,用dlgradient求梯度,再调用adamupdate更新网络参数。代码模板如下:
% build_dlnet.m 结构示意 % 网络层: % conv1d -> relu -> conv1d(膨胀) -> relu % 两个GRU分支:正序GRU + 逆序GRU % concat -> fullyConnected -> 输出 % 训练循环: % for epoch = 1:maxEpochs % [loss, grad] = dlfeval(@modelLoss, net, dlX, dlY); % [net, avgLoss] = adamupdate(net, grad, avgLoss, iteration); % end严格版代码比快速版复杂,但灵活性也高很多,可以自由调整GRU层数和拼接方式。我建议第一次跑先用快速版把整个流程跑通,再去升级成严格版,不然调试难度叠加会把项目周期拖得很长。
4.5 训练配置与预测
MATLAB新版本里trainnet比trainNetwork更灵活,支持自定义损失函数。我常用的训练配置:
% train_model.m options = trainingOptions('adam', ... 'MaxEpochs', 80, ... 'InitialLearnRate', 1e-3, ... 'MiniBatchSize', 64, ... 'ValidationData', {XVal, YVal}, ... 'ValidationFrequency', 20, ... 'Plots', 'training-progress', ... 'OutputFcn', @(info) myEarlyStopping(info, 10));早停函数根据ValidationLoss判断,连续patience轮不下降就终止训练,能省不少时间。预测时用predict函数,然后反归一化:
% predict_model.m YPredNorm = predict(net, XTest); YPred = YPredNorm * sigY + muY; YTrue = YTest * sigY + muY;注意一个容易出错的地方:如果归一化是按特征单独做的,反归一化时只对功率那一列反算,不能把整个特征矩阵都反算一遍。我在这上面栽过跟头,预测出来的功率数量级完全不对,查了半天才发现是尺度算错了。
5. 实验设置与结果分析
5.1 评价指标:别被单一指标骗了
功率预测最常用的四个指标:
| 指标 | 公式 | 说明 |
|---|---|---|
| MAE | mean(abs(pred - true)) | 平均绝对误差 |
| RMSE | sqrt(mean((pred - true).^2)) | 对大误差更敏感 |
| MAPE | mean(abs(pred-true) / abs(true)) | 注意小功率点会放大 |
| R² | 1 - SS_res/SS_tot | 接近1效果越好 |
MAPE在功率接近0时的表现参考价值不大,风速低、功率趋近于0的样本多,MAPE会被拉得很大,单看MAPE会误判模型很差。我一般以RMSE和R²为主要参考,MAE做辅助。如果你要跟论文对比,尽量用同一套指标和同一段测试时段,否则数值没有可比性。
5.2 对比实验设计思路
为了验证TCN-BiGRU的有效性,我只推荐做三组硬对比:
- 单变量输入:只输入历史功率,用同样的TCN-BiGRU,看加了多变量输入到底有没有提升。
- 换模型:把BiGRU换成BiLSTM或者去掉TCN,用同样的特征,看结构组合增益。
- 换预测步长:单步vs滚动多步,衡量误差累积情况。
这种对照方式能帮你判断:效果提升到底是来自“模型结构”还是“输入特征”,在写后续研究报告时也有说服力。我见过很多项目只做一组模型就直接上线,结果出了问题分不清是特征的问题还是结构的问题,回头排查非常痛苦。
5.3 某次运行结果记录
我这边某次实验的记录如下(示例数据,读者复现时因随机种子不同会有浮动):
| 方案 | MAE(kW) | RMSE(kW) | R² |
|---|---|---|---|
| TCN单模型 | 9.2 | 13.8 | 0.97 |
| BiGRU单模型 | 8.1 | 12.5 | 0.97 |
| TCN-BiGRU | 6.5 | 10.2 | 0.98 |
| TCN-BiGRU,无历史功率输入 | 8.8 | 13.1 | 0.96 |
从这个结果能看出几点:加上历史功率输入后,预测误差显著下降,说明功率自相关很强,气象特征只能提供“边际信息”;TCN-BiGRU比两者单模型效果好,说明组合结构的互补性真实存在。在功率爬坡段,TCN-BiGRU的跟随效果明显好于单模型,这也是我为什么最终选择这个结构的原因。注意,绝对数值跟风电场装机容量有关,上面只是相对对比,不是通用指标。
5.4 绘图与可视化解读
建议至少画三张图:预测曲线和真实曲线对比、误差分布直方图、特征重要性热图。预测曲线重点看爬坡时段和功率低谷,误差直方图看是否有系统性偏差。把风速突变时段单独高亮,比较模型在“天气稳定”和“天气突变”两种场景下的误差,这样能直观看出多变量输入和组合模型的价值。
我在MATLAB里用plot和histogram就能画,不需要额外工具箱。画图的时候把RMSE和MAE直接标注在标题里,方便对比不同模型的图。保存图片时建议用exportgraphics导出高分辨率图,在论文或报告里用不会糊。
6. 常见问题与排查技巧实录
这个部分我整理成速查表,能省大家很多调试时间。
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
| Loss在训练早期就卡住 | 学习率太小或数据未归一化 | 检查特征尺度,取消异常值;把学习率调大到3e-3再看曲线 |
| Loss下降但验证集MAE反弹 | 过拟合 | 增大dropout、加早停、减小batch size |
| 预测曲线整体滞后 | 输入特征中没有历史功率,或感受野不够 | 加入历史功率输入;增大TCN膨胀深度或win_size |
| 预测值明显偏离量级 | 反归一化搞错 | 检查是否只对功率列反算;看保存的mu/sig是否一致 |
| 训练过程中内存不足 | batch size太大或输入序列太长 | 减小batch size,降低通道数,使用dlarray分batch |
| 训练耗时很长 | TCN卷积核太大/通道数太多 | 减少通道数,或先减小win_size验证逻辑 |
| 多次运行结果波动大 | 随机初始化不同 | 固定rng(如rng(42)),或多次运行取平均 |
| 输入风向直连导致误差增大 | 风向0/360跳变 | 改成sin/cos展开 |
6.1 关于“数据泄漏”的提醒
这是做时序预测最容易犯的错。很多朋友把数据随机打乱再划分训练集测试集,这在普通分类回归里没问题,但时序数据一旦乱序,等于拿未来的数据去预测过去,测试指标会虚高,完全不可信。正确做法是按时间顺序切分,前70%训练,中间10%验证,最后20%测试。滑动窗口构造样本时,也要保证训练和测试不重叠。
我自己早期踩过这个坑,当时测试R²做到0.99,换到真实场景直接崩,后来才意识到是顺序泄露。更隐蔽的一种泄露是:先对所有数据做归一化再切分,归一化的均值和方差是从整个序列算出来的,包含了测试集的信息。正确做法是先按时间切分,再分别计算训练集和测试集各自的均值和方差。当然对测试集用训练集的统计量也行,只要不混用。
6.2 关于随机种子与可复现性
MATLAB中rng影响随机数生成,训练前固定可以保证多次训练结果一致。但注意,如果使用GPU训练,并行计算的随机性还是会有细微波动,完全复现比较难。建议在论文或报告中固定种子并记录版本号。我一般固定rng(42),并在代码开头打印当前的MATLAB版本和工具箱版本,方便后续回溯。
6.3 关于训练集与测试集的统计分布差异
风电数据有季节特征,夏季风速低、冬季风速高。如果测试集只选某一个月,可能无法代表全年。最好让测试集覆盖至少一个完整的气象变化周期,比如从完整数据集里按时间顺序取最后20%,并尽量跨几个季节。这是实际工程项目中常被忽略的细节,但在功率预测里影响很大,一句话总结:测试集要能代表模型上线后的真实分布。
6.4 训练Loss曲线的判读方法
训练时Loss曲线通常有三种形态:持续下降然后平稳,说明模型在正常学习;断崖式下降后保持在某个平台,说明模型被异常样本拉偏了;一开始就波动很大,说明学习率太高或数据有问题。我习惯把训练Loss和验证Loss画在同一张图里,验证Loss不再下降就早停,验证Loss开始上升而训练Loss还在下降,就是过拟合信号,直接调大dropout。
7. 写在最后的个人经验
这套代码在我自己项目里跑过很多轮,最大的体会是:模型结构再先进,也顶不过数据质量差。清洗数据、按时间划分、做风向循环编码、归一化,这些占了我一半以上的工作量,但带来的收益比换网络结构大得多。建议第一次复现的朋友一定不要跳过第2章的数据预处理步骤,尤其是风向sin/cos编码和按时间顺序切分这两件事,直接影响最终效果。
另外,单步预测只是基础,后续可以往两个方向扩展。第一个方向是滚动多步预测:用预测出的功率作为下一时刻的输入特征,做多步外推,重点解决误差累积的问题。第二个方向是分时段建模:白天和夜间、大风期和低风期分开建模,或者直接把时刻编码(小时序号)加入特征,让模型学到日周期性。这两种扩展我都试过,分时段建模对短期峰值预测的提升尤其明显,代价是要小心训练数据不够的问题。
最后说个小技巧:如果你有NWP气象预报数据,但时间分辨率和SCADA不一致,可以先做时间对齐,再用滞后1小时的气象预报作为输入。这样模型在真实应用场景中才用得上预报数据,否则训练时用实测、上线时用预报,性能会差一大截。我见过不少项目最后落地效果不及预期,问题就出在这个训练/推理数据源不一致上,提前把这一点想清楚,能帮你少走很多弯路。
本文还有配套的精品资源,点击获取