Skip to main content

Command Palette

Search for a command to run...

Integrated PV-Storage-Load Forecasting: Empowering EMS with Predictive Intelligence

Updated
4 min read

光伏-储能-负荷联合预测:给 EMS 装上"预知能力"

本文结合我正在维护的一套工业储能管理系统的真实工程实践,聊聊如何把预测能力嵌入 EMS 决策链路。代码片段均来自项目实际文件,不是伪代码。


一、为什么 EMS 需要预测?

我在调试这套系统的 MQTT 指令链路时,发现一个有意思的现象:EMS 的充放电决策完全依赖当前时刻的 SOC 和预设的时段计划表。翻开 ems_management.c,核心逻辑大概是这样的:

BOOL IsBatt_Plan2_StartChrg(...) {
    if (pEMS->nTMSector < 0) return FALSE;
    if (pPlanSectorNow->emBatt_WorkMode != BATT_WORKMODE_FIRST_CHRGING) return FALSE;
    if (nBattSOC >= pPlanSectorNow->nStopSOC) return FALSE;
    return TRUE;
}

逻辑很清晰:查当前时段(nTMSector),对比工作模式(emBatt_WorkMode)和停止 SOC 阈值(nStopSOC),决定充还是不充。

这套逻辑在电价稳定、负荷规律的场景下跑得很好。但现实是:光伏出力受云层影响可以在几分钟内从满功率跌到零;工厂负荷在节假日和工作日差异巨大;电网侧的峰谷价差窗口也在动态变化。

纯规则驱动的 EMS 本质上是在用昨天的地图走今天的路。

预测的价值在于:把"当前状态 → 决策"的单步反应,升级为"未来状态预估 → 提前布局"的前瞻控制。这就是 MPC(模型预测控制)的核心思想,后面会详细展开。


二、数据基础:我们手里有什么原料?

预测模型不是凭空建的,得先搞清楚系统里有哪些可用的数据。

2.1 光伏逆变器采样数据

项目里的 PV 采样模块(_inverter_sampler/)支持 Growatt、华为、固德威、阳光电源等主流逆变器品牌,通过 RS485 轮询采集。核心数据结构 PV_INVERTER_DATA(定义在 blob_model.h:4539)包含:

typedef struct {
    float fOutputActivePower;      // AC 侧输出有功功率 (W)
    float fPVInputTotalPower;      // DC 侧总输入功率 (W)
    float fPVGroupVolt[MAX_PV_NUM]; // 各组串电压 (V)
    float fPVGroupCurr[MAX_PV_NUM * 2]; // 各组串电流 (A)
    float fDailyPowerGeneration;   // 当日发电量 (kWh)
    float fTotalPowerGeneration;   // 累计发电量 (kWh)
    int   iActivePowerRate;        // 有功功率限制百分比
    int   iWorkMode;               // 0=未安装 1=等待 2=运行 3=故障
} PV_INVERTER_DATA;

汇总层面还有 A_BLOB_PV_INVERTER_DATA_TOTAL,字段 fTotalPVOutputActPower 给出全站光伏总出力(kW),这是预测模型的直接训练标签。

对预测有用的特征fPVGroupVolt(组串电压反映辐照度变化)、iWorkMode(故障状态需要剔除异常样本)、fDailyPowerGeneration(日累计量用于校准预测偏差)。

2.2 DLT645 负荷计量数据

