换热站的温控数据看似只是温度、压力、流量等模拟量,但在数百个站点同时采集时,数据规模会迅速膨胀。传统方案把这些原始数据通过4G或以太网全部发往中心SCADA平台,中心平台再计算并下发阀门开度指令,整个闭环周期往往超过10秒。对于热力惯性较大的系统,这个延迟尚可接受,但当室外温度骤变或管网出现泄漏时,秒级响应就变得关键。本文将CDN的内容分发思路引入供热数据传输,把边缘网关视为缓存与调度节点,讨论如何在换热站侧完成数据优化和温控闭环。

边缘节点如何承接CDN的缓存职责
CDN解决的是内容离用户更近的问题,而智慧供热的边缘节点要解决的是数据离控制决策更近的问题。换热站边缘网关可以部署本地时序库或内存缓存,把最近一段时间的温控数据按测点和时间窗口存储起来,并向中心平台提供命中查询。中心平台不再每次都从几十公里外的站房拉取原始值,而是优先从边缘节点读取已经聚合的分钟级或秒级快照。
缓存策略可以借鉴CDN的热度淘汰机制。在供热场景中,不同测点的数据热度并不相同:一次网供水温度、二次网回水温度等关键参数被调度算法频繁读取,而一些辅助测点可能只在故障排查时才会用到。边缘网关可以维护一个带权重的访问计数,按照最近最少使用或TTL进行淘汰。下面是一个简化版的TTL缓存写入逻辑,用来判断是否更新本地缓存以及是否向中心推送变化量。
import time
class EdgeCache:
def __init__(self, ttl=5):
self.ttl = ttl
self.store = {}
def put(self, point, value):
now = time.time()
self.store[point] = (value, now)
def get(self, point):
item = self.store.get(point)
if not item:
return None
value, ts = item
if time.time() - ts > self.ttl:
del self.store[point]
return None
return value
def should_report(self, point, new_value, delta_threshold=0.5):
old = self.get(point)
if old is None:
self.put(point, new_value)
return True
if abs(new_value - old) > delta_threshold:
self.put(point, new_value)
return True
return False
这个缓存对象不仅存储了最近一次值,还通过should_report判断新值与缓存值的偏差是否超过阈值。只有超过阈值才触发上报,这样在温度平稳阶段可以大幅减少上行报文数量。实际部署时,ttl可以设置为3到5秒,delta_threshold根据二次网温度波动范围调整,通常取0.2至0.5摄氏度。
温控数据的聚合与就近调度
边缘优化不只是缓存,还要对数据进行聚合和分片。换热站内通常有十到二十个温度测点,如果每个测点独立上报,报文头开销会很高。边缘网关可以把同一时间窗口内的多个测点打包成一个数据帧,按照调控中心订阅的测点列表进行裁剪,再通过MQTT或CoAP协议发送。这种机制类似CDN的边缘节点先合并请求再回源。
调度优先级同样重要。对于参与闭环控制的测点,如二次网供水温度、室外温度,可以采用高频上报;对于只用于报表的测点,如补水箱液位,可以降低频率。边缘调度器还可以根据控制指令的紧急程度插队。以下是用Go语言实现的一个简单的优先级调度队列,它会先把高优先级变化推送到发送通道。
package main
import (
"container/heap"
"fmt"
)
type Item struct {
Point string
Value float64
Priority int
index int
}
type PriorityQueue []*Item
func (pq PriorityQueue) Len() int { return len(pq) }
func (pq PriorityQueue) Less(i, j int) bool {
return pq[i].Priority > pq[j].Priority
}
func (pq PriorityQueue) Swap(i, j int) {
pq[i], pq[j] = pq[j], pq[i]
pq[i].index = i
pq[j].index = j
}
func (pq *PriorityQueue) Push(x interface{}) {
n := len(*pq)
item := x.(*Item)
item.index = n
*pq = append(*pq, item)
}
func (pq *PriorityQueue) Pop() interface{} {
old := *pq
n := len(old)
item := old[n-1]
old[n-1] = nil
item.index = -1
*pq = old[0 : n-1]
return item
}
func main() {
pq := make(PriorityQueue, 0)
heap.Init(&pq)
heap.Push(&pq, &Item{Point: "supply_temp", Value: 48.2, Priority: 3})
heap.Push(&pq, &Item{Point: "return_temp", Value: 41.5, Priority: 5})
for pq.Len() > 0 {
item := heap.Pop(&pq).(*Item)
fmt.Printf("sending %s with priority %d\n", item.Point, item.Priority)
}
}
这个优先级队列把温度变化超过阈值的测点按照优先级排序,优先级高的先进入发送通道。实际工程中可以在优先级上叠加时间衰减因子,避免某些测点长期占据带宽。调度器与缓存模块配合后,边缘节点既能减少无效上报,又能保证关键数据不延迟。
边缘闭环控制与中心云协同
CDN的边缘节点通常只负责缓存和分发,但供热边缘节点还可以进一步执行控制逻辑。对于单个换热站的二次网温度调节,完全可以在本地完成PID闭环,只有涉及全网热力平衡或负荷预测时才需要中心云介入。这样即使公网链路中断,换热站仍然能够根据预设曲线和室外温度维持基本供暖。
本地控制器读取缓存中的实时值,计算目标温度与当前温度的偏差,然后输出阀门开度调节量。下面是一个增量式PID的简化实现,它直接运行在边缘网关的实时进程中,输出值被转换为4-20mA或Modbus指令驱动电动调节阀。
class IncrementalPID:
def __init__(self, kp, ki, kd, output_max=100.0):
self.kp = kp
self.ki = ki
self.kd = kd
self.output_max = output_max
self.prev_error = 0.0
self.integral = 0.0
def step(self, setpoint, measured, dt):
error = setpoint - measured
self.integral += error * dt
derivative = (error - self.prev_error) / dt
output = self.kp * error + self.ki * self.integral + self.kd * derivative
output = max(-self.output_max, min(self.output_max, output))
self.prev_error = error
return output
增量式PID的优势在于积分项可以限幅,避免阀门频繁大幅动作。边缘侧调度器会根据输出值的变化量决定是否下发新指令,例如输出变化小于1%时可以保持当前阀门位置,进一步减少执行器磨损。
中心云与边缘节点的协同还涉及参数分发。云平台可以定期更新每个换热站的温度设定曲线、PID参数和调度阈值,这些配置数据通过类似CDN的配置推送通道到达边缘节点。节点收到新配置后先在影子副本中生效,确认无误后再切换主配置,避免错误参数导致供热事故。
性能对比与调优建议
为了评估边缘优化效果,可以在一个包含50个换热站的试验网中对比三种模式:全量回传、定时聚合、偏差驱动加本地缓存。全量回传模式下每站每5秒上报一次全量数据,单站上行流量约为80KB/h;定时聚合可降低到30KB/h;偏差驱动加缓存可以进一步降到8KB/h以下。中心平台的平均数据延迟也从前者的6秒下降到后者的2秒以内。
边缘调度参数需要根据热力系统惯性整定。对于板式换热器,二次网温度响应较慢,delta_threshold可以适当放大,避免传感器噪声导致频繁上报;对于直供系统,响应快,需要更小的阈值和更高的采样频率。缓存TTL不宜超过10秒,否则中心查询到的数据与真实值偏差过大,影响负荷预测。
调优时还要注意边缘节点的存储与CPU占用。虽然时序库可以缓存更多数据,但边缘网关通常资源有限,建议只保留最近24小时的高频数据和最近30天的分钟级聚合数据。调度模块可以使用单线程事件循环,避免锁竞争,确保控制指令发送的确定性。