课程首页· 术语表· 第 4 课 / 共 6 课

Lesson 04 · 控制

用 Python 操控它:pyenergyplus 与 EMS

强化学习的命脉:能实时"读传感器、写执行器"。这一课讲清它怎么做到的。

前三课的 EnergyPlus 还是个"被动演员"——你给它 IDF 和 EPW,它演完一年吐个报表。但我们的智能体要边演边干预:每个时间步,读当前室温,决定冷机怎么开,再把这个决定塞回去。这一课讲的就是这件事的机制——EMS 和它上面的 pyenergyplus。这是整个 RL 接入的关键,也是 Sinergym(第 5 课)的地基。

核心概念:EMS(能源管理系统)

EnergyPlus 内部早就有一套机制让"外部逻辑"干预仿真,叫 EMS(Energy Management System,能源管理系统)。它的模型很干净,三个角色:

EMS 角色类比对应我们什么
Sensor(传感器)读量RL 的观测(室温、水温、CO₂…)
Actuator(执行器)写量RL 的动作(冷机功率、水泵频率…)
-meter(计量表)读能耗RL 的奖励(耗电量、COP)
关键认识

EMS 把"仿真内部"和"你的控制逻辑"解耦了

EnergyPlus 物理引擎照常算楼的热响应;EMS 在每个时间步给你一个"插口"——你通过它读到内部变量(Sensor),再把控制值写回去(Actuator)。引擎收到你的值后继续往下算。这套机制让任何外部控制器(PID、规则、RL)都能接同一个仿真。

必须在 IDF 里声明要用哪些 Sensor/Actuator,给它们起名字(方案 [§2.2.3] 里提到的 EnergyManagementSystem:Actuator 就是干这个)。没声明的量,外部读不到也写不了。这是为什么方案强调"IDF 建模需暖通工程师参与"——RL 要碰的执行器,得在建模型时就埋好。

从 Erl 到 Python:pyenergyplus 的由来

历史上,EMS 的控制逻辑用一种叫 Erl(EnergyPlus Runtime Language)的脚本写,写在 IDF 里。Erl 很笨重。从 EnergyPlus 9.3(2020 年 3 月)起,官方内置了 Python 解释器,你可以用 Python 写 EMS 逻辑——这就是 Python EMS / Python Plugin。再往后,官方又把这套能力打包成更通用的 Python API(pyenergyplus,不局限于"写 EMS 脚本",而是把整个仿真进程驱动起来

pyenergyplus 的三块能力

入口是一个类 EnergyPlusAPI,它分三类能力(官方 API 文档口径):

from pyenergyplus.api import EnergyPlusAPI

api = EnergyPlusAPI()

# 1) Functional —— 一次性查询(不在仿真循环里)
functional = api.functional

# 2) Runtime —— 注册"在仿真的某个时刻"回调(核心!)
runtime = api.runtime
runtime.callback_begin_zone_timestep_before_set_current_heat_balance(my_handler)

# 3) Exchange(数据传递)—— 在回调里读 Sensor / 写 Actuator
exchange = api.exchange
exchange.get_variable_value(...)   # 读
exchange.set_actuator_value(...)   # 写

# 然后用 api.run_energyplus(...) 启动整个仿真
能力用途RL 场景
Functional仿真外的工具查询查询状态、版本
Runtime注册回调(在某个仿真钩子点被调用)每个时间步触发"读→决策→写"
Exchange在回调内读写变量/执行器取观测、回写动作

RL 的一步,落到 EMS 上是什么样

把方案 [§2.1.4] 里 HvacEnv.step() 的逻辑翻译成 EMS 语言:

RL 智能体调 env.step(action)
        │
        ▼
┌─ Sinergym / 自建封装层把 action 存进队列 ─────────┐
│                                                   │
│  EnergyPlus 走到一个时间步                         │
│        │                                          │
│        ▼                                          │
│  Runtime 回调触发(begin_zone_timestep)           │
│        │                                          │
│        ├─▶ exchange.get_variable_value(...) × N   │  ← 读传感器 = 观测
│        │       (室温/水温/CO₂/室外温...)           │
│        │                                          │
│        ├─▶ exchange.set_actuator_value(...) × M   │  ← 写执行器 = 动作
│        │       (冷机功率/水泵频率/AHU风量...)       │
│        │                                          │
│        └─▶ 让仿真继续走这一步                       │
│                                                   │
│  仿真算完 → 把新观测 + 能耗推回队列 → 算 reward ────┘
        │
        ▼
返回给 RL 智能体:obs, reward, done
这一课的小收获

EnergyPlus 用 EMS 把物理引擎和外部控制解耦:Sensor 读观测、Actuator 写动作、meter 给奖励。从 9.3 版起,控制逻辑可用 Python 写(Python EMS / pyenergyplus),核心是 Runtime 回调(每个时间步触发)+ Exchange(在回调里读写)。RL 的 step() 就落在这一套机制上,而 Sinergym 替我们封好了它。

自测一下

RL 智能体要调冷机功率,前提是?

卡住了就问我:"回调 + 队列"通信如果让你头晕,正常——它是异步线程模型。可以问我"为什么不能同步地读一个变量",我会解释 EnergyPlus 是 C++ 主循环、Python 是被它回调的,所以天然是异步的。

参考来源 EnergyPlus Python API 文档 · DOE: Python EMS upgrade · Python Plugins I/O Reference (v26.1) · Sinergym: simulators/eplus.py · 方案文档 §2.1.4 / §2.2.1