简介:这份资源是一篇发表于《现代电子技术》的学术论文PDF,面向电力系统、配电网运维及机器学习应用方向的研究人员、工程师与学生。内容围绕农村配电网末端低电压问题,提出基于BP神经网络的短期预测估算方法,系统梳理了温度、天气、时段、节假日等影响因素,并给出台区样本数据训练、预测建模及结果对比分析的完整技术路径,兼具理论推导与工程参考价值。资源为单份PDF文件,大小1.42MB,排版清晰、图表完整,可直接用于论文研读、算法复现或毕业设计参考。目前已有76人学习浏览,适合希望掌握BP神经网络在电力负荷与电压预测中实际落地方法的读者。通过该文档可深入理解低电压短期预测的特征选取思路、网络训练流程以及精度评估方式,同时了解机器学习在配电网治理中的应用切入点,有助于快速建立从数据到预测模型的整体认知。
1. 配电网末端电压偏低,靠得不是“看见”而是“预判”
做配网运检或电能质量分析的人都有这种经历:台区末端电压一到晚高峰就跌破 198V,等接到工单再赶过去,电压已经低了两三个小时。与其说这是个测量问题,不如说是个预测问题——你要在电压跌落发生之前给出估算,才能提前投切电容器、调主变分接头或者通知用户错峰。基于BP神经网络的低电压短期预测,做的就是这件事:用过去几天的电压、负荷、温度这些序列,估算未来 1 到 24 小时的电压曲线,标出哪些时段大概率跌出国标下限。它不需要台区装设复杂的量测终端,用营销系统里现成的电压监测数据和负荷数据就能训练,落地成本比装一整套在线分析系统低得多。适合的读者是配网自动化、电力营销、综合能源服务里做电压质量分析的人,也适合刚接触电力数据挖掘、想用神经网络处理时间序列预测的工程师。
2. BP神经网络结构图和拟合曲线:先搞清楚它到底在拟合什么
2.1 电压预测里的“拟合”不是拟合历史曲线
很多人在 BP 神经网络拟合曲线上有个误解,以为网络是在把历史电压曲线画圆滑、补上缺失点。真正做的不是这件事。BP 网络拟合的是“输入特征向量”到“未来电压值”之间的映射关系。输入是过去一段时间窗口里的电压、负荷、温度,输出是下一时刻或者未来几个时刻的电压估算值。训练过程调整的是神经元之间的连接权值,目标是让预测值与实测值的均方误差最小。
所以看拟合曲线时,重点不是看训练集上曲线贴得多紧,而是看验证集和测试集上的预测曲线与真实电压曲线的趋势是否一致、峰值时刻是否对准、低谷深度是否接近。训练集拟合得再好都说明不了问题,那是网络把训练样本背下来了。
2.2 网络结构怎么对应电压预测的物理含义
BP 神经网络结构图在低压预测场景下,典型配置是三层:输入层、单隐含层、输出层。
输入层的神经元个数对应特征向量长度。比如你用“当前时刻前 3 个点的电压 + 前 1 个点的负荷 + 温度”做输入,输入层就是 5 个节点。输入特征的选择直接决定了预测上限,网络结构只是在逼近这个上限。隐含层神经元的数量决定网络对非线性关系的表达能力。电压跌落和负荷增长之间的关系不是线性的,导线阻抗上的压降与电流成正比,但变压器损耗、无功补偿投切都引入非线性,所以隐含层必须有足够的神经元去逼近这个非线性映射。
输出层节点数取决于预测步长。只预测下一个时刻的电压,输出层就是 1 个节点;要预测未来 4 个 15 分钟点的电压,输出层就是 4 个节点。多步输出比单步滚动预测误差更小,因为单步滚动会把每一步的预测误差累积到下一步输入里。
2.3 隐含层节点数:最不值得纠结的问题
隐含层节点数是最常被问的问题。行业里流传的经验公式不少,比如sqrt(输入节点数×输出节点数)+1~10,或者输入节点数×2+1,这些公式只能给个起点。对电压预测这类输入维度不高、样本量几万条的任务,我一般从 10 个节点开始试,逐一加到 20,比较验证集上的均方根误差,取误差最小的那个。
节点数太少,网络欠拟合,拟合曲线在电压低谷处明显偏高;节点太多,训练集表现极好但验证集误差大,典型的过拟合。判断方法很简单:训练误差持续下降而验证误差开始上升的那个点,就是网络容量到头了。
2.4 激活函数对电压幅值预测的约束
BP 网络三种激活函数在电压预测里的分工要分清。输入层到隐含层用双曲正切函数tansig,输出范围在 -1 到 1 之间,需要把输入数据归一化到同样范围。隐含层到输出层用线性函数purelin,因为电压输出是连续的物理量,没有上下界约束,如果用logsig反而会把输出压到 0 到 1 之间,还得做一次放大,放大后误差也跟着放大。
提示:如果网络输出层用了非线性激活函数,反归一化后电压幅值在两端的误差往往偏大,这是激活函数非线性压缩导致的固有偏差。电压预测直接输出连续值,输出层必须选
purelin。
3. 训练数据的滑窗构造与归一化:预测准不准七成看这里
3.1 数据来源与对齐是第一个坑
做低电压预测,最容易踩的坑不是网络结构,而是数据没对齐。电压监测数据、负荷数据、温度数据往往来自三个不同系统:电压监测仪按 15 分钟一个点上报,负荷采集系统按整点冻结,气象数据按小时更新。时间戳对不上,特征和标签之间就出现错位,网络学到的映射关系是乱的。
我一般先把所有序列重采样到同一时间粒度。电压和负荷按 15 分钟对齐,温度按整点对齐后向前填充到 15 分钟粒度。数据清洗时先处理电压中的零值、跳变点和通信中断造成的空值。电压变成 0 基本是监测终端断电,不能用 0 参与训练,否则网络会把“电压为 0”学成正常模式。处理办法是线性插值或者用前一天同时刻的值替换。
% 数据对齐示例:电压15分钟一个点,负荷15分钟一个点,温度整点向前填充 data = synchronize(voltageTable, loadTable, 'union', 'linear'); temperatureFill = retime(temperatureTable, data.Time, 'previous'); data.Temperature = temperatureFill.Temperature;这段代码用synchronize把电压和负荷表对齐到公共时间轴,retime把温度按前向填充对齐到 15 分钟粒度。注意union选项会保留两边所有时间点,线性插值会填充中间的 NaN,温度用previous前向填充是为了避免在整点之间引入虚假的温度渐变。
3.2 滑窗法构造样本:输入特征和标签
监督学习需要成对的“输入特征 → 标签”样本。对时间序列,标准做法是滑窗。假设预测目标是“用当前时刻及前 3 个点的电压、当前负荷、当前温度,预测下一个 15 分钟点的电压”,那么窗口长度为 4,滑窗步长为 1。
样本构造时有一个细节容易被忽略:预测目标的超前时间。低电压短期预测里,“短期”通常指未来 1 到 24 小时。如果只做下一个点的预测,留给调控动作的时间可能不够,因为从预测结果到人工干预最少也需要 30 分钟到 1 小时。所以实际项目中我会在标签上做偏移,用 t 时刻的数据预测 t+4 时刻的电压,即超前 1 小时,给操作留出时间。
function [X, Y] = buildSlidingWindow(data, inputSteps, horizon) n = length(data.Voltage); numSamples = n - inputSteps - horizon + 1; X = zeros(numSamples, inputSteps + 2); % 电压窗口 + 负荷 + 温度 Y = zeros(numSamples, 1); for i = 1:numSamples X(i, 1:inputSteps) = data.Voltage(i:i+inputSteps-1)'; X(i, inputSteps+1) = data.Load(i+inputSteps-1); X(i, inputSteps+2) = data.Temperature(i+inputSteps-1); Y(i) = data.Voltage(i+inputSteps-1+horizon); end end特征矩阵的每一行对应一个预测点,前 4 列是电压历史窗口,第 5 列是负荷,第 6 列是温度。标签是当前窗口之后第horizon个点的电压值。这里horizon = 4表示提前 4 个 15 分钟点,即 1 小时。
3.3 归一化的正确做法:训练集和测试集共用一组参数
归一化这个步骤看似简单,翻车率却极高。最常见的错误是对全部数据做一次mapminmax,然后再划分训练集和测试集。这会引入数据泄漏:测试集的统计信息已经进入了训练过程,验证结果看起来很好,但上线后真实预测误差翻倍。
正确做法是先划分训练集和测试集,只对训练集计算归一化的最小值和最大值,测试集用同一组参数做变换。matlab 里mapminmax返回归一化参数ps,把ps保存下来给测试集用。
[X_train, X_test, Y_train, Y_test] = splitData(X, Y, 0.8); % 只拟合训练集的归一化参数 [X_norm, ps_X] = mapminmax(X_train', 0, 1); [Y_norm, ps_Y] = mapminmax(Y_train', 0, 1); % 测试集复用训练集的参数,不允许重新计算 X_test_norm = mapminmax('apply', X_test', ps_X); Y_test_norm = mapminmax('apply', Y_test', ps_Y);mapminmax第二、三个参数 0 和 1 把数据映射到 [0,1] 区间。apply模式用已有的ps_X对测试集做同样变换。注意mapminmax默认按行处理,所以输入要转置。
提示:归一化范围选 [0,1] 还是 [-1,1] 对最终效果影响不大,关键是隐含层激活函数用
tansig时,输入范围必须包含负数区间,此时应映射到 [-1,1] 更合适。
4. 用 matlab 搭建和训练 BP 网络:从网络生成到拟合曲线判读
4.1 建网和训练:trainlm 适合小样本,trainbr 防过拟合
matlab 的深度学习工具箱提供了feedforwardnet函数来创建前馈 BP 网络,取代了早期版本里的newff。创建网络时只需要指定隐含层节点数和训练函数。
训练函数的选择有讲究。trainlm(Levenberg-Marquardt)收敛快、精度高,适合样本量在几万以内的场景,但内存占用大、容易过拟合。trainbr(贝叶斯正则化)在训练过程中自动调整正则化强度,抗过拟合能力强,适合数据噪声大的电压预测场景。电压监测数据本身有测量误差,我一般优先用trainbr,只有当训练时间过长时才换回trainlm。
net = feedforwardnet(15, 'trainbr'); net.trainParam.epochs = 1000; net.trainParam.goal = 1e-5; net.trainParam.min_grad = 1e-8; net = train(net, X_norm, Y_norm); % 预测并反归一化 Y_pred_norm = net(X_test_norm); Y_pred = mapminmax('reverse', Y_pred_norm, ps_Y);feedforwardnet(15, 'trainbr')创建只含一个隐含层、隐含层 15 个神经元、训练函数为贝叶斯正则化的网络。train函数会根据输入维度自动确定输入层和输出层节点数。迭代次数上限设为 1000,但trainbr通常会在几百轮内触发早停。min_grad设小一些,避免梯度下降提前停滞导致欠拟合。
4.2 回归图与拟合曲线的判读:R² 不是唯一指标
训练完成后,matlab 会弹出三个图:性能曲线、训练状态、回归图。其中回归图最值得细看,它把网络输出和真实目标绘制成散点图,同时给出拟合直线和 R 值。
R 值在 0.95 以上说明整体相关性强,但注意 R 值对系统性偏差不敏感。设想一种情况:网络把所有预测值都比真实值高 5V,只要趋势一致,R 值仍然很高。所以回归图之外一定要画预测电压和真实电压的时序对比曲线,重点看三个位置:低谷时刻的幅值误差、高峰时刻的相位偏移、整体均值偏差。
timeVector = testTime(1:length(Y_test)); plot(timeVector, Y_test, 'b-', 'LineWidth', 1); hold on; plot(timeVector, Y_pred, 'r--', 'LineWidth', 1); legend('实测电压', 'BP预测电压'); ylabel('电压/V'); xlabel('时间');4.3 误差指标:MAPE 之外必须看 RMSE 和最大偏差
电压预测的误差评估不能只看平均绝对百分比误差。电压的正常范围是 198V 到 235V,数值本身不大,MAPE 的分母接近 220,算出来的百分比天然偏小,容易掩盖真实问题。我一般同时看三个指标。
| 指标 | 计算公式 | 对电压预测的意义 |
|---|---|---|
| RMSE | sqrt(mean((y_true - y_pred).^2)) | 反映整体误差量级,适合对比不同模型 |
| R² | 1 - SS_res/SS_tot | 反映模型对电压波动方差的解释能力 |
| MaxAbsErr | max(abs(y_true - y_pred)) | 反映最坏情况下的预测偏差,低电压预警尤其关注 |
rmse_val = sqrt(mean((Y_test - Y_pred).^2)); r2_val = 1 - sum((Y_test - Y_pred).^2) / sum((Y_test - mean(Y_test)).^2); max_err = max(abs(Y_test - Y_pred)); fprintf('RMSE = %.2f V, R² = %.4f, MaxAbsErr = %.2f V\n', ... rmse_val, r2_val, max_err);RMSE 在 2V 以内说明网络对电压波动拟合得较好,可以用于低电压预警。RMSE 超过 5V 时预测曲线基本跟着均值走,对低谷幅度的估计没有参考价值。最大绝对误差如果频繁出现在傍晚负荷爬升时段,说明输入特征里缺少对负荷快速变化的表达,可以在特征中加入负荷差分项。
4.4 训练集误差低、测试集误差高的排查顺序
如果训练集 R² 达到 0.99 而测试集 R² 掉到 0.7 以下,按以下顺序排查,而不是急着调网络结构。
第一查数据泄漏。检查归一化是不是用了全量数据计算参数,检查滑窗是否把同一时间段的样本同时放进了训练集和测试集。时间序列划分必须按时间顺序切分,不能随机打乱,否则训练集里混入未来数据。
第二查特征与标签的相关性。用corrcoef计算输入特征与电压标签的相关系数,如果负荷和电压的相关系数绝对值很低,说明数据对齐出了问题。
第三才是调网络。训练集和测试集的数据分布本身就不一样时,再调隐含层节点数也救不回来。
5. 短时预测的滞后效应与滚动校准
5.1 为什么预测曲线总比实测曲线“慢半拍”
单步 BP 电压预测最常见的现象是预测曲线整体滞后于实测曲线,电压跌落的预测比实际发生晚了一到两个采样点。原因是网络在训练时只优化了幅值误差,没有显式建模变化趋势。当电压开始快速下跌时,输入窗口内看到的还是下跌前的电压值,网络给出的预测自然偏高。
缓解滞后有两个办法。特征里加入电压一阶差分,让网络显式看到变化方向;或者把预测目标从绝对电压改为电压变化量,让网络学习增量而不是总量。第二种方法尤其有效,因为电压在短时间内变化范围有限,预测增量比预测绝对值的方差更小。实现时可以这样改滑窗标签:
Y(i) = data.Voltage(i+inputSteps-1+horizon) - data.Voltage(i+inputSteps-1);训练完成后实际预测值需要把窗口最后一个电压加上增量。这样网络的输出目标变成了“未来电压相对当前的变化量”,网络更容易捕捉到下跌的趋势。
5.2 用滚动预测做未来 2 到 4 小时的电压估算
低压短期预测的实际应用不是只预测下一个点,而是要给出未来几小时的电压曲线,才能判断哪些时段有低电压风险。做法是滚动预测:先用历史数据预测 t+1 时刻,然后把预测值拼接到历史序列尾部,继续预测 t+2,循环下去。
horizonSteps = 8; % 预测未来 2 小时(8个15分钟点) predBuffer = X_test_norm(1, :); futurePred = zeros(horizonSteps, 1); for i = 1:horizonSteps y_next = net(predBuffer'); futurePred(i) = y_next; % 窗口前移:丢弃最早一个点,接入刚预测的点 predBuffer(1:end-1) = predBuffer(2:end); predBuffer(end) = y_next; end注意滑动窗口里包含负荷和温度字段,滚动预测时这些值需要替换成对应时间的真实数据,如果未来时刻的负荷数据未知,可以用同期历史均值代替再重新生成预测。
5.3 模型校准:每天用新数据微调比定期重训更稳
BP 网络的参数在训练完成后是冻结的,但配电网负荷特性会随季节变化,冬季取暖负荷和夏季空调负荷对应的电压跌落模式完全不同。一套冬季训练的网络用到夏季,预测偏差会越来越大。
常见做法是每周重训一次模型,或者每天追加当天数据做增量微调。matlab 里用adapt函数对已训练网络进行在线自适应,也可以用train在原有网络参数基础上继续训练。继续训练时学习率要调小,否则新数据会冲刷掉已经学到的历史模式。
net.trainParam.lr = 0.001; % 微调时降低学习率 net = train(net, X_new_norm, Y_new_norm);实际操作中我建议保留一个滑动窗口的数据集,只保留最近 30 天的数据参与微调,让模型逐步遗忘过时的负荷模式。判断模型是否需要更新的指标是滚动预测的 RMSE 持续超过 3V,连续三天触发这个阈值就启动重训。
5.4 低电压预警的判定:连续多点低于阈值才报警
神经网络预测值本身有误差,单点预测值略低于 198V 不一定代表真实电压就会跌破国标下限。实用的判据是连续两个以上预测点低于阈值才触发预警,同时叠加一个裕度——预测值低于 200V 就提前关注,低于 198V 才告警。这个裕度值可以根据模型在测试集上的最大绝对误差来确定,模型最大误差是 3V,预警阈值就设在 201V,保证真实电压跌破 198V 之前有机会发出警报。
本文还有配套的精品资源,点击获取