Skip to main content

Command Palette

Search for a command to run...

储能 EMS 的 PID 功率调节落地:从原理到工程实现(含死区、分离阈值、限幅、稳态启用)

Updated
2 min readView as Markdown

1. 写在前面:这不是“教科书 PID”,而是“能跑的 PID”

在储能系统里,EMS 常见的目标是:让并网点/总柜电表功率尽可能跟随计划功率或限值(充电、放电、削峰、跟随负载等)。但真实系统里你会遇到:

  • 电表采样噪声、刷新慢

  • PCS/电池执行响应慢、非线性、限幅

  • 外部扰动频繁(负载突变、PV 波动、网侧波动)

如果把目标功率直接下发给执行端,常见结果就是:误差大、输出抖、甚至振荡
因此工程里引入了“PID 调节”,但为了适配现场约束,我们更关心的是:

  • 能否网页在线调参

  • 能否安全启停(不带积分历史冲击)

  • 能否抗噪、抗扰、限幅保护

  • 能否快速定位问题(日志/指标可观测)

本文结合一套实际工程代码,讲清楚它的整体思路与关键实现。


2. 核心目标:功率闭环要控制什么?

先定义闭环的三个核心量:

  • 目标功率 (P_{target}):来自业务逻辑(计划/功率限制/可用充放能力等)

  • 反馈功率 (P_{meter}):来自电表/总柜表(工程里用柜内表功率)

  • 误差 (e = P_{target} - P_{meter})

闭环的目的不是“让 PCS 输出等于某个数”,而是更贴近业务:
让电表侧的实际功率更接近目标功率(这也是防逆流/防过载类策略更看重的量)。


3. 方案选择:增量式 PI + 补偿项(Compensation)

很多项目 PID 做不稳,不是算法错,而是“工程形态”没选对。这里采用的是非常典型、也很工程化的结构:

  • 不用位置式 PID(直接算输出)

  • 增量式 PI 计算“补偿增量”

  • 用一个 补偿量 compensation 累加变化

  • 最终输出 = 目标功率 + 补偿量

核心关系:

  • (e = P_{target} - P_{meter})

  • ( \Delta P = K_p \cdot (e - e_{prev}) + K_i \cdot e )

  • (comp \leftarrow comp + \Delta P)

  • (P_{out} = P_{target} + comp)

为什么这样做更适合现场?

  • 输出变化天然平滑(增量式)

  • 易加“工程约束”(补偿限幅、清零条件、稳态启用)

  • 目标变化期可以选择“不让补偿乱动”(很关键)

工程实现位于 Power_Control_Loop()ems_management.c),核心计算就是上述逻辑。


4. 参数体系:把 PID 做成“可在线调参”的产品能力

能不能在线调参,决定了 PID 是“实验室 demo”还是“现场可维护能力”。

工程里把参数拆成两类:

4.1 PID 参数(Parameters)

包括:

  • Kp / Ki

  • Dead Band(死区)

  • Proportional Separation Threshold(比例项分离阈值)

  • Integral Separation Threshold(积分项分离阈值)

并且充电与放电分两套参数(因为系统响应方向、动态特性常不同):

  • stPIDChgParams

  • stPIDDischgParams

结构体定义在 blob_model.h

  • PID_Params

  • PID_Ctx(里面包含两套 PID_Params)

4.2 PID 上下文(Context / State)

运行时状态包括:

  • prev_error / prev_prev_error

  • compensation

  • prev_target

  • “目标稳态计数/阈值”

为什么要把状态独立出来?
因为启停切换时必须可清零,否则积分残留会让系统“突然一脚油门”。


5. 工程化增强:现场稳定性来自这些“小细节”

下面这些机制,决定了“能不能跑稳”。

5.1 使能条件:只在合适工况启用 PID

PID 只在“充电/放电且使能”的条件下才生效;否则:

  • 输出直接等于原目标功率(不加补偿)

  • 清空 PID 历史状态(误差、补偿、稳态计数等)

这能避免“未启用时积分累积,重新启用瞬间冲击”。

5.2 目标稳态启用:目标不稳定时,先别调

工程里做了一个非常实用的策略:

  • 如果目标变化超过阈值:稳态计数清零

  • 目标持续稳定一段时间后:才允许 PID 调节进入有效区

  • 未进入稳态:误差置零 + 清历史误差 + 关闭某些高灵敏度逻辑

直觉解释:
目标本身在变时,误差并不代表“控制偏差”,而更像“目标变化的瞬态”
这时候让 PID 去追,只会引入更多抖动。

5.3 死区 Dead Band:抑制小误差抖动

