如何在温度时间序列中检测温度控制的开始和结束

信息处理 时间序列 衍生物
2022-01-31 13:27:32

我有一个巨大的数据集,其中包含建筑物内的温度数据。我想提取建筑物开始和停止控制温度的时间(大约在图片中的垂直黑线周围)。在这种情况下,温度控制同时启动和停止。但是,我想在每天和建筑物内的每个区域的开始和停止时间可变的建筑物中检测到相同的情况。您将如何寻找解决此类问题的方法?

通过检测绝对速度/加速度何时达到某个阈值以上,我可以非常可靠地检测到第一条线,但是这种方法对于检测停止点似乎不太可靠。

在此处输入图像描述

较小的子集以更好地显示数据的行为: 在此处输入图像描述

2个回答

一种选择:很明显,在不受控制的范围内,温度遵循简单的指数加热/冷却曲线。就像是

Tn+1=Tn+(TAmbientTn)eΔt/tBuilding

在哪里Δt是样本和之间的时间差tBuilding建筑物的热时间常数(在不同的传感器位置可能略有不同)。

您可以简单地测试每个新样本与模型预测的差异,并设置允许误差的阈值。仅有的两个模型参数是建筑物的环境温度和热时间常数。

热时间常数是建筑物热阻的函数,除非有人打开/关闭窗户或发生一些实际的结构工作,否则它实际上不会改变。查看应该易于估计的数据。您可以尝试直接使用传感器或查看可靠的天气报告来获取环境。您也可以只使用前几个传感器的数据来估计环境,然后测试其他传感器是否同意。

所以这是一种尝试,但它并不是真正基于您的“受控”部分的方式。

这个想法是使用卡尔曼滤波器将开始和结束部分建模为一阶系统(正如 Hilmar 的好答案所暗示的那样)。受控部分将与此不同。

您可以查看卡尔曼滤波器中的创新(误差项),以查看创新是噪声还是更结构化的东西。

第一个代码只是生成信号。

from numpy import log10, asarray, polyfit, ceil, arange, exp, sin, pi, log, random, sum, diff
import matplotlib.pyplot as plt



T = 1000
Ton = 300
Toff = 650


#
# First period: temperature rising or falling as a first order system.
#
# IC @ 1 = min FC @ Ton = max
# f(t) = K1 + K2 exp(-t/tau)
# f(1) = K1 + K2 exp(-1/tau) = min        (1)
# f(Ton) = K1 + K2 exp(-Ton/tau) = max    (2)
#
# (1) - (2) --> K2 ( exp(-1/tau) - exp(-Ton/tau) ) = min - max --> K2 = (min - max) / (exp(-1/tau) - exp(-Ton/tau) )
mx = 100
mn = 10
tau = 150
time_period_1 = list(arange(1,Ton))
K2 = (mn - mx) / (exp(-1/tau) - exp(-Ton/tau))
print(K2)
K1 = mn - K2*exp(-1/tau)
K1_2 = mx - K2*exp(-Ton/tau)
print(str(K1) + " " + str(K1_2))

temperature = [K1 + K2*exp(-x/tau) + random.normal(0,0.001) for x in time_period_1]

plt.figure(1)
plt.plot(time_period_1, temperature)

#
# Second period: being controlled.
#
time_period_2 = list(arange(Ton, Toff))

variation = 50
mean_value = temperature[Ton-2]
tau2 = 120

temperature2 = [variation*sin(2.0*pi*(x/100))*exp(-(x-Ton)/tau2) + mean_value for x in time_period_2]
plt.plot(time_period_2, temperature2)

#
# Third period: back to first order.
#
# IC @ Toff = last value of previous period FC @ T = mx3
# f(t) = K1 + K2 exp(-t/tau)
# f(Toff) = K1 + K2 exp(-Toff/tau) = min        (1)
# f(T) = K1 + K2 exp(-T/tau) = max              (2)
#
# (1) - (2) --> K2 ( exp(-Toff/tau) - exp(-T/tau) ) = last value - mx3
#           --> K2 = (last value - mx) / (exp(-Toff/tau) - exp(-T/tau) )
mx3 = 110
mn3 = temperature2[Toff-Ton-2]
tau2 = 50
time_period_3 = list(arange(Toff, T))

K23 = (mn3 - mx3) / (exp(-Toff/tau2) - exp(-T/tau2))
print(K23)
K13 = mn3 - K23*exp(-Toff/tau2)
K13_2 = mx3 - K23*exp(-T/tau2)
print(str(K13) + " " + str(K13_2))

temperature3 = [K13 + K23*exp(-x/tau2) for x in time_period_3]
plt.plot(time_period_3, temperature3)

all_temps = list(temperature) + list(temperature2) + list(temperature3)

plt.figure(2)
plt.plot(arange(1,T), all_temps)

然后设置卡尔曼滤波器:

import matplotlib.pyplot as plt
import numpy as np
from filterpy.kalman import KalmanFilter
from filterpy.common import Q_discrete_white_noise, Saver

dt = 0.1
r_std = 0.1
q_std = 0.1

cv = KalmanFilter(dim_x=2, dim_z=1)
cv.x = np.array([[all_temps[0]], [10.]]) # position, velocity
cv.F = np.array([[1, dt],[0, 1]])
cv.R = np.array([[r_std**2]])
cv.H = np.array([[1., 0.]])
cv.P = np.diag([.1**2, .03**2])
cv.Q = Q_discrete_white_noise(2, dt, q_std**2)

saver = Saver(cv)
for z in range(len(all_temps)):
    cv.predict()
    cv.update([all_temps[z] + random.randn()*q_std ])
    saver.save() # save the filter's state

saver.to_array()
plt.figure(figsize=(10,10))
plt.plot(saver.x[:, 0], 'b.')
plt.plot(saver.x[:, 1], 'go')
plt.plot(all_temps,'k.')

# plot all of the priors
plt.plot(saver.x_prior[:, 0], 'r+')

# plot mahalanobis distance
plt.figure()
plt.figure(figsize=(10,10))
plt.plot(saver.P[:,0,0])
plt.plot(saver.P[:,0,1])
plt.plot(saver.P[:,1,0])
plt.plot(saver.P[:,1,1])

plt.figure()
plt.figure(figsize=(10,10))
plt.plot(abs(saver.y[:,0,0]))

N = 50
smoothed_innovations = np.convolve(abs(saver.y[:,0,0]), np.ones((N,))/N, mode='valid')
plt.plot(smoothed_innovations)
threshold = np.mean(smoothed_innovations[100:200])
standard_deviation = np.std(smoothed_innovations[100:200])

plt.plot(8*(smoothed_innovations > threshold + 3*standard_deviation))

plt.savefig('Q70221.png')

结果如下所示。

尝试阈值

蓝线是创新的绝对值。橙色线是它的平滑版本。绿线表示橙色线何时高于或低于所选阈值。

不是真的 CUSUM,但我会努力让它更接近。