把并网点拆成结算单元:三个让总额对得上、明细全错的建模坑
月末对账那天,两家主体拿着同一张明细表来找我。一家算出来 285,另一家也算出来 285,总额一模一样。往下翻明细,差 200 度电。
那一刻我才承认:总额对得上,是这类 bug 最危险的伪装。
一、设备台账加几个字段,不是结算实体
过去做储能电站的能量管理系统,站内只有一块关口表,谁发的电、谁用的电,全都在一条线上,账很安静。一旦站里出现第二个权属主体(租出去的容量、共享的升压间隔、代运维的电池组),这套模型立刻不够用。
最常见的补救是在设备台账上加三个字段:所属主体、分摊比例、计量点编号。这个做法有三个问题,而且都不在数据写入那一刻暴露。
- 一个设备只能属于一个主体。 共用关口表要按比例分摊给两家,加一列
owner就塞不下第二个值,只好拆成两条设备记录,然后全站的容量统计开始重复。 - 主体关系没有时间维度。 成员 10 月 20 日退出共用、改成独立计量,台账上改一下字段就把历史抹了。10 月 18 日那两天的账再也算不回来。
- 台账是给运维看的视图。 设备增删、间隔调整、检修挂牌都会动它。拿一个高频变更的视图当结算依据,等于把账本挂在会动的墙上。
结算单元的粒度不是设备,是那本要被考核的账。 先有单元,才有聚合;设备是单元的成员,不是单元本身。
二、四张表,把「账」建成实体
规则层面的依据很直接。现货新规的附件把新型经营主体做成二分:单一技术类(分布式光伏、分散式风电、储能、可调节负荷)与资源聚合类(虚拟电厂、负荷聚合商、智能微电网、绿电直连);第八条允许新能源与场站内配套储能作为联合报价主体,参与申报、出清、调用、结算和考核;聚合模式的结算数据要求由被聚合资源的计量数据汇总生成,并区分不同时段的上网与下网电量。
翻译成表结构,最小集合是四张:
CREATE TABLE settlement_unit( -- 结算单元:法定对象,独立于设备
unit_id TEXT PRIMARY KEY, unit_name TEXT,
unit_type TEXT, -- single / aggregate
node_id TEXT); -- 现货节点,决定用哪个节点价
CREATE TABLE metering_point( -- 计量点:物理表位,不含权属
mp_id TEXT PRIMARY KEY, mp_name TEXT, ct_ratio REAL DEFAULT 1);
CREATE TABLE unit_member( -- 成员关系:多对多 + 分摊比例 + 有效期
unit_id TEXT, mp_id TEXT, share_ratio REAL,
valid_from TEXT, valid_to TEXT,
PRIMARY KEY(unit_id, mp_id, valid_from));
CREATE TABLE meter_reading_15m( -- 读数:带方向,带规则版本
mp_id TEXT, ts TEXT, direction TEXT, -- import / export
kwh REAL, rule_ver TEXT,
PRIMARY KEY(mp_id, ts, direction, rule_ver));
关键在 unit_member 这一张。它把「哪个计量点算进哪个单元、算多少比例、从哪天算到哪天」从设备台账里剥出来,变成可以按时段回溯的关系。有了它,一个计量点同时挂给两个单元不会重复建记录,成员退出也不会改历史。
汇总口径只有一条:
SELECT u.unit_id, r.direction, ROUND(SUM(r.kwh * m.share_ratio), 2) AS kwh
FROM settlement_unit u
JOIN unit_member m ON m.unit_id = u.unit_id
JOIN meter_reading_15m r ON r.mp_id = m.mp_id
WHERE r.ts >= m.valid_from
AND (m.valid_to IS NULL OR r.ts < m.valid_to) -- 这一行是命门
GROUP BY u.unit_id, r.direction;
三、三个坑,我用同一份数据跑出来的
造一份最小数据:U1 是风光场站加配储的联合报价主体,U2 是共享储能。10 月 18 日两者共用 #1 主变关口表,按 70/30 分摊,当天关口上网 1000 度;10 月 20 日 U2 退出共用、改接独立进线表,22 日充电 100 度、放电 85 度。
正确口径的结果是:U1 上网 700,U2 上网 385、下网 100。
坑一:只记净额。 把方向折成一个带符号的数再加总,U2 得到 285。数字看着对,但充电 100 和放电 85 都不见了,中间损耗的 15 度无从体现。分时价格下这是致命的:充电发生在低谷、放电发生在高峰,两个方向的电量必须按各自的时段价分别结算,一旦净额化,价差就再也算不出来。
坑二:成员有效期不过滤。 少写一个 valid_to 条件,U2 从 285 变成 485,凭空多出 300 度,正是它在 10 月 18 日共用关口表上的分摊量。这类错误在月底最容易被当成「计量异常」去查表,其实表没问题,是关系没设边界。
坑三:两个错误互相抵消。 既忘了方向、又忘了有效期,U2 算出来仍然是 285,与正确答案一字不差。这就是开头那幕的来源。两个错误抵消之后,月度总额全校验不出来,只有翻到日粒度、翻到方向维度才会露馅。
实测输出(SQLite,字段与上面一致):
A 正确口径 U1 export 700.0 | U2 export 385.0 | U2 import 100.0
B 只记净额 U1 700.0 | U2 285.0
C 忘过滤有效期 U1 700.0 | U2 485.0
D 方向+有效期双错 U1 700.0 | U2 285.0 <- 与正确答案相同
四、规则为什么逼着人这么建
两天后的另一份文件把同一件事从电源侧又说了一遍。国能发电力〔2026〕69 号要求融合项目具备煤电与新能源独立电量计量条件,合理设置关口计量表,确保计量界面清晰、结果准确;接网方式要求与公用电网形成清晰的物理界面与责任界面;涉网性能要求新能源实现可观、可测、可调、可控。
一条线路送两家电,账要在表上分开,不能在线路上分。
再往下传导,这条要求会沿着设计文件一路走到代码里:一次系统图上标了计量点,监控系统的间隔表里就得有权属主体,对外接口里就得有结算方向。任何一层偷懒,最后都会在结算单上以争议的形式出现。我在 VPP 平台项目里最耗时的从来不是调控链路,而是月底那几张对不上的表:平台里没有「结算单元」这个概念,谁属于哪个报价主体、按什么口径汇总、责任算谁的,全靠人记。
五、三个反模式,代价都在半年后
| 反模式 | 当时省了什么 | 六个月后的代价 |
|---|---|---|
设备台账加 owner 字段 |
少建两张表 | 共用表强行拆设备,容量统计重复;成员变更即断历史 |
| 汇总时用净额,省一个方向维度 | 少一列、少一个 group by | 分时价差与充放电损耗永久丢失,考核无法复算 |
| 成员关系只存当前值,不留有效期 | 少两个时间字段 | 历史月份重算结果不稳定,同一期报表两次跑出两个数 |
第三种最隐蔽:它不出错,它只是不稳定。财务对账时最怕的不是错,是两次不一样。
六、落地顺序
- 先建
settlement_unit与unit_member,把关系和时间维度补上。 设备台账继续服务运维,两者用mp_id关联,不要合并。 - 读数表加
direction和rule_ver。 方向不做默认值,宁可写入时报错,也别让import悄悄落成默认。 - 每个申报量与报送量存四份快照。 申报值、指令值、实际值、认定值,各带规则版本号,并保留原始测点。凡是「报一个值、事后被考核」的场景(容量电价的最大放电功率认定就是典型),争议的胜负在留痕阶段就已经决定。
- 上线前跑一次双错校验。 故意把方向聚合与有效期过滤各关掉一次,如果两种错法的结果与正确结果相同,说明校验 SQL 本身没有覆盖到这两个维度。
数据说明
本文事实部分来源分级如下。A 级:国家发展改革委 2026-10-19《电力现货市场基本规则(公开征求意见稿)》公告及附件(新型经营主体二分、联合报价、聚合结算口径、第七十六条施行条款);国家能源局 2026-10-21《关于推动煤电与新能源融合发展的实施意见》(国能发电力〔2026〕69 号)及配套解读。B 级:上述条款细节经财新网、中国储能网 10-19 至 10-22 交叉核对。文中的电站规模、主体名称与电量数值均为示意数据,用于说明口径差异,不对应任何真实客户或项目。
涉电力市场交易与容量补偿的段落只讨论机制与实现口径,不构成投资建议。
模型是算出来的,不是接出来的。表画对了,账才算得清。

浙公网安备 33010602011771号