电工杯 2025 A 范文:光伏电站发电功率日前预测(清洗 + 晴空指数 + 物理/相似日/混合三模型 + 区间)
一、摘要
针对 2025 年电工杯 A 题「光伏电站发电功率日前预测」,本文给出一套「数据清洗 → 晴空指数特征 → 物理/相似日/混合三模型 → 分天气误差评估 → 残差分位区间」的确定性建模范式。基于合成 20 MW 电站 240 天、96 点/天(15 min)数据(固定种子 SEED=20250501,晴空几何 + 云衰减物理链路生成,并对日前 NWP 辐照施加分天气噪声),完成三项核心工作:其一,清洗环节保留夜间零值、线性插值 87 个缺失点、识别并标记 86 个限电点(功率骤降至 60% 的正午平台特征);其二,构建 M1 物理基线(NWP 辐照→功率转换链)、M2 相似日加权(同天气类内按 NWP kt 曲线余弦相似度取 k=5 加权)、M3 混合修正(物理基线 × 相似日日能量比)三个模型;其三,在 40 个测试日上分天气评估。结果显示:M2 相似日法综合最优(平均 nRMSE=0.0327),多云天把 M1 的 0.0640 压到 0.0506——关键机制是相似日隐式吸收了组件积灰等未建模因素的系统性水平偏差(约 −9%),而纯物理链路因「不知道积灰」在三类天气全面落后(平均 0.0441);M3 在阴雨天最优(0.0264)且三类天气均不差,是无需同类样本时的稳健替代。不确定性方面,按残差 P5–P95 构建的 90% 区间实测覆盖率 90.2%–90.4%,平均宽度按晴 1.89 MW(占装机 9.4%)→ 多云 5.33 MW(26.7%)→ 阴雨 2.58 MW 递增,正确反映了「越难越宽」。全文纯标准库、确定性合成,正文、配图、附录与真源四路数字一致。
二、问题重述
光伏出力具有强天气依赖性,日前预测(D-1 提交未来 24 h 曲线)直接支撑电网调度与电力交易。赛题可归纳为五问:① 历史功率与气象面板如何清洗——哪些是缺失、哪些是夜间零值、哪些是限电假象?② 构造哪些特征能把「天文确定的太阳几何」与「随机变化的云」分离?③ 建立什么模型输出逐 15 分钟功率曲线,物理方法与数据方法各自的长处是什么?④ 误差指标应如何按天气类型拆分评估,避免整体均值掩盖阴雨天的高误差?⑤ 如何量化预测不确定性,给出调度可直接使用的预测区间?本文的主线是「把确定性与随机性分开处理」:太阳位置决定功率的上限包络(确定性),云与积灰决定实际出力对包络的偏离(随机性与系统偏移),三模型分别代表处理这两层的不同哲学。
三、模型假设与符号
- H1(确定性合成):官方数据未公开,采用晴空几何 + 云衰减链路合成 20 MW 电站数据(SEED=20250501),并显式植入一个物理基线未建模的因素——组件积灰衰减 (第 240 天累计约 −9.6%),用于检验各模型对「未知系统偏差」的吸收能力。
- H2(日前信息集):模型只允许使用 D-1 可获得的 NWP 版辐照/气温,NWP 对真实晴空指数的扰动幅度分天气设定(σ:晴 0.045 / 多云 0.13 / 阴雨 0.06),杜绝「用当天真值作弊」。
- H3(限电非天气):限电时段(功率骤降后维持平台)视为外生调度行为,从训练集中剔除,不计入预测误差。
- H4(同分布检验):测试期为连续末端 40 天,天气构成(晴 21/多云 13/阴雨 6)与全样本比例接近。
主要符号: 为一天内时刻(0–24 h,96 点); 为晴空 GHI; 为 NWP 晴空指数; 为温度折减; MW; 为相似日日能量比。
四、数据清洗与特征工程(问题 1–2)
4.1 清洗:三种「零」与一种「假」
清洗的关键是区分四种形态:夜间零值是天文事实,必须保留(它们定义了日曲线边界);短缺口缺失共 87 点,按前后邻点线性插值回填;限电时段共 86 点,特征是正午高功率段骤降至约 60% 后维持平台、与辐照走势脱钩,全部标记并剔除出训练集;异常毛刺在本合成集中未植入,但流程预留了 3σ 滑动窗口检测位。若把限电当真实出力训练,模型会学到「晴天中午只有六成功力」的错误物理。
4.2 晴空指数:把太阳与云分开
晴空 GHI 由太阳几何解析给出(赤纬角 + 时角,正午峰值约 1000–1100 W/m²)。定义 ,则 承载了全部天文确定性, 承载云的全部随机性——图 3 给出三类天气典型日的 NWP kt 剖面:晴天是 0.78–0.88 的平直带,多云是 0.2–0.9 的剧烈锯齿(云团过境),阴雨是 0.16–0.30 的低位平线。功率转换链为 ,其中电池温度 、,高温正午的温度折减可达 −8%。
五、日前预测三模型与对比(问题 3)
5.1 三个模型、三种哲学
M1 物理基线:把 NWP 辐照代入完整转换链(含削顶与温度折减),代表「机理透明」路线。M2 相似日加权:在同一天气类的历史日内,按 NWP kt 曲线的余弦相似度选 k=5 个最相似日,将其实际功率曲线逐点平均——它不需要知道任何物理公式,只需要「历史上长得像今天的日子实际发了多少电」。M3 混合修正:先算 M1,再用相似日的「日能量比」(截断于 [0.7, 1.3])做单标量水平修正,代表「物理定形状、数据定水平」的折中。
5.2 结果:谁赢、为什么赢
分天气 nRMSE(表 1、图 4):M2 综合最优(平均 0.0327),多云天把 M1 的 0.0640 压到 0.0506;M1 平均为 0.0441 且三类全垫底;M3 平均 0.0385,但在阴雨天以 0.0264 夺冠。
表 1 三模型 × 三天气误差(测试 40 日)
| 天气 | 指标 | M1 物理基线 | M2 相似日 | M3 混合修正 |
|---|---|---|---|---|
| 晴(21) | MAE/RMSE/nRMSE | 0.443/0.774/0.0387 | 0.222/0.386/0.0193 | 0.327/0.601/0.0300 |
| 多云(13) | MAE/RMSE/nRMSE | 0.669/1.280/0.0640 | 0.531/1.011/0.0506 | 0.614/1.183/0.0592 |
| 阴雨(6) | MAE/RMSE/nRMSE | 0.303/0.594/0.0297 | 0.301/0.565/0.0282 | 0.269/0.529/0.0264 |
M1 落后的根因在图 5 中一目了然:晴天正午 M1 曲线整体高于实际约 9%——这正是积灰衰减的贡献。物理链路本身没错,但它「不知道组件脏了」;M2 的相似日本身带着同样的积灰水平,偏差被隐式抵消。这印证了一个重要工程判断:纯物理模型的精度上限取决于物理链路的完整性,而现场总有链路之外的因素(污尘、衰减、逆变器效率漂移)。M3 的日能量比只能部分恢复水平(相似日的 同样被自身积灰稀释),故介于两者之间;但它在阴雨天的低水平扁平曲线上最稳——此时形状信息几乎无用而水平信息主导,标量修正恰好对症。
六、误差拆分与不确定性量化(问题 4–5)
6.1 为什么必须分天气看误差
若只报整体指标,多云天的高误差会被晴天的大量低误差点稀释——整体 nRMSE 约等于把「最难场景」藏进了平均数。拆分后可见:多云是唯一 nRMSE 突破 5% 的场景(M1 达 6.4%),其根源是 NWP 对云团的刻画误差(σ=0.13,约为晴天的三倍)经功率转换非线性放大。调度侧的含义很直接:多云日预留的备转容量不能按全天平均水平配置。
6.2 预测区间:越难越宽才合理
以主推模型逐点残差的 P5/P95 分位数构建 90% 区间(分天气估计),实测覆盖率为 晴 90.2%、多云 90.2%、阴雨 90.4%——三者都与名义置信度吻合,说明残差分位法没有系统性失准。更值得注意的是区间宽度(图 7):晴 1.89 MW(装机的 9.4%)、多云 5.33 MW(26.7%)、阴雨 2.58 MW(12.9%)。区间的宽窄本身就是一份「今日天气预报难度指数」:交易员看到 5 MW 宽的多云区间,就应自动降低该日的现货敞口、提高备用合同比例。
七、结论与建议(问题 5)
- 清洗规范:夜间零值保留、短缺口插值(87 点)、限电标记剔除(86 点)三步缺一不可,否则模型会把调度行为学成天气。
- 特征核心:晴空指数把太阳几何(确定)与云(随机)解耦,是日前场景下最有效的单一特征;NWP 误差随天气类型放大(多云 σ≈0.13),决定了各方法的精度天花板。
- 模型选择:相似日法 M2 综合最优(平均 nRMSE 0.0327,多云 0.0506),其本质是让历史同类日替我们消化未知系统偏差;物理基线 M1 受积灰等链路外因素拖累(平均 0.0441);混合修正 M3 在阴雨最优(0.0264)且全天候稳健,适合作为无充足相似样本时的兜底。
- 不确定性与建议:分天气 90% 区间实测覆盖率 90.2%–90.4%;多云日区间宽达装机 26.7%,交易与调度应按区间宽度动态调整备用。运维上建议建立组件定期清洗计划——本文中约 9% 的「看不见的损失」正是可以由物理链路纳入 soiling 项后收回的部分。
八、模型验证(四路一致)
三处交叉验证:① 用独立实现的太阳几何公式复核晴空 GHI 正午峰值(春分日约 1040 W/m²)与生成器一致;② 附录脚本独立重跑全链路,清洗计数(87/86)、三模型 × 三天气全部 9 组误差、区间覆盖率与宽度逐项吻合;③ 抽取多云典型日逐点核对 M2 预测与 5 个相似日实际功率均值的对应关系,最大偏差为浮点舍入量级。正文、配图、附录、真源四路数字一致。
参考文献
[1] 2025 年电工杯数学建模竞赛 A 题:光伏电站发电功率日前预测问题(赛题原文,官方数据未公开)。
[2] Lorenzo E. et al. PV Grid Connected Systems: Irradiance and Power Standardized Reporting[R]. IES, 1994.(晴空模型与 kt 定义)
[3] Pedregosa F. et al. Scikit-learn: Machine Learning in Python[J]. JMLR, 2011.(梯度提升类日前预测的代表工具链)
[4] Antonanzas J. et al. Review of photovoltaic power forecasting[J]. Solar Energy, 2016, 136: 78–111.
附录:核心 Python 实现(可独立运行复现上述数字)
import sys, os
_HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, os.path.abspath(os.path.join(_HERE, "..", "..", "..", "tools")))
import gen_dgcup2025a as G
D = G.gen_dgcup2025a()
print("SEED=%d 装机=%.0fMW 天数=%d(训%d+测%d) 每天%d点"
% (D["seed"], D["cap"], D["ndays"], D["train_n"], D["ntest"], D["kp"]))
print("清洗: 缺失插值%d点 限电标记%d点" % (D["n_missing"], D["n_curtail"]))
print("天气构成 全部:", D["weather_all"], " 测试:", D["weather_test"])
for w in ("晴", "多云", "阴雨"):
for k in ("m1", "m2", "m3"):
e = D["metrics"][w][k]
print(" [%s]%s: MAE=%.3f RMSE=%.3f nRMSE=%.4f"
% (w, k, e["mae"], e["rmse"], e["nrmse"]))
avg = {k: sum(D["metrics"][w][k]["nrmse"] for w in ("晴", "多云", "阴雨")) / 3
for k in ("m1", "m2", "m3")}
print("平均 nRMSE: M1=%.4f M2=%.4f M3=%.4f" % (avg["m1"], avg["m2"], avg["m3"]))
for w in ("晴", "多云", "阴雨"):
lo, hi = D["quant"][w]
print("区间[%s]: P5=%.3f P95=%.3f 覆盖率=%.3f 宽=%.3fMW"
% (w, lo, hi, D["cover"][w], D["width"][w]))