Lesson 06 · 支柱 B · 控制
无模型 DRL 设定值优化(SAC)
预测已就位,现在让它"动起来"——用深度强化学习优化 HVAC 设定值,在能耗与舒适间找最优。
支柱 A 解决了"未来会怎样"(预测)。支柱 B 解决"那我该怎么动"(控制)。BrainBox 控制层是无模型深度强化学习(事实核查定调,第 1 课)——它不学环境模型,直接从试错里学一个"好策略"。
这一课给你完整闭环:奖励设计 → 安全限幅 → SAC 训练 → 对标 PID 基线看节能率。跑完你会得到一个"在仿真里比 PID 更省电还不违规"的策略。
一、为什么是无模型,为什么是 SAC
先澄清一个常见混淆(第 1 课讲过,这里再敲一遍):
| 无模型(BrainBox 用的) | 基于模型 / MBRL(DreamerV3) | |
|---|---|---|
| 学不学环境模型 | 不学,直接学策略 | 先学动力学模型,再在模型上规划 |
| 样本效率 | 低(要大量交互) | 高(可在模型里想象) |
| 实现复杂度 | 低(成熟库直接用) | 高 |
| BrainBox 是否用 | 是(事实核查确认) | 否(公开材料零出现) |
无模型 RL 里,连续控制(设定值是连续数)的事实首选是 SAC(Soft Actor-Critic)。三个理由:
- off-policy:历史交互存进 replay buffer 反复用,样本高效——这对每一步都是昂贵 EnergyPlus 仿真的 HVAC 至关重要。
- 熵正则:自带探索,不易陷局部最优;对奖励形状不敏感。
- 连续动作 SOTA:SB3 文档明确把 SAC 列为单进程连续控制首选。
二、奖励函数:复刻 BrainBox 的多目标
BrainBox 专利反复出现"user objective indicators",奖励是能耗 + 舒适度 + 设备磨损的加权。这是整课最需要"调"的部分——权重直接决定策略行为。
def hvac_reward(obs, action, prev_action, pwr_max=1e6): # obs 里取出关键量(列号按你的 env 调整) T_zone = obs[0] # 区域温度 °C co2 = obs[1] # CO₂ ppm fan_pwr = obs[2] # 风机功率 W chiller = obs[3] # 冷机功率 W # ① 能耗(归一化) e_energy = (fan_pwr + chiller) / pwr_max # ② 舒适违规:超出 ASHRAE-55 的 18–26°C 死区 over_hot = max(0.0, T_zone - 26.0) over_cold = max(0.0, 18.0 - T_zone) comfort = 2.0 * (over_hot + over_cold) # K/K 斜率 # ③ IAQ:CO₂ 超 1000ppm 惩罚 co2_pen = max(0.0, co2 - 1000.0) / 1000.0 # ④ 设备磨损:动作抖动(设定点反复横跳伤压缩机) wear = np.sum(np.abs(action - prev_action)) return -(0.4*e_energy + 0.4*comfort + 0.1*co2_pen + 0.1*wear)
三、动作空间:设定值 + 安全限幅
BrainBox 控的是设定值(setpoint),不是阀门。SAC 输出归一化的 [-1,1],你要映射回真实物理范围并限幅 + 平滑。
SAFE = {"sat": (12.0, 18.0), # 送风温度设定点 °C
"chw": (5.0, 10.0), # 冷冻水供水温度设定点 °C
"airflow": (0.2, 1.0)} # 风量占比
def to_safe_action(a, prev):
# a ∈ [-1,1]^3 → 真实设定值
sat = (a[0]+1)/2 * (SAFE["sat"][1]-SAFE["sat"][0]) + SAFE["sat"][0]
chw = (a[1]+1)/2 * (SAFE["chw"][1]-SAFE["chw"][0]) + SAFE["chw"][0]
af = (a[2]+1)/2 * (SAFE["airflow"][1]-SAFE["airflow"][0]) + SAFE["airflow"][0]
raw = np.clip([sat, chw, af],
[SAFE[k][0] for k in SAFE], [SAFE[k][1] for k in SAFE])
# EMA 平滑,防策略"乱抖"伤设备
smoothed = 0.7*prev + 0.3*raw
return smoothed
限幅保证 SAC 永远发不出"冻管"或"失流"指令;平滑压制高频抖动。这两步是第 7 课安全门控的雏形。
四、动手做:SAC 训练完整闭环
动手做 6.1 · SAC 训练 + 评估回调(核心)
import gymnasium as gym, sinergym from stable_baselines3 import SAC from stable_baselines3.common.vec_env import DummyVecEnv from stable_baselines3.common.callbacks import EvalCallback from gymnasium.wrappers import NormalizeObservation from sinergym.utils.wrappers import NormalizeAction, LoggerWrapper ENV_ID = "Eplus-5zone-hot-continuous-stochastic-v1" def make_env(): env = gym.make(ENV_ID) env = NormalizeObservation(env) # 观测归一化(必做!) env = NormalizeAction(env) # 动作映射到 [-1,1] env = LoggerWrapper(env) # 记录能耗/舒适 return env train_env = DummyVecEnv([make_env]) eval_env = DummyVecEnv([make_env]) # 独立评估环境 model = SAC("MlpPolicy", train_env, learning_rate=3e-4, buffer_size=100_000, batch_size=256, gamma=0.99, verbose=1) # 评估回调:每 N 步在 eval_env 上跑,存最优模型 cb = EvalCallback(eval_env, best_model_save_path="./sac_best", log_path="./sac_logs", eval_freq=5_000, deterministic=True) model.learn(total_timesteps=50_000, callback=cb) # 先小步快跑通 model.save("sac_hvac") print("训练完成,最优模型在 ./sac_best")
tensorboard --logdir ./sac_logs)里 eval/mean_reward 应稳步上升。先跑 50k 步验证管线;正式训练通常要 200k–500k 步才稳定(每步是 EnergyPlus 仿真,会比较慢,第 8 课讲并行提速)。
动手做 6.2 · 对标 PID 基线,算节能率
import gymnasium as gym, sinergym, numpy as np from stable_baselines3 import SAC def run_policy(model, env_id, steps=3504): # 一年 env = gym.make(env_id) obs, _ = env.reset() energy, comfort_viol = 0.0, 0 for _ in range(steps): action, _ = model.predict(obs, deterministic=True) obs, r, term, trunc, info = env.step(action) energy += info.get("total_power", 0.0) if obs[0] > 26 or obs[0] < 18: comfort_viol += 1 if term or trunc: obs, _ = env.reset() env.close() return energy, comfort_viol sac = SAC.load("./sac_best/best_model") e_sac, c_sac = run_policy(sac, "Eplus-5zone-hot-continuous-stochastic-v1") # e_pid, c_pid = run_policy(pid_model, ...) # 第 3 课的 PID 包成同样接口 # saving = (e_pid - e_sac) / e_pid * 100 print(f"SAC 能耗={e_sac:.0f} 违规步数={c_sac}")
五、提速与冷启动(进阶,但必须知道)
无模型 RL 在 HVAC 上的两大现实痛点:训练慢、真实楼不能随便试错。
训练慢 → 并行 + 离线预训练
| 痛点 | 解法 |
|---|---|
| 单 env 每步要等 EnergyPlus | SubprocVecEnv / VecEnv 开 N 个仿真副本并行(SAC 可换 PPO 吃满并行度) |
| 真实楼不能在线试错 | 用历史 BMS 日志做离线 RL预训练(d3rlpy 的 IQL/CQL),再在线微调 |
| 探索阶段会乱发危险动作 | 第 7 课的安全门控(shielding) |
import d3rlpy # 从 BMS 历史日志构造 (obs, action, reward, next_obs, terminal) dataset = d3rlpy.dataset.MDPDataset(observations, actions, rewards, terminals) iql = d3rlpy.algos.IQLConfig().create(device="cuda:0") iql.build_with_dataset(dataset) iql.fit(dataset.episodes, n_steps=100_000) # 再把 IQL 权重灌进 SAC 做在线微调,省掉大量危险探索
1. BrainBox 控制层是无模型 DRL(事实核查定调),连续控制首选 SAC(off-policy、样本高效、熵正则)。
2. 奖励 = 能耗 + 舒适违规 + CO₂ + 设备磨损的加权(权重是奖励工程灵魂,要按量纲调)。
3. 动作要去归一化 + 限幅 + EMA 平滑——这是安全门控的雏形。
4. 你跑通了 SAC 训练 + 评估闭环,并对照 PID 基线算出节能率(典型 15–25%)。离线预训练是"上真楼"的关键延伸。
在 HVAC 控制里,相比 PPO,SAC 的核心优势是什么?
对了。SAC 是 off-policy(PPO 是 on-policy)。off-policy 意味着每条历史交互都能被 replay buffer 多次重放来更新策略——在每一步都触发一次完整 EnergyPlus 仿真的昂贵环境里,这种样本复用是决定性的训练效率优势。SAC 处理连续动作、需要奖励函数、靠熵正则稳定——其余三项都错。
- Stable Baselines3 仓库 / 示例:github.com/DLR-RM/stable-baselines3 · examples
- Gymnasium 接口:gymnasium.farama.org/api/env
- d3rlpy 离线 RL:github.com/takuseno/d3rlpy
- 专家引导 DRL + 安全屏蔽(Xu 2025, Nature Sci Rep):doi/10.1038/s41598-025-91326-z(研究材料原 ID -87288-x 已修正)
- Sinergym 上 SAC/TD3/PPO 基准:arxiv.org/abs/2401.05737
- 研究材料对标:world-model-research.md §6.4 / §6.6