负荷侧通过 DLT645 协议采集电表数据(dlt645_kWmeter.c)。协议帧结构是标准的 0x68 + 地址域 + 0x68 + 控制码 + 数据域 + CS + 0x16,采集的量包括:

  • 三相电压、电流、有功功率、无功功率

  • 正向/反向累计电量(WH_FRAME_TYPE_GET_TOTALWH / WH_FRAME_TYPE_GET_RVSTATALWH

  • 最大需量(WH_FRAME_TYPE_GET_PMAXDEMAND)——这个字段对需量控制预测特别有价值

数值解码用 BCD 转换:

float ConvertBCD_2WhVal(BYTE *pData, int nLen, int nDecimalPos) {
    // BCD 编码 → 浮点,nDecimalPos 控制小数点位置
}

实际运行中,fGridMeter_Power[1](实时电网功率,kW)和 fCabMeter_Power[1](柜内功率)是负荷预测的核心输入,采样周期通常是 1 分钟。

2.3 储能电池状态

电池 SOC 存在 nSOC(千分位,0-1000 对应 0-100%),充放电能量分别记录在 fCalc_ChargedEnergyfCalc_DisChargedEnergy。这些数据在预测框架里扮演"状态变量"角色——预测模型的输出要结合当前 SOC 才能转化为可执行的充放电指令。


三、光伏发电功率预测

3.1 NWP + 历史数据融合

光伏功率预测的难点在于它强依赖气象条件,而气象本质上是混沌系统。工程上通行的做法是两路信号融合:

NWP(数值天气预报)路:从气象局或商业 API 获取未来 24-72 小时的辐照度(GHI/DNI/DHI)、云量、温度预报。辐照度是光伏出力的物理驱动量,理论上 \(P_{pv} = \eta \cdot A \cdot G\)(\(\eta\) 为效率,$A$ 为面积,$G$ 为辐照度),但实际逆变器效率随温度、老化程度变化,所以 NWP 只能给出粗粒度的趋势。

历史数据路:用过去 30-90 天的 fTotalPVOutputActPower 时序数据,学习"同类天气下的实际出力曲线"。关键是天气类型分类——晴天、多云、阴天、雨天的出力曲线形态差异极大,需要先做天气聚类再分类建模。

融合方式:NWP 预报作为外生变量(exogenous variable)输入模型,历史序列提供自回归特征。

3.2 模型选型:为什么不用 LSTM?

很多人第一反应是 LSTM,但在工业场景里我更倾向于 N-BEATSPatchTST,原因如下:

N-BEATS(Neural Basis Expansion Analysis for Time Series)的核心思想是把时序分解为趋势项和季节项的叠加,每个 block 学习残差。对光伏这种有强日周期性的序列,这种归纳偏置(inductive bias)非常合适。而且 N-BEATS 是纯 MLP 结构,没有循环依赖,训练速度快,部署到嵌入式 Linux 上的推理开销也小。

PatchTST 把时序切成 patch(类似 ViT 对图像的处理),用 Transformer 的自注意力捕捉长程依赖。对于需要融合 NWP 多变量输入的场景,Transformer 的多头注意力天然适合处理异构特征。

Informer 用稀疏注意力(ProbSparse Attention)把复杂度从 \(O(L^2)\) 降到 \(O(L \log L)\),适合预测窗口很长(比如 72 小时)的场景。

对于本项目这种 15 分钟粒度、预测 24 小时的需求,我会优先试 PatchTST,patch size 设为 16(对应 4 小时历史窗口),预测长度 96 个点。

3.3 不确定性量化:分位数回归

点预测给出的是期望值,但 EMS 决策需要知道"最坏情况下光伏出力是多少"。这就是概率预测的价值。

分位数回归(Quantile Regression)的损失函数:

$$\mathcal{L}_q(\hat{y}, y) = q \cdot \max(y - \hat{y}, 0) + (1-q) \cdot \max(\hat{y} - y, 0)$$

同时预测 \(q = [0.1, 0.5, 0.9]\) 三个分位数,就得到了预测区间。EMS 在做保守决策时用 P10(下界),做激进决策时参考 P90(上界)。

实现上,只需要把模型最后一层的输出维度从 1 改为 3,损失函数换成三个分位数损失的加权和,其余架构不变。


四、负荷预测:挖掘工业负荷的周期性规律

4.1 工业负荷的三层周期结构

工业负荷不像居民负荷那样平滑,它有很强的生产节律:

  • 日内周期:班次切换(早班/中班/夜班)导致功率阶跃,fGridMeter_Power 的时序上会看到明显的台阶状跳变

  • 周周期:工作日 vs 周末,某些工厂周末停产,负荷降到基础维持水平(空调、照明、待机)

  • 节假日模式:春节、国庆等长假期间负荷曲线完全异于平日,需要单独建模

从 DLT645 采集的历史数据里,可以用 STL 分解(Seasonal-Trend decomposition using LOESS)把这三层周期显式分离出来,再分别建模。

4.2 特征工程

除了历史负荷序列本身,以下特征对工业负荷预测有显著提升:

特征 来源 说明
星期几(one-hot) 系统时钟 捕捉周周期
是否节假日 日历 API 节假日模式切换
时段索引(0-47) nTMSector 对应 EMS 的 30 分钟时段划分
最大需量 WH_FRAME_TYPE_GET_PMAXDEMAND 反映生产强度
滞后特征(lag-24h, lag-168h) 历史数据 昨天同时刻、上周同时刻
滚动均值(rolling mean 1h/4h) 历史数据 平滑短期波动

nTMSector 这个字段在 EMS 代码里本来是用来查时段计划表的,但它同时也是一个天然的时间特征——把它直接 embedding 进模型,比用原始时间戳效果好。

4.3 多变量时序预测

负荷预测不是孤立的,光伏出力、电池 SOC、历史电价都会影响实际负荷(比如高电价时段工厂会主动降负荷)。把这些变量一起输入 Informer 或 PatchTST,做多变量 → 单变量(或多变量 → 多变量)预测,通常比纯单变量模型提升 10-20% 的 MAE。


五、预测结果注入 EMS:MPC 框架

这是整个方案最关键的一环,也是最容易被忽视的一环。很多项目做完预测就停了,预测结果没有真正改变决策逻辑。

5.1 现有 EMS 决策的局限

回到 ems_management.c 里的逻辑:IsBatt_Plan2_StartChrg()IsBatt_Plan2_StopDischarge() 都是单步决策,只看当前时刻的 SOC 和时段配置。这意味着:

  • 如果预测到下午 2 点光伏会大发,现在(上午 10 点)就应该少充一点,留出空间吸纳光伏;但现有逻辑不知道这件事,会按计划表继续充到 nStopSOC

  • 如果预测到晚上 8 点有一个负荷高峰,现在就应该开始储能,但现有逻辑要等到那个时段才触发。

5.2 MPC 的基本框架

MPC(Model Predictive Control,模型预测控制)的思路是:在每个控制周期,用预测模型生成未来 $N$ 步的状态预估,然后求解一个优化问题,得到未来 $N$ 步的最优控制序列,只执行第一步,下一个周期滚动重复。

优化目标(以经济性为例):

$$\min_{u_t, ..., u_{t+N}} \sum_{k=0}^{N-1} \left[ c_k^{buy} \cdot P_{grid,k}^+ - c_k^{sell} \cdot P_{grid,k}^- + \lambda \cdot \Delta u_k^2 \right]$$

其中 \(c_k^{buy/sell}\) 是预测的电价,\(P_{grid}^+\) 是购电功率,\(P_{grid}^-\) 是售电功率,\(\lambda \cdot \Delta u_k^2\) 是控制平滑项(避免频繁切换充放电)。

约束条件

$$SOC_{min} \leq SOC_k \leq SOC_{max}$$ $$P_{batt,min} \leq P_{batt,k} \leq P_{batt,max}$$ $$SOC_{k+1} = SOC_k + \frac{\eta_{chg} \cdot P_{batt,k}^+ - P_{batt,k}^- / \eta_{dis}}{E_{cap}} \cdot \Delta t$$

功率平衡约束:

$$P_{pv,k} + P_{batt,k} + P_{grid,k} = P_{load,k}$$

这里 \(P_{pv,k}\) 和 \(P_{load,k}\) 就是预测模型的输出。

5.3 与现有代码的接口设计

要把 MPC 嵌入现有系统,最小侵入的方式是:不改变底层执行逻辑,只替换决策层的参数生成

现有系统通过 MQTT 下发 cmd/set/emu/powerCmd 来控制充放电模式,通过 cmd/set/emu/dispatchPower 下发调度计划。MPC 优化器可以作为一个独立进程运行,每 15 分钟执行一次:

  1. 从数据库读取最新的 fTotalPVOutputActPowerfGridMeter_PowernSOC

  2. 调用预测模型,生成未来 24 小时的 \(\hat{P}{pv}\) 和 \(\hat{P}{load}\)

  3. 求解 MPC 优化问题(用 scipy.optimizecvxpy

  4. 把优化结果转换为 dispatchPower 的 JSON 格式,通过 MQTT 下发

注意 EMU_dispatchPower 函数(GH_DigitalEnergy_Pub.c:2582)里有时间戳校验:

// GH_DigitalEnergy_Pub.c:2631
if(ABS(Now_time - Ts_val->valueint) > 15) {
    pMqtt->bDisPower = TRUE;
    return -1;
}

MPC 优化器下发指令时,时间戳字段必须用设备当前时间(误差 ≤15 秒),这是一个容易踩的坑。

5.4 不确定性在 MPC 中的处理

前面提到分位数预测给出了 P10/P50/P90 三条曲线。在 MPC 里,可以用鲁棒 MPC 的思路:

  • 光伏预测用 P10(保守估计),避免因高估光伏出力导致过度放电

  • 负荷预测用 P90(保守估计),确保高负荷场景下有足够储能余量

  • 在约束里加入 SOC 缓冲带(比如 SOC 下限从 10% 提高到 15%),为预测误差留出安全裕度

这种处理方式不需要复杂的随机优化,计算开销小,适合嵌入式 Linux 环境。


六、工程落地的几个实际问题

6.1 数据质量

DLT645 采集偶尔会有通信超时,ConvertBCD_2WhVal 返回异常值。训练数据里需要做异常检测(3σ 准则或 IQR 过滤),否则一个坏点会严重影响模型。

光伏逆变器的 iWorkMode == 3(故障)期间的数据要标记并剔除,不能用来训练"正常发电"的模式。

6.2 模型更新频率

光伏组件会随时间老化(年衰减约 0.5-0.8%),负荷模式会随生产计划变化。模型不能训练一次就永久使用,建议每月用最新 90 天数据重新微调(fine-tune),而不是从头训练。

6.3 预测失效时的降级策略

预测模型是软件,会出 bug,NWP 数据源也可能断线。系统必须有降级逻辑:当预测模块不可用时,自动回退到现有的规则驱动模式(IsBatt_Plan2_StartChrg 那套逻辑)。这个降级切换可以通过 emControlMode 字段来实现——预测驱动模式和规则模式对应不同的控制模式枚举值。

6.4 计算资源约束

项目运行在 ARM 嵌入式 Linux 上(从 src/mkenv_arm_st 可以看出是 ARM 交叉编译环境)。深度学习模型推理需要考虑资源限制:

  • N-BEATS 的 MLP 结构可以用 ONNX Runtime 部署,推理一次 24 小时预测在 ARM Cortex-A 上通常在 100ms 以内

  • MPC 优化问题如果是线性规划(LP),用 glpkHiGHS 求解,几十个变量的问题毫秒级可解

  • 如果资源实在紧张,可以把预测和优化放到云端,设备只负责执行,通过 MQTT 接收优化后的调度计划


七、小结

从"当前 SOC + 时段表 → 充放电决策"到"未来 24 小时预测 + MPC 优化 → 前瞻调度",这不是一个简单的模型替换,而是整个决策架构的升级。

核心链路是:原始采样数据(PV 逆变器 + DLT645 电表)→ 特征工程 → 时序预测模型(PatchTST/N-BEATS)→ 概率预测区间 → MPC 优化求解 → MQTT 指令下发 → 设备执行

每个环节都有工程细节需要处理,但最重要的是把预测结果真正接入决策闭环,而不是让它停留在离线分析报告里。现有代码里的 dispatchPower 接口已经提供了足够的控制自由度,缺的只是上游的预测驱动层。

这套方案在理论上可以把储能系统的经济收益提升 15-30%(相比纯规则调度),具体数字取决于当地电价结构和光伏/负荷的波动程度。值得投入工程资源去做。


代码引用均来自项目实际文件,文中行号以当前代码版本为准。

More from this blog

电力需求响应——SEMS/REMS层级架构下的多站协调控制

作者:储能系统固件开发工程师日期:2026-04-14项目背景:工商业储能管理系统(BESS),支持川崎项目多站联合需求响应,SEMS为站级本地EMS,REMS为上级远程EMS 一、为什么需要两级EMS? 最初,项目只有一个站级EMS(站级能量管理系统,SEMS)。SEMS负责控制本站的PCS充放电,执行时段计划、防逆流、防过载,运行得还算平稳。 然而,当客户在川崎项目提出"多个储能站联合响应

Apr 14, 20267 min read

BMS SOC显示平滑算法:让百分比变化符合用户直觉

作者:悦悦 | 平台:S32K146 + FreeRTOS | 源文件:SocDisplay.c 前言 在储能BMS系统里,SOC(State of Charge,荷电状态)是用户最直接感知的核心指标。从EMS大屏到HMI触摸屏,SOC百分比就是电池的"油表"。 然而,算法层计算出来的SOC是一个不断跳变的原始值。把它直接推给显示层,用户看到的将是一个毫无规律、时快时慢、甚至会"倒退"的数字—

Apr 11, 20267 min read

EMS储能工程师的职业发展分析

一、你现在真实的竞争力画像 先说实话,让你有清醒认知。 从你的工程代码来看,你具备的能力是: 你最大的护城河不是C语言,而是"懂储能业务的嵌入式工程师"这个组合。 这个组合的人,全中国不超过几千人。 二、五大问题的系统回答 问题1:深度 vs 全栈,如何提升不可替代性? 核心判断:你不应该二选一,而是走"T型 + 业务锚点"路线。 什么是你的T型结构? 具体要做什么? 向下打深(6个月内优

Apr 9, 20262 min read2

BMS

12 posts