管网漏损定位

供水管网埋在地下,漏水看不见。这套系统只用几只压力表的读数,反推出「最可能在漏的是哪几根管」,把开挖范围从几公里收到几十米。

这是可操作的演示:默认载入的这张管网、它的管径管长、监测点位置、压力读数全部是合成的,与任何真实项目无关。 但算法是真跑的 —— 页面加载时现场做了 25 次水力仿真建指纹库,你每拖动一次滑块,反演都重算一遍。 也可以换成你自己的管网:贴三张表(节点/管段/监测点)就地建库反演, 填了实测压力就用实测值反演,不填就用页面正算出来的合成读数。 数据只存在你的浏览器里,不上传、不落盘。

1 · 这套系统解决什么问题

一座县城的供水管网,每年漏掉的水常在总供水量的两三成。难点不在「知道在漏」——分区计量的夜间最小流量早就告诉你哪个区在漏——而在漏在哪一根管。听漏工沿街逐段听,一天走不了几公里;开挖验证一次意味着破路、断交通、再回填,挖错了这些成本全部作废。所以真正的问题是:怎么把开挖顺序排对

要的是排序,不是答案 没有任何算法能指着地图说「就是这里」。工程上有用的输出是一份带置信度的候选清单:先挖第 1 根,没有就挖第 2 根。评价指标因此是 top-3 命中率,不是「准不准」。
候选单元是管段,不是节点 漏损物理上发生在管段上——腐蚀穿孔、接口脱开、爆管。节点只是模型里的交汇抽象,地上没有那个东西。所以建库时把每根管从中点劈开、插一个虚拟节点再开孔,候选集是。真实项目里改成按管之后,top-1 命中率比按节点高约 7 个百分点。
所有表都同向降压 随便哪儿漏,每只压力表都往下掉,只是掉多掉少不同——任意两根管的「指纹」相似度中位数高达 0.94。常见对策是先减掉这个共同的下降量,只比响应模式的相对差异(本页实测能把 0.94 压到 0.36)。但这是笔交易不是免费午餐:换来对基线漂移的免疫,代价是丢掉幅值信息。划不划算取决于你的基线有多准,而这只能在自己的网上量、不能照抄结论——第 2 个演示区把两种口径并排跑给你看,包括去均值输掉的那些工况
压力和用水量互相咬 漏水导致压降,压降又抑制居民正常出水,出水少了压力回升一点,又反过来改变漏量本身。这个耦合只有压力驱动模型(PDA)表达得了,用常规的需水驱动模型算漏损工况,算出来的压力场是错的。
有些漏点原理上就定不了 从水厂出来的那根总干管一旦漏,全网所有表同幅下降,相对差异为零——去均值之后信号整个归零。这类漏点靠压力反演永远排不出来,只能靠分区计量的流量数据抓。把这条写进说明书,比把命中率报高一点重要。
假数字长得和真数字一样 这套结果的表格、概率、排名,用假设参数跑和用实测参数跑一模一样,肉眼分不出。所以真伪不能靠人记——引擎每次把逐项数据来源(实测/派生/假设/占位/合成)随产物一起输出,任何一项不是实测,总口径就自动降级为「演示」,界面禁止标成实测定位。

下面演示里这几条都是真在跑的逻辑,不是配图。

2 · 亲手试一下

压力表读数(米水柱)

替我造一次真漏损

在你选的管上真跑一次水力仿真,把 6 只表的读数写进左边,再让算法去猜。 这不是回放录像——仿真现算,选不同的管、不同的漏口,读数都不一样。

反演参数

嫌疑管段排序
残差 = 实测 − 基线
这张结果里,哪些数是你的、哪些是页面编的

3 · 四个公式,每个都代一遍数

下面这四个式子就是整套系统的全部数学。每个都用本页真实跑出来的数代一遍,结果能和演示区里的数字对上。 代的这些数出自内置示例管网(P16、P20 那几根管)—— 换成你自己的管网之后,演示区的数字会变,这四个式子一个字不变。

① 管段水头损失 · Hazen-Williams

水从管子一头流到另一头会损失多少压力。整个水力模型的骨架就是它加节点上的水量平衡。

hf= 10.67LQ1.852 C1.852D4.871
hf水头损失(米水柱)
L管长(米)
Q流量(立方米每秒)
CHazen-Williams 糙率系数,本页取 100–110(越大越光滑)
D管内径(,不是毫米)

