简介:《电力需求响应信息模型 第1部分:集中式空调系统》为T/CEC 239.1—2019中国电力企业联合会标准,面向集中式空调自动需求响应终端、接口设计与开发人员,以及参与智能电网负荷调控的设备厂商和研究者,用于统一空调系统参与需求响应的信息表达与互操作框架。压缩包共1个PDF文件,大小约396KB,完整收录标准正文及资料性附录,便于检索查阅。目前已有307人学习。文档围绕实用性、便捷性、适用性与扩展性等建模原则,明确整型、字符串、浮点、布尔量、日期时间等数据类型,并划分通用包与专用包;附录给出需求响应能力计算方法,可帮助读者理解终端接口建模、数据字段定义、控制指令与节能策略的组织方式,为设备接入、软件开发和后续类似负荷信息模型设计提供参考。
1. 集中式空调要参与需求响应,先得有一份能对话的信息模型
某写字楼夏天收到电网侧发来的需求响应邀约,物业说“空调能压 30 分钟”,调度那边追问三句:压多少千瓦、多久能爬到位、什么时候能完全恢复。两边就聊不下去了。类似僵局我遇到过很多次,问题从来不在冷水机组能不能降载——能,问题在于双方没有共同语言去描述“这台机组此刻能提供多少可调容量、降载要付出什么代价、恢复到什么状态才算结束”。电力需求响应信息模型 第 1 部分把对象锁定在集中式空调系统上,要解决的就是这件事:把冷站里的冷机、冷冻水泵、冷却水泵、冷却塔、末端机组,连同它们的可调能力、响应约束、事件状态,整理成一组可交换、可校验、可被第三方复核的数据结构。这套模型适合三类人:做楼宇自控想往上接需求响应平台的、做负荷聚合要盘用户侧可调容量的、以及做配电侧集成需要批量对接空调资源的。它不教你怎么调 PID,但它决定你报上去的数字能不能被信任。
2. 从设备台帐到逻辑节点:集中式空调系统怎么拆成可交换的对象
集中式空调(也就是常说的中央空调)是一个典型的“点多、耦合强、边界模糊”的系统。冷水机组、冷冻水泵、冷却水泵、冷却塔、板式换热器、组合式空调机组、风机盘管、电动二通阀,任何一台设备的动作都会牵动整个水系统的温度和流量。给这样的系统建模,最忌讳按电气一次图去切,也忌讳按厂家品牌去切。合理的切法只有一种:按“能独立表达可调能力的最小单元”来切。
2.1 先定边界:一棵从站到末端的对象树
我一般把模型分成四层,层级关系固定,不允许现场随意增减,否则不同项目之间的模型无法比对。第一层是站,代表一个冷源站或一个独立的空调系统边界,它承担需求响应事件的接收、能力汇总和回执;第二层是子系统,冷源侧、输配侧、末端侧三个,用来描述耦合关系;第三层是设备,冷机、各类水泵、冷却塔、末端机组;第四层是能力,也就是可调容量、爬坡率、可持续时长这些“数字”,它们不挂在设备铭牌上,而是挂在设备当前工况下。
这样分层的好处是汇总逻辑天然成立:站级可调容量 = Σ(设备级可调容量) ,但要乘一个同时率系数,因为水泵降频之后冷机的可用能力也会跟着变。很多项目栽在这里——把设备容量简单相加,报出去的数字比实际能拿到的多三成,第一次结算就被打回来。所以模型里必须有一个“同时率”或“耦合修正系数”属性,挂在子系统层,由现场调试时标定,默认值我一般取 0.85,再按实际响应曲线修正。
对象树还要解决一个现实问题:现场大量设备根本没有通信接口,老冷机只有一块本地显示屏。这类设备不能从模型里排除,而要建成“虚拟设备”——保留设备对象和铭牌属性,运行数据由人工录入或由电量计量间接推算,并打上数据来源标记。模型对数据来源的诚实,比数据的精度更重要。
2.2 冷站主要设备的属性清单
属性清单是整个模型里最容易失控的部分。写多了没人填,写少了没法算。我的经验是每类设备控制在“6 个静态属性 + 8 个动态属性 + 4 个能力属性”以内,再多就是给自己挖坑。下面这张表是冷站核心设备的必备项,可以直接当检查清单用。
| 设备类 | 静态属性(铭牌/配置) | 动态属性(实时上报) | 能力属性(响应相关) |
|---|---|---|---|
| 冷水机组 | 额定制冷量、额定功率、最小负荷率、最短运行时间、最短停机时间、允许启停次数/小时 | 启停状态、负载率、冷冻水出水/回水温度、功率、累计运行时长、故障码 | 可下调容量、可上调容量、降载爬坡率、恢复时长 |
| 冷冻水泵 | 额定流量、额定扬程、额定功率、变频下限频率、台数 | 运行状态、频率、流量、功率、进出口压差 | 可降频幅度、对应节电功率、爬坡率 |
| 冷却水泵 | 同上,另加与冷机的联锁关系 | 运行状态、频率、流量、功率 | 同上,受冷机最小冷却水量约束 |
| 冷却塔 | 风机台数、单台功率、变频下限、出水温度设定 | 风机状态、频率、出水温度、湿球温度 | 可降容量、受出水温度上限约束 |
| 组合式空调机组 | 额定风量、风机功率、送风温度设定、服务区域 | 风机频率、送风温度、回风温度、阀位、功率 | 可降风量比例、温度越限容忍时长 |
| 电动调节阀 | 口径、流量特性、行程时间 | 阀位反馈、指令值 | 可关小幅度、动作时间 |
表里最容易被忽略的是“最短运行时间”“最短停机时间”“允许启停次数”这三个。它们看着像运维参数,实际上是硬约束:一台冷机上报“10 分钟内可削减 200 kW”,但如果它刚启动 5 分钟,强制停机就要付出代价,模型里没有这个约束字段,平台就会给出一个物理上不该执行的调度指令。
能力属性里,“爬坡率”和“恢复时长”最能区分专业和不专业。爬坡率决定调度能在多短时间内把功率压下去,恢复时长决定事件结束后多久能回到正常工况、会不会影响第二天的基线。这两个数字不是查手册得来的,是现场实测出来的,实测方法后面第 6 章会讲。
2.3 从现场点表反推模型:一次最小盘点的四步流程
不要拿着模型规范去现场逐条对照,那样一天盘不完一栋楼。实际做法是反过来:先拿到现场已有的点表和系统图,再往模型上映射。四步走。
第一步,圈出参与响应的设备清单。判别标准很简单:能远程改变功率、且改变后不影响安全的设备。照明、电梯不在这个标题范围内,空调系统里末端风机盘管通常也不单独列,合并到区域。
第二步,对每台设备确认三件事——有没有通信接口、能不能远程写、写下去之后有没有反馈。这三件事决定了它在模型里是“可控设备”“可观设备”还是“虚拟设备”。只有可观不可控的设备照样要建模,因为它参与基线计算。
第三步,把点表里的点名逐条对到属性上,对不上的先标“待定”,不要硬凑。我见过把冷机的“运行时间累计”硬塞进“最短运行时间”字段的,结果平台算出来的可调容量全是 0。
第四步,用一张 Excel 或者配置表把映射关系固化下来,作为模型的实例化输入。这张表后面第 4 章会给出 YAML 形态,核心是每个模型属性一行,写明来源协议、对象地址、缩放系数、品质位来源。固化之后,换楼只改表不改代码,这是能不能批量复制的分水岭。
提示:盘点阶段一定要拉上现场运维的人。模型里 60% 的约束条件(联锁、防冻、结露、工艺要求)只存在于运维师傅的脑子里,规范文档上一条都没有。
3. 事件、基线、可调容量:需求响应侧的数据结构怎么定
设备模型解决的是“我有什么”,事件模型解决的是“什么时候、要我做多少、怎么算做到”。这两块必须一起设计,因为它们共享同一套时间基准和状态定义。很多项目把设备模型做得很细,事件侧只留了一个“目标功率”字段,结果执行完了没法结算,也没法复盘。
3.1 事件对象必须写死的字段与取值约束
事件对象是整个模型的主键载体,字段少了没法算,字段多了没人填。下面这 12 个字段是我认为不能省的,每一条都有明确的取值约束。
| 字段 | 含义 | 取值约束与常见错法 |
|---|---|---|
| 事件标识 | 全局唯一编号 | 必须跨系统唯一,不能只用自增整数,否则并网后冲突 |
| 事件类型 | 削峰 / 填谷 / 紧急 / 经济 | 紧急事件通常不参与基线结算,类型必须早定 |
| 通知时间 | 平台下发时刻 | 用 UTC 带时区偏移,不要用本地时间字符串 |
| 提前通知时长 | 通知到开始的间隔 | 单位统一为分钟,且必须 ≥ 设备最短启动准备时间 |
| 开始时间 / 结束时间 | 响应窗口 | 两个字段必须成对出现,不能只给时长 |
| 目标削减量 | 期望削减的功率 | 单位 kW,保留一位小数,避免精度歧义 |
| 目标削减比例 | 相对于基线的比例 | 与目标削减量二选一作为主判据,另一个作校核 |
| 爬坡率要求 | 每分钟可接受的变化量 | 缺少这一项,慢响应设备会被判违约 |
| 允许中断次数 | 窗口内可暂停次数 | 冷机频繁启停的容忍度就靠这个字段表达 |
| 基线类型与基线值 | 结算依据 | 类型枚举化,基线值必须带计算方法标识 |
| 响应等级 | 多档位,如 1~3 级 | 等级与容量对应关系要在模型里显式声明 |
| 状态 | 待确认/已接受/执行中/已完成/已终止/违约 | 枚举固定,不允许自定义字符串 |
表里“提前通知时长 ≥ 设备最短启动准备时间”这条约束,建议做成模型校验规则而不是靠人看。冷水机组的准备时间、水泵的暖机时间、末端的预冷时间各不相同,平台按最短的那个下发通知,一定会有设备来不及。
另一个容易漏的是“目标削减量”与“目标削减比例”的主判据问题。两者同时给且互相矛盾时,现场执行会无所适从。模型里必须声明哪一个优先,我的习惯是以绝对量为主判据,比例只用于聚合商层面的分摊。
3.2 基线算法怎么变成模型里的一个属性
基线不是一个数字,是一个算法加一组参数。把算法硬编码在平台里,换一个地区、换一种建筑类型就得改代码。正确做法是把基线做成模型里的一个对象:类型标识 + 计算窗口 + 排除规则 + 修正系数。
常见的基线类型有三种。高 N 取平均:取事件前若干天中负荷最高的几天做平均,抗偶然波动;相邻时段法:取事件前 2~4 小时的平均功率外推,对天气突变敏感;回归法:用历史负荷对气温、湿度做回归,适合季节性变化大的地区。集中式空调的基线我倾向于用“高 N 取平均 + 当日气温修正”,因为空调负荷和气温的相关性太强,纯统计法在连续高温天会把基线压低,用户白白吃亏。
排除规则同样要建模。事件日、节假日、设备检修日、极端天气日要不要从基线窗口剔除,必须写成显式规则,否则同一份数据换个人算出来就是两个数。修正系数一般用当日最高气温与窗口内平均最高气温的差值乘以一个灵敏度系数,这个系数按建筑类型标定,办公类通常取 3%~5%/℃。
下面这段是我常用的基线计算骨架,参数全部从模型对象里读,不写死。
# baseline.py —— 基线计算,参数来自模型中的 BaselineProfile 对象 def compute_baseline(history, profile, event_day): # history: [(date, temp_max, avg_kw), ...] 已剔除排除日 window = [h for h in history if h[0] not in profile["exclude_days"]] window = window[-profile["window_days"]:] # 取最近 N 天 top = sorted(window, key=lambda x: x[2], reverse=True)[:profile["top_n"]] base = sum(x[2] for x in top) / len(top) # 高 N 取平均 d_temp = event_day["temp_max"] - sum(x[1] for x in top) / len(top) return base * (1 + profile["temp_sensitivity"] * d_temp)window_days一般取 10,top_n取 3 到 5,temp_sensitivity按建筑类型取 0.03~0.05。这三个参数在模型里是显式属性,允许现场调整并留痕。改参数要记录修改人和时间,否则事后结算时没人说得清当初为什么是这个基线。
3.3 响应状态机与回执时序:别让“已执行”变成自说自话
状态机是这个模型里最像“协议”、也最容易被轻慢对待的部分。我见过太多系统,状态只有“执行中”和“已完成”两个,结果事件结束了平台不知道用户到底压下去没有,只能靠事后读表,中间这段时间全是黑匣子。
完整的状态迁移应该是:待确认 → 已接受(或已拒绝,带原因码)→ 执行中 → 已恢复 → 已完成(或违约)。每个迁移都要有一条回执消息,回执里带三个东西:迁移发生的时刻、迁移时刻的实测功率、迁移的原因码。原因码至少覆盖:设备故障、约束越限、人工干预、平台指令终止。
“已恢复”这个状态是很多人漏掉的。需求响应事件窗口结束,不等于设备立刻回到原工况。冷机重新加载、水温回落、末端温度恢复都需要时间,有的要 30 分钟以上。模型里必须有一个独立的“恢复时长”属性,并且在状态机里体现,否则结算时按事件结束时刻的功率去比对,用户明明完成了响应,却因为还在恢复过程中被判定“未恢复到基线”。
时序上还有一个硬要求:回执时间戳一律用 UTC,并在模型里声明时钟漂移容限,一般要求设备侧与平台侧偏差在 1 秒以内。跨系统对时不准,事件窗口就会错位,错位几分钟,基线比对结果能差出几十千瓦。
4. 映射落地:信息模型怎么挂到 Modbus / BACnet 的现场点表上
模型写得再漂亮,落到现场还是要面对一堆 Modbus 寄存器和 BACnet 对象。这一章讲的就是中间那层黏合剂。我的观点很明确:映射关系必须是数据,不能是代码。
4.1 三条落地路径的取舍
现场有三种典型做法,各有适用边界,选错了后期维护成本翻倍。
| 路径 | 做法 | 适用场景 | 主要代价 |
|---|---|---|---|
| 原生建模 | 现场网关直接按信息模型建模,设备层就对齐 | 新建项目,控制器可编程 | 对集成商要求高,调试周期长 |
| 点表转换 | 现场保持原有协议,网关做协议到模型的映射 | 改造项目,存量设备多 | 依赖映射配置的准确性 |
| 旁路计量 | 加装独立计量与控制回路,只在响应时段接入 | 老设备无接口、不允许改动 | 数据不完整,只能做可调容量估算 |
存量楼宇改造我一般走点表转换,因为不可能为了需求响应把整栋楼的控制器换掉。原生建模适合新建,一次到位,后面不用维护两套语义。旁路计量是最后手段,能用但要清楚它的局限:拿不到设备级状态,只能测总功率,可调容量只能靠统计估计,不能做精细调度。
还有一个常被忽略的中间选项:混合路径。冷站主机走点表转换,末端走旁路计量,站级汇总时按数据来源打标记,精度高的权重高。这种做法工程上很务实,模型里只要把“数据来源”和“置信度”两个属性加上就能支持。
4.2 用一张配置表把模型和点表解耦
映射配置的核心结构是“模型属性 ← 现场点”。一条记录描述一个属性的来源、地址、缩放、品质位来源。写成一棵 YAML 树,网关启动时加载,运行期只读。
# model_map.yaml —— 一条记录对应一个模型属性,换楼只改这张表 model: Plant01.Chiller01 # 模型实例路径,与对象树一致 class: Chiller points: - attr: Availability # 可用性:能否参与本次响应 source: bacnet object: AI-1 # 现场对象实例号 property: present-value quality_from: reliability # 品质位从现场对象取,不自己造 - attr: CoolingOutput # 当前制冷量 source: modbus unit_id: 3 register: 40021 dtype: uint16 scale: 0.1 # 原始值 × 0.1 得到 kW offset: 0 - attr: MinLoadRatio # 最小负荷率,铭牌静态参数 source: const value: 0.3 - attr: RestoreDuration # 恢复时长,实测标定值,单位分钟 source: const value: 25scale和offset是最容易出错的两列。Modbus 寄存器常以 0.1 为单位存温度、以 0.01 存功率,漏乘一次,上报的容量就差一个数量级。我的习惯是配置表里所有scale必须写全,哪怕是 1.0 也写出来,避免后来人以为可以省略。
quality_from这一列决定了数据可信度。BACnet 对象自带 reliability 属性,直接透传即可;Modbus 没有品质位,就要靠网关做超时判断,连续 N 次读失败就把品质位打成“无效”,而不是继续上报最后一次的值。这一条后面还会展开。
source: const用于铭牌参数和标定值,这类数据不进实时采集,但必须在模型里存在。把它们和实时点混在一张表里,好处是模型实例化只有一条路径,不会出现“静态参数在数据库、动态参数在网关”的分裂。
4.3 时间戳与品质位:最容易被糊弄的两列
绝大多数翻车不是因为主数据错,而是因为这两列没做好。
时间戳的问题是时区。现场控制器多数用本地时间,而且不带时区标识,到了跨时区或跨系统对接时,事件窗口就对不上。我的做法是网关统一转换成 UTC 毫秒时间戳,本地时间只在展示层出现。模型里每个动态属性都带自己的采样时间,不是一个设备一个时间,因为不同协议的采集周期不同,用一个时间会把慢采样的点“变新”。
品质位的问题是把“没数据”当成“数据是 0”。冷机通信断了,网关读不到功率,如果直接填 0,平台会认为这台机组当前功率为零,可调容量算出来是满的,调度下发指令过去必然失败。正确做法是品质位置为“无效”,模型汇总时把该设备从可用容量里剔除。
品质位的取值我一般只用四个:有效、无效、被闭锁、人工置数。“被闭锁”用于检修挂牌、联锁保护动作这类情况,它的语义是“设备本身是好的,但现在不允许动”,和“无效”要区分开,因为前者在容量汇总里同样要剔除,但在故障统计里不算故障。“人工置数”用于调试和应急,必须带有效期,过期自动失效,防止调试时填的值一直挂着。
注意:品质位不要自己发明枚举。模型里定义几种就用几种,自定义字符串在跨系统交换时一定解析失败。
5. 联调避坑:五类翻车现象与排查顺序
现场联调阶段暴露的问题,八成不是模型设计错,而是设计和现场之间那层“想当然”。下面五条按我遇到的频率排序,每条都给出排查顺序。
5.1 容量类与状态类的坑
现象一:平台显示可调容量 800 kW,实际响应只压下去 300 kW。原因通常是把额定功率当成了可调容量。一台 500 kW 的冷机,最小负荷率 30%,它真正的可下调空间最多是 350 kW,还要扣掉当前已经在低负载运行的部分。更隐蔽的是耦合:冷机降载之后冷冻水温上升,末端阀位开大,水泵频率上升,输配侧功率反而涨了。 解决方式是模型里强制分离“额定容量”和“当前可调容量”两组属性,后者由工况实时计算,并且在子系统层乘耦合修正系数。上报前做一次自检:设备级可调容量之和 × 同时率 ≤ 站级历史最大功率与当前功率之差。
现象二:事件下发后一部分设备完全没动作,平台却显示“已执行”。原因是可用性判断没串起来。设备状态里其实已经有“检修”“联锁”“故障”这些位,但可用性属性是单独算的,没读这些位。另一个常见原因是把“通信正常”等同于“可控”,其实有些点表只读不写,写下去返回成功但设备不动。 解决方式是可用性做成一个复合判断:通信品质有效 AND 无故障 AND 未挂牌 AND 该点可写 AND 满足最短运行时间约束。五条全过才算可用。联调时逐个设备人为制造一个不满足条件,看可用性有没有正确翻转,这是必做的验证动作。
5.2 时序类与工程类的坑
现象三:事件窗口结束,平台判定恢复超时,用户申诉。原因是把“事件结束时间”和“恢复完成时间”混成一个字段。事件窗口只管到结束时刻,恢复是窗口之后的事,模型里必须有独立的恢复时长和恢复完成状态。还有一个变种:恢复时长填的是设计值,不是实测值,实测往往长得多。 解决方式是恢复时长按设备类型分别标定并定期复测,冷机 20~40 分钟、水泵 5~10 分钟,差异很大。状态机里加“已恢复”节点,回执带实测功率,结算时按恢复完成时刻的功率比对,而不是事件结束时刻。
现象四:事件窗口整体偏移半小时,基线比对全乱。原因是时间戳没统一。现场控制器用本地时间且不标时区,网关直接透传,平台按 UTC 解析,刚好差一个时区偏移。夏令时切换那天会更乱。 解决方式是全链路统一 UTC,网关做一次转换,模型里每个时间戳带时区偏移字段,平台入库前做一致性校验:事件开始时间必须晚于通知时间,结束时间必须晚于开始时间,任何一条不满足直接拒收并告警。
现象五:换一栋楼就要改一次网关代码。原因是映射硬编码。第一栋楼为了赶工期把寄存器地址写进代码,第二栋楼地址一变就得重新编译发版。 解决方式是从项目第一天就用配置表驱动,代码里只保留“读取配置 → 建实例 → 周期采集”三段逻辑。这件事没有技术难度,纯粹是工程纪律问题,但决定了这套方案能不能复制到第十栋楼。
排查顺序我固定为:先查时间戳,再查品质位,再查可用性,最后查容量计算。因为前三类是“硬错”,能快速排除;容量类是“软错”,要对着曲线一点点看。
6. 上线前用历史数据回放,把模型的可信度验一遍
模型和现场对上之后,别急着接真实事件。我的习惯是先做一个回放沙盘:拿过去 30 天的历史数据,人为构造几个需求响应事件,让模型走一遍完整流程,看申报值和实测值的偏差。这个过程不花钱,但能提前暴露大部分逻辑错误。
6.1 一个最小回放沙盘怎么做
输入三样东西:历史功率与温度曲线(15 分钟粒度够用)、设备状态日志、映射好的模型实例。输出两样:模型在事件时刻给出的可调容量申报值,以及从历史数据里“真实”能压下去的量。两者一比,偏差就出来了。
# replay.py —— 用历史数据回放一次事件,比对申报容量与可实现容量 def replay(model, hist, event): t0 = event["start"] declared = model.declared_capacity(t0) # 模型申报的可调容量 base = model.baseline(t0) # 同一套基线算法 actual = base - min(p for t, p in hist if t0 <= t < event["end"]) # 实际最低功率 return { "declared_kw": declared, "achievable_kw": actual, "error_ratio": (declared - actual) / max(actual, 1e-6), }declared_capacity直接调模型接口,不要另写一套算法,否则验的不是线上那套逻辑。回放窗口建议覆盖三种天气:连续高温、阴雨、气温骤降,因为空调负荷的响应特性和天气强相关,只回放晴天数据会高估能力。
6.2 三个验收指标与阈值
回放跑完看三个数。第一是容量申报偏差率,我要求绝对值控制在 20% 以内,超过就说明耦合修正系数或最小负荷率标定有问题。第二是事件执行率,即可用设备在窗口内实际参与响应的比例,低于 90% 要逐台查可用性判断。第三是恢复时长偏差,实测恢复时间与模型标定值之差,超过 50% 就要重标。
这三个数不是一次达标就完了,季节切换、设备大修、末端改造之后都要重跑。我吃过一次亏:春天标定的耦合系数,到七月连续高温时完全不准,申报容量虚高四成,第一次真实事件就被判了部分违约。从那以后我把回放做成了季度例行动作,比任何文档都管用。
再往前一步是聚合。单栋楼的模型跑顺了,多栋楼往上汇总时会遇到同时率、响应速度差异、基线口径不一致三个新问题。我的建议是先把单体的三个指标稳定住,再谈聚合,否则聚合层算出来的数字只是把误差放大了。这个方向值得做,因为集中式空调是目前用户侧少数几个既有量、又相对可测、还能连续调节的资源类型,模型做扎实了,后面的调度和结算才有基础。希望帮到你。
本文还有配套的精品资源,点击获取