当误差很小时(可能主要是噪声),直接当作 0,避免输出不断微调抖动。

5.4 分离阈值:控制器的“安全阀”

  • 误差太大时,限制比例/积分项的参与

  • 特别是积分分离:避免积分饱和导致长时间偏置

这是很多现场 PID 之所以稳的原因:
不是因为 PID 精准,而是因为它知道什么时候该“收手”。

5.5 双限幅:补偿限幅 + 输出限幅

  • compensation 有自己的上限(防越积越大)

  • 最终 raw_output 也有上下限(防下发越界)

这两层限幅属于“工程必备”,是对执行端与系统安全的保护。

5.6 清补偿阈值:小目标功率时回到干净状态

当目标功率接近 0 时,补偿归零,避免零点漂移长期残留。


6. 代码结构怎么组织?(读代码的正确路径)

如果你要在工程里快速理解 PID 功能,建议按这个路径:

  1. 数据模型/结构体blob_model.h

    • PID_Params

    • PID_Ctx

    • POWER_CTRL_ENABLE_STATE

    • EMSMgmtDatastPidCtxemPIDEnableState、PID 输出变量等

  2. 控制主回路ems_management.c

    • Power_Control_Loop():核心算法、约束策略、输出写回
  3. 参数入口(网页配置 → DPR)config/System.sql

    • PID 相关 SettingParameters:使能、Kp/Ki、阈值、限幅、稳态阈值等
  4. 使能/状态同步st_batt_sampler.c(事件更新)

    • PID Control EnableHigh Sensitivity Enable 的读取与状态更新

7. 调试与验证:现场怎么判断“PID 在起作用且没副作用”

建议按以下 checklist 排查(非常实用):

  • 使能是否正确:当前工况是充电/放电?使能状态是否允许?

  • 稳态是否达标:目标是否稳定?稳态计数是否达到阈值?

  • 补偿是否合理compensation 是小幅变化,还是经常顶到限幅?

  • 输出是否频繁限幅:若频繁打到最大/最小输出,通常不是 PID 参数问题,而是上层目标或限值策略不合理

  • 调参顺序建议

    • 先调 Dead Band 抑制抖动

    • 再调 Ki 消除稳态误差(小步慢调)

    • 最后调 Kp 改善响应速度(防振荡)

    • 分离阈值更多是“保护参数”,别设太小导致 PID 总被关断


8. 常见坑与经验(建议直接贴到项目 Wiki)

  1. 目标变化太快时不要 PID:先稳态判断,再介入补偿

  2. 积分不是越大越好:Ki 太大会“慢性振荡/累积偏置”

  3. 死区不是偷懒:它是对噪声与小功率抖动的工程解

  4. 限幅一定要双层:补偿限幅保护“积累”,输出限幅保护“执行端”

  5. 启停一定要清状态:否则现场会出现“突然冲一下”的玄学问题


9. 结语:把控制算法做成“可维护能力”

真正有价值的 PID,不是公式写对,而是具备:

  • 可配置(网页在线调参)

  • 可诊断(日志、关键状态可观测)

  • 可保护(死区、分离阈值、限幅)

  • 可安全启停(状态可清零)

  • 可工程扩展(充/放分参数、不同工况策略)

这套实现的意义就在于:把“控制理论”落成“可运营、可维护、可交付”的产品能力。


More from this blog

BMS Fault Diagnosis: Reliable Fault Detection Using a Two-State State Machine and Filtering Delay

前言 电池管理系统(BMS)在储能、电动汽车、UPS等高压直流应用中承担着核心的安全守卫职责。一个错误的故障判断——无论是漏报还是误 报——都可能带来严重后果:漏报导致过充过放损毁电芯甚至起火,误报导致系统频繁保护停机、影响生产和用户体验。 如何在噪声环境下做到"不该报的不报,该报的必须报"?本文基于真实固件代码,深入剖析其故障诊断体系的设计思路与实现细节。 一、两态故障状态机:简单却不简陋 1

Jul 14, 20268 min read

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

光伏-储能-负荷联合预测:给 EMS 装上"预知能力" 本文结合我正在维护的一套工业储能管理系统的真实工程实践,聊聊如何把预测能力嵌入 EMS 决策链路。代码片段均来自项目实际文件,不是伪代码。 一、为什么 EMS 需要预测? 我在调试这套系统的 MQTT 指令链路时,发现一个有意思的现象:EMS 的充放电决策完全依赖当前时刻的 SOC 和预设的时段计划表。翻开 ems_management

Jun 8, 20264 min read

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

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

Apr 14, 20267 min read

BMS

14 posts