代一遍:取管 P16 被劈开后的上半段,L=115 m、D=0.200 m、C=100。 先把与流量无关的部分并成阻力系数: 10.67 × 115 ÷ (1001.852 × 0.2004.871) = 1227.05 ÷ (5023.8 × 0.0003968) = 615.95。 这一段若走 Q=0.010 m³/s,则 hf = 615.95 × 0.0101.852 = 615.95 × 0.0001977 = 0.1218 m。 ——十米出头的管子只掉十几厘米,所以漏损引起的那零点几米压降才是可辨识的信号。

② 居民出水随压力折减 · Wagner 式(PDA)

压力不够时水龙头出水会变小。不写这一条,漏损工况算出来的压力场就是错的。

d(p)= d0 { 0 p ≤ 3.5 m ( ppmin preqpmin ) 0.55 3.5 m < p < 21 m 1 p ≥ 21 m
d(p)该节点在压力 p 下的实际出水量
d0该节点的额定用水量(压力充足时想用多少)
preq足额供水压力,取 21 m(约 30 psi)
pmin完全断流压力,取 3.5 m
0.55折减指数,规范经验值

代一遍:某节点压力掉到 p=15 m 时, (15 − 3.5) ÷ (21 − 3.5) = 11.5 ÷ 17.5 = 0.6571,再取 0.55 次方 = 0.7938 —— 也就是只能出到额定水量的 79.4%。本页演示网的基线压力都在 26 m 以上,全部落在「足额」那一档; 只有大爆管把某处压到 21 m 以下时,这条折减才开始起作用。

③ 漏口出流 · 孔口公式

漏多少水,取决于漏口有多大、以及那一点还剩多少压力。它和上一条一起构成「压力—漏量」的互相咬合。

q=CdA 2gp
q漏量(立方米每秒)
Cd孔口流量系数,取 0.75
A漏口面积,建库标准孔口取 0.0015 m²
g重力加速度 9.81 m/s²
p漏点处的压力水头(米)——注意它本身是被漏量拉低的,所以要迭代

代一遍:在管 P16 中点开标准孔口,迭代收敛后该点压力 p = 29.7217 m。 √(2 × 9.81 × 29.7217) = √583.14 = 24.1483, q = 0.75 × 0.0015 × 24.1483 = 0.0271668 m³/s = 27.167 L/s。 本页求解器独立算出的漏量是 27.1668 L/s,逐位一致 —— 这条正是水力内核的自检用例。 对照:全网正常用水一共才 56.5 L/s,这一个漏口就顶掉了近一半的供水量。

④ 反演匹配 · Pearson 相关 + softmax

前三个式子用来建指纹库,这一个用来查库

ρi= j=1M (rjr¯) (SijS¯i) j=1M (rjr¯)2 j=1M (SijS¯i)2 , Pi= eρi/τ keρk/τ
rj第 j 只表的残差 = 实测压力 − 基线压力(都是负数)
Sij指纹库第 i 行第 j 列 = 第 i 根管漏时第 j 只表掉多少米
r̄、S̄i各自 M 个分量的均值。减掉它就是「去均值」——把「大家一起降」的共同分量剥掉
M启用的压力表数量,本页 6
ρi第 i 根管的相关得分,值域 [−1, 1],越接近 1 越可疑
τsoftmax 温度,取 0.10。只改概率的尖锐程度,不改排序

代一遍(就是反演台默认那一局:真值 P16、无噪声,所以残差 r 恰好等于指纹库 P16 那一行):
r = [−0.3148, −0.4338, −0.4427, −0.6070, −0.5315, −0.7100],均值 r̄ = −0.5066;
拿它去比候选 P20,SP20 = [−0.3149, −0.4957, −0.4999, −0.5879, −0.6976, −0.8096],均值 = −0.5676。
两边各自去均值后逐项相乘再求和,分子 = 0.1125230;两个平方和开根分别是 0.3134853 与 0.3865859。
ρP20 = 0.1125230 ÷ (0.3134853 × 0.3865859) = 0.1125230 ÷ 0.1211885 = 0.928492 —— 与演示区表格里 P20 那一行的得分逐位相同。
而真值 P16 自己和自己比,ρ = 1.000000。再过 softmax:两者概率之比 = e(1.000000−0.928492)/0.10 = e0.71508 = 2.0444, 对应表里的 35.00% 与 17.12%(35.00 ÷ 17.12 = 2.044)。
注意这个 0.9285 有多高 —— P20 完全不是真值,得分却离满分只差 0.07。这就是为什么必须给的是排序而不是单一答案, 这个逼仄的得分间隔也解释了为什么排序对误差这么敏感。
顺带说清「去均值」到底买到了什么。它等价于在比对前把 r 和 S 各自的整体升降抹掉,好处是任何全表同幅的误差都被消掉了 ——水厂水位当天高了半米、当日整体用水偏离模型、基线本身标定得不准,这些都是全表同幅的。代价是幅值信息一起被扔了, 只剩下「形状」。所以这不是一条放之四海皆准的改进,而是一笔交易:基线越脏越该去均值,基线越干净越不必。 本页这张网的基线是干净的(就是模型自己算的),所以在演示区里你会看到朴素 cosine 反而更准。 把基线漂移逐档拨大,实测出来的是这样一组数(σ=0.02 m,各 2500 次,top-1 命中率): 基线不漂时 Pearson 82.7% / 朴素 91.5%;±0.2 m 时 82.4% / 76.6%;±0.5 m 时 83.4% / 51.8%;±1 m 时 83.0% / 31.8%去均值那条几乎是一条水平线——它对共模误差在数学上完全免疫;朴素 cosine 则一路滑下去,两条线在 ±0.17 m 附近交叉。 真实项目里网更大、指纹更像、基线是由未装齐的表和假设参数拼出来的,天平才实实在在倒向去均值。 别照抄任何一边的结论,在自己的网上量。

4 · 技术上怎么做的

水力内核 稳态管网求解用全局梯度法(Todini GGA):把上面式①的管段能量方程和节点水量平衡联立,牛顿迭代到收敛。本页这版是为演示用原生 JS 重写的,生产版本跑在 EPANET/WNTR 上。本页基线工况的节点连续性残差量级 1e-15 m³/s,水源入流与用户实际用水逐位平衡。
压力驱动 节点出水按式②随压力折减,漏口按式③出流。用水量和漏量都随压力变、又反过来改变压力,所以要在水力迭代外面再套一层不动点迭代(本页阻尼系数 0.4,收敛判据 1e-11 m³/s)。
建指纹库 逐根管从中点劈开插虚拟节点、在虚拟节点上开一个标准孔口,各跑一次仿真,得灵敏度矩阵 S[24×6],第 i 行 = 第 i 根管漏时 6 只表各掉多少米。这一步是离线的、可缓存的:拓扑/需水/水源/水力参数任一项变了才需要重建。真实项目 67 根管重建一次约 12 秒,之后命中缓存。
反演匹配 残差(实测减基线)与 S 每一行按式④做 Pearson 相关(等价于「先去均值再算 cosine」)得 24 个得分,再过 softmax 转成概率排序。去均值把行间相似度中位数从 0.94 压到 0.36、把 top-1 概率从 0.07 抬到 0.35 —— 但区分度变好不等于命中率变好:本页实测,基线干净时朴素 cosine 的 top-1 反而高出约 9 个百分点(91.5% vs 82.7%);随着基线共模漂移变大,去均值那条几乎是水平线(82~83% 不动),朴素 cosine 一路滑到 ±1 m 时的 31.8%,两条线在 ±0.17 m 附近交叉。所以它不是「更好的相似度」,而是共模误差保险,保费是幅值信息。
概率怎么读 softmax 概率是候选之间的相对可信度,不是「有 35% 的概率漏在这」。温度 τ 只改分布的尖锐程度,不改排序——你在反演台上换 τ 可以验证这一点。真正决定成败的是排序,所以验收指标盯 top-3 命中率。
已知失效模式 总干管漏损定不了(全表同幅降压,去均值后归零);② 糙率标定误差影响远大于加表——真实项目实验里糙率偏 20% 能让 top-3 命中率腰斩;③ 指纹库按单点漏损建,多点同时漏时残差是叠加的,排序会指向两点之间。这三条都写在交付说明书里,不藏。
数据真伪机制 每项输入带一个状态标签:measuredderivedassumedplaceholdersynthetic。只要有一项不是前两类,产物总口径自动落为 demo,并在终端打横幅、在产物里写明「最弱的一项是什么」。声明文件缺失或写了词表外的值,引擎直接拒绝运行——不允许靠删掉声明让警告消失。
防漂移 给开发的交付包是主仓算法的单文件重打包。快照式重打包最容易出的事故是「主仓改了一行常数,交付包没跟上,两边结果长得一模一样」。所以配了一道对账闸门,逐项比 5 份复制件字节、监测点列表、水力常数、反演参数、灵敏度矩阵与基线,并拿主仓算法把每个候选复算一遍;fail-closed,一项都没跑起来也算失败,拒绝在空集上报绿。
内置示例管网的拓扑、地名、监测点、压力读数与全部数值均为合成,与任何真实项目无关;第 3 节里代数的那几个例子也都是这张示例网算出来的。 载入你自己的数据后,本页只把它当作你声明的值原样使用,不做任何标定,也不会因此把结果标成实测定位 —— 逐项来源见反演台右下角那张表。 所有计算(建指纹库、水力仿真、反演)都在你的浏览器内完成,本页不向任何服务器发送数据。