Spaces:
Sleeping
Sleeping
jerin
commited on
Commit
•
8e50b17
1
Parent(s):
0c3f62c
update dashbord with fault color
Browse files- dashboard.py +44 -19
- src/rtu/RTUAnomalizer1.py +12 -10
- src/rtu/RTUAnomalizer2.py +10 -8
dashboard.py
CHANGED
@@ -11,6 +11,7 @@ import mqtt_client
|
|
11 |
import time
|
12 |
from src.rtu.RTUPipeline import RTUPipeline
|
13 |
from src.rtu.RTUAnomalizer1 import RTUAnomalizer1
|
|
|
14 |
import plotly.express as px
|
15 |
|
16 |
rtu_data_pipeline = RTUPipeline(
|
@@ -38,15 +39,15 @@ rtu_anomalizers.append(
|
|
38 |
)
|
39 |
|
40 |
rtu_anomalizers.append(
|
41 |
-
|
42 |
-
prediction_model_path="src/rtu/models/
|
43 |
clustering_model_paths=[
|
44 |
-
"src/rtu/models/
|
45 |
-
"src/rtu/models/
|
46 |
],
|
47 |
pca_model_paths=[
|
48 |
-
"src/rtu/models/
|
49 |
-
"src/rtu/models/
|
50 |
],
|
51 |
num_inputs=rtu_data_pipeline.num_inputs,
|
52 |
num_outputs=rtu_data_pipeline.num_outputs,
|
@@ -159,12 +160,21 @@ for i in range(4):
|
|
159 |
|
160 |
|
161 |
# Temperatures streaming and updates
|
162 |
-
def update_status_boxes(df):
|
163 |
for i in range(4):
|
164 |
sa_temp = df[f"rtu_00{i+1}_sa_temp"].iloc[-1]
|
165 |
ra_temp = df[f"rtu_00{i+1}_ra_temp"].iloc[-1]
|
166 |
rtu_placeholders[i]["sa_temp"].markdown(f"**SA temp:** {sa_temp} °F")
|
167 |
rtu_placeholders[i]["ra_temp"].markdown(f"**RA temp:** {ra_temp} °F")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
168 |
|
169 |
|
170 |
# Zones
|
@@ -344,7 +354,7 @@ with st.container():
|
|
344 |
distances = []
|
345 |
|
346 |
|
347 |
-
def create_residual_plot(resid_pca_list, rtu_id,
|
348 |
if rtu_id % 2 == 1:
|
349 |
ax1 = 0
|
350 |
ax2 = 1
|
@@ -354,6 +364,7 @@ def create_residual_plot(resid_pca_list, rtu_id, lim=8):
|
|
354 |
fig = px.scatter(
|
355 |
x=resid_pca_list[:, ax1],
|
356 |
y=resid_pca_list[:, ax2],
|
|
|
357 |
labels={"x": "Time", "y": "Residual"},
|
358 |
width=500,
|
359 |
height=500,
|
@@ -372,7 +383,7 @@ def create_residual_plot(resid_pca_list, rtu_id, lim=8):
|
|
372 |
hoverlabel_font_color="black",
|
373 |
hoverlabel_bordercolor="lightgray",
|
374 |
)
|
375 |
-
fig.update_traces(marker=dict(size=5, color="blue"))
|
376 |
|
377 |
return fig
|
378 |
|
@@ -401,12 +412,20 @@ while True:
|
|
401 |
)
|
402 |
|
403 |
# Loop to update
|
404 |
-
|
405 |
|
406 |
dist = None
|
407 |
resid_pca_list_rtu = None
|
408 |
resid_pca_list_rtu_2 = None
|
409 |
resid_pca_list_vav_1 = None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
410 |
|
411 |
df_new1, df_trans1, df_new2, df_trans2 = rtu_data_pipeline.fit(
|
412 |
pd.DataFrame(mqtt_client.data_list)
|
@@ -430,7 +449,10 @@ while True:
|
|
430 |
resid_list,
|
431 |
resid_pca_list_rtu,
|
432 |
dist,
|
433 |
-
|
|
|
|
|
|
|
434 |
) = rtu_anomalizers[0].pipeline(
|
435 |
df_new1, df_trans1, rtu_data_pipeline.scaler1
|
436 |
)
|
@@ -440,7 +462,10 @@ while True:
|
|
440 |
resid_list_2,
|
441 |
resid_pca_list_rtu_2,
|
442 |
dist_2,
|
443 |
-
|
|
|
|
|
|
|
444 |
) = rtu_anomalizers[1].pipeline(
|
445 |
df_new1, df_trans1, rtu_data_pipeline.scaler1
|
446 |
)
|
@@ -464,31 +489,31 @@ while True:
|
|
464 |
resid_rtu1_placeholder, resid_rtu2_placeholder = st.columns(2)
|
465 |
with resid_rtu1_placeholder:
|
466 |
st.subheader("RTU 1 Residuals")
|
467 |
-
fig = create_residual_plot(resid_pca_list_rtu, rtu_id=1)
|
468 |
st.plotly_chart(fig)
|
469 |
|
470 |
with resid_rtu2_placeholder:
|
471 |
st.subheader("RTU 2 Residuals")
|
472 |
-
fig = create_residual_plot(resid_pca_list_rtu, rtu_id=2)
|
473 |
st.plotly_chart(fig)
|
474 |
|
475 |
resid_rtu3_placeholder, resid_rtu4_placeholder = st.columns(2)
|
476 |
with resid_rtu3_placeholder:
|
477 |
st.subheader("RTU 3 Residuals")
|
478 |
-
fig = create_residual_plot(resid_pca_list_rtu, rtu_id=3)
|
479 |
st.plotly_chart(fig)
|
480 |
|
481 |
with resid_rtu4_placeholder:
|
482 |
st.subheader("RTU 4 Residuals")
|
483 |
-
fig = create_residual_plot(resid_pca_list_rtu, rtu_id=4)
|
484 |
st.plotly_chart(fig)
|
485 |
|
486 |
if resid_pca_list_vav_1 is not None:
|
487 |
-
print(resid_pca_list_vav_1)
|
488 |
with resid_vav_placeholder.container():
|
489 |
st.subheader("VAV 1 Residuals")
|
490 |
fig = create_residual_plot(
|
491 |
-
np.array(resid_pca_list_vav_1), rtu_id=1, lim=15
|
492 |
)
|
493 |
st.plotly_chart(fig)
|
494 |
|
@@ -507,5 +532,5 @@ while True:
|
|
507 |
# ax.set_xlabel("Time")
|
508 |
# ax.set_ylabel("Energy (kWh)")
|
509 |
# st.pyplot(fig)
|
510 |
-
|
511 |
mqtt_client.data_list.clear()
|
|
|
11 |
import time
|
12 |
from src.rtu.RTUPipeline import RTUPipeline
|
13 |
from src.rtu.RTUAnomalizer1 import RTUAnomalizer1
|
14 |
+
from src.rtu.RTUAnomalizer2 import RTUAnomalizer2
|
15 |
import plotly.express as px
|
16 |
|
17 |
rtu_data_pipeline = RTUPipeline(
|
|
|
39 |
)
|
40 |
|
41 |
rtu_anomalizers.append(
|
42 |
+
RTUAnomalizer2(
|
43 |
+
prediction_model_path="src/rtu/models/lstm_2rtu_smooth_03.keras",
|
44 |
clustering_model_paths=[
|
45 |
+
"src/rtu/models/kmeans_rtu_3.pkl",
|
46 |
+
"src/rtu/models/kmeans_rtu_4.pkl",
|
47 |
],
|
48 |
pca_model_paths=[
|
49 |
+
"src/rtu/models/pca_rtu_3.pkl",
|
50 |
+
"src/rtu/models/pca_rtu_4.pkl",
|
51 |
],
|
52 |
num_inputs=rtu_data_pipeline.num_inputs,
|
53 |
num_outputs=rtu_data_pipeline.num_outputs,
|
|
|
160 |
|
161 |
|
162 |
# Temperatures streaming and updates
|
163 |
+
def update_status_boxes(df,fault):
|
164 |
for i in range(4):
|
165 |
sa_temp = df[f"rtu_00{i+1}_sa_temp"].iloc[-1]
|
166 |
ra_temp = df[f"rtu_00{i+1}_ra_temp"].iloc[-1]
|
167 |
rtu_placeholders[i]["sa_temp"].markdown(f"**SA temp:** {sa_temp} °F")
|
168 |
rtu_placeholders[i]["ra_temp"].markdown(f"**RA temp:** {ra_temp} °F")
|
169 |
+
if fault[i]== 1:
|
170 |
+
rtu_placeholders[i]["box"].markdown(
|
171 |
+
f"""
|
172 |
+
<div style='background-color:#ff4d4d;padding:3px;border-radius:5px;margin-bottom:10px'>
|
173 |
+
<h4 style='color:black;text-align:center;'>RTU{i+1}</h4>
|
174 |
+
</div>
|
175 |
+
""",
|
176 |
+
unsafe_allow_html=True,
|
177 |
+
)
|
178 |
|
179 |
|
180 |
# Zones
|
|
|
354 |
distances = []
|
355 |
|
356 |
|
357 |
+
def create_residual_plot(resid_pca_list, distance, rtu_id,lim=8):
|
358 |
if rtu_id % 2 == 1:
|
359 |
ax1 = 0
|
360 |
ax2 = 1
|
|
|
364 |
fig = px.scatter(
|
365 |
x=resid_pca_list[:, ax1],
|
366 |
y=resid_pca_list[:, ax2],
|
367 |
+
color=distance,
|
368 |
labels={"x": "Time", "y": "Residual"},
|
369 |
width=500,
|
370 |
height=500,
|
|
|
383 |
hoverlabel_font_color="black",
|
384 |
hoverlabel_bordercolor="lightgray",
|
385 |
)
|
386 |
+
# fig.update_traces(marker=dict(size=5, color="blue"))
|
387 |
|
388 |
return fig
|
389 |
|
|
|
412 |
)
|
413 |
|
414 |
# Loop to update
|
415 |
+
|
416 |
|
417 |
dist = None
|
418 |
resid_pca_list_rtu = None
|
419 |
resid_pca_list_rtu_2 = None
|
420 |
resid_pca_list_vav_1 = None
|
421 |
+
rtu_1_distance = None
|
422 |
+
rtu_2_distance = None
|
423 |
+
fault_1 = None
|
424 |
+
fault_2 = None
|
425 |
+
rtu_3_distance = None
|
426 |
+
rtu_4_distance = None
|
427 |
+
fault_3 = None
|
428 |
+
fault_4 = None
|
429 |
|
430 |
df_new1, df_trans1, df_new2, df_trans2 = rtu_data_pipeline.fit(
|
431 |
pd.DataFrame(mqtt_client.data_list)
|
|
|
449 |
resid_list,
|
450 |
resid_pca_list_rtu,
|
451 |
dist,
|
452 |
+
rtu_1_distance,
|
453 |
+
rtu_2_distance,
|
454 |
+
fault_1,
|
455 |
+
fault_2
|
456 |
) = rtu_anomalizers[0].pipeline(
|
457 |
df_new1, df_trans1, rtu_data_pipeline.scaler1
|
458 |
)
|
|
|
462 |
resid_list_2,
|
463 |
resid_pca_list_rtu_2,
|
464 |
dist_2,
|
465 |
+
rtu_3_distance,
|
466 |
+
rtu_4_distance,
|
467 |
+
fault_3,
|
468 |
+
fault_4
|
469 |
) = rtu_anomalizers[1].pipeline(
|
470 |
df_new1, df_trans1, rtu_data_pipeline.scaler1
|
471 |
)
|
|
|
489 |
resid_rtu1_placeholder, resid_rtu2_placeholder = st.columns(2)
|
490 |
with resid_rtu1_placeholder:
|
491 |
st.subheader("RTU 1 Residuals")
|
492 |
+
fig = create_residual_plot(resid_pca_list_rtu, rtu_1_distance, rtu_id=1)
|
493 |
st.plotly_chart(fig)
|
494 |
|
495 |
with resid_rtu2_placeholder:
|
496 |
st.subheader("RTU 2 Residuals")
|
497 |
+
fig = create_residual_plot(resid_pca_list_rtu, rtu_2_distance, rtu_id=2)
|
498 |
st.plotly_chart(fig)
|
499 |
|
500 |
resid_rtu3_placeholder, resid_rtu4_placeholder = st.columns(2)
|
501 |
with resid_rtu3_placeholder:
|
502 |
st.subheader("RTU 3 Residuals")
|
503 |
+
fig = create_residual_plot(resid_pca_list_rtu, rtu_3_distance, rtu_id=3)
|
504 |
st.plotly_chart(fig)
|
505 |
|
506 |
with resid_rtu4_placeholder:
|
507 |
st.subheader("RTU 4 Residuals")
|
508 |
+
fig = create_residual_plot(resid_pca_list_rtu, rtu_4_distance, rtu_id=4)
|
509 |
st.plotly_chart(fig)
|
510 |
|
511 |
if resid_pca_list_vav_1 is not None:
|
512 |
+
# print(resid_pca_list_vav_1)
|
513 |
with resid_vav_placeholder.container():
|
514 |
st.subheader("VAV 1 Residuals")
|
515 |
fig = create_residual_plot(
|
516 |
+
np.array(resid_pca_list_vav_1),rtu_4_distance, rtu_id=1, lim=15
|
517 |
)
|
518 |
st.plotly_chart(fig)
|
519 |
|
|
|
532 |
# ax.set_xlabel("Time")
|
533 |
# ax.set_ylabel("Energy (kWh)")
|
534 |
# st.pyplot(fig)
|
535 |
+
update_status_boxes(df,[fault_1,fault_2,fault_3,fault_4])
|
536 |
mqtt_client.data_list.clear()
|
src/rtu/RTUAnomalizer1.py
CHANGED
@@ -44,8 +44,8 @@ class RTUAnomalizer1:
|
|
44 |
self.initialize_lists()
|
45 |
)
|
46 |
|
47 |
-
self.fault_1 =
|
48 |
-
self.fault_2 =
|
49 |
|
50 |
def initialize_lists(self, size=30):
|
51 |
"""
|
@@ -59,7 +59,7 @@ class RTUAnomalizer1:
|
|
59 |
"""
|
60 |
initial_values = [[0] * self.num_outputs] * size
|
61 |
initial_values1 = [[0] * 4] * size
|
62 |
-
initial_values2 = [[0] * 2] *
|
63 |
return (
|
64 |
initial_values.copy(),
|
65 |
initial_values.copy(),
|
@@ -197,8 +197,8 @@ class RTUAnomalizer1:
|
|
197 |
axis=1,
|
198 |
)
|
199 |
)
|
200 |
-
|
201 |
-
|
202 |
resid_pcas = np.array(resid_pcas).flatten().tolist()
|
203 |
self.resid_pca_list.pop(0)
|
204 |
self.resid_pca_list.append(resid_pcas)
|
@@ -206,12 +206,14 @@ class RTUAnomalizer1:
|
|
206 |
return np.array(dist)
|
207 |
def fault_windowing(self):
|
208 |
rtu_1_dist = np.array(self.distance_list).T[0]>1 #rtu_1_threshold
|
209 |
-
|
|
|
210 |
self.fault_1 = 1
|
211 |
else:
|
212 |
self.fault_1 = 0
|
213 |
-
rtu_2_dist = np.array(self.distance_list).T[1]>
|
214 |
-
|
|
|
215 |
self.fault_2 = 1
|
216 |
else:
|
217 |
self.fault_2 = 0
|
@@ -235,7 +237,7 @@ class RTUAnomalizer1:
|
|
235 |
actual, pred = self.inverse_transform(scaler, pred, df_trans)
|
236 |
actual_list, pred_list, resid_list = self.update_lists(actual, pred, resid)
|
237 |
dist = self.calculate_distances(resid)
|
238 |
-
|
239 |
return (
|
240 |
actual_list,
|
241 |
pred_list,
|
@@ -243,7 +245,7 @@ class RTUAnomalizer1:
|
|
243 |
self.resid_pca_list,
|
244 |
dist,
|
245 |
np.array(self.distance_list[30:]).T[0]>1, #rtu_1_threshold
|
246 |
-
np.array(self.distance_list[30:]).T[1]>
|
247 |
self.fault_1,
|
248 |
self.fault_2
|
249 |
)
|
|
|
44 |
self.initialize_lists()
|
45 |
)
|
46 |
|
47 |
+
self.fault_1 = 0
|
48 |
+
self.fault_2 = 0
|
49 |
|
50 |
def initialize_lists(self, size=30):
|
51 |
"""
|
|
|
59 |
"""
|
60 |
initial_values = [[0] * self.num_outputs] * size
|
61 |
initial_values1 = [[0] * 4] * size
|
62 |
+
initial_values2 = [[0] * 2] * 60
|
63 |
return (
|
64 |
initial_values.copy(),
|
65 |
initial_values.copy(),
|
|
|
197 |
axis=1,
|
198 |
)
|
199 |
)
|
200 |
+
self.distance_list.pop(0)
|
201 |
+
self.distance_list.append(np.concatenate(dist).tolist())
|
202 |
resid_pcas = np.array(resid_pcas).flatten().tolist()
|
203 |
self.resid_pca_list.pop(0)
|
204 |
self.resid_pca_list.append(resid_pcas)
|
|
|
206 |
return np.array(dist)
|
207 |
def fault_windowing(self):
|
208 |
rtu_1_dist = np.array(self.distance_list).T[0]>1 #rtu_1_threshold
|
209 |
+
rtu_1_dist = [int(x) for x in rtu_1_dist]
|
210 |
+
if sum(rtu_1_dist)>0.8*60: # 80% of the 60 min window
|
211 |
self.fault_1 = 1
|
212 |
else:
|
213 |
self.fault_1 = 0
|
214 |
+
rtu_2_dist = np.array(self.distance_list).T[1]>0.5 #rtu_2_threshold
|
215 |
+
rtu_2_dist = [int(x) for x in rtu_2_dist]
|
216 |
+
if sum(rtu_2_dist)>0.05*60: # 80% of the 60 min window
|
217 |
self.fault_2 = 1
|
218 |
else:
|
219 |
self.fault_2 = 0
|
|
|
237 |
actual, pred = self.inverse_transform(scaler, pred, df_trans)
|
238 |
actual_list, pred_list, resid_list = self.update_lists(actual, pred, resid)
|
239 |
dist = self.calculate_distances(resid)
|
240 |
+
self.fault_windowing()
|
241 |
return (
|
242 |
actual_list,
|
243 |
pred_list,
|
|
|
245 |
self.resid_pca_list,
|
246 |
dist,
|
247 |
np.array(self.distance_list[30:]).T[0]>1, #rtu_1_threshold
|
248 |
+
np.array(self.distance_list[30:]).T[1]>0.5, #rtu_2_threshold
|
249 |
self.fault_1,
|
250 |
self.fault_2
|
251 |
)
|
src/rtu/RTUAnomalizer2.py
CHANGED
@@ -3,7 +3,7 @@ from tensorflow.keras.models import load_model
|
|
3 |
import joblib
|
4 |
|
5 |
|
6 |
-
class
|
7 |
"""
|
8 |
Class for performing anomaly detection on RTU (Roof Top Unit) data.
|
9 |
"""
|
@@ -44,8 +44,8 @@ class RTUAnomalizer1:
|
|
44 |
self.initialize_lists()
|
45 |
)
|
46 |
|
47 |
-
self.fault_1 =
|
48 |
-
self.fault_2 =
|
49 |
|
50 |
def initialize_lists(self, size=30):
|
51 |
"""
|
@@ -197,8 +197,8 @@ class RTUAnomalizer1:
|
|
197 |
axis=1,
|
198 |
)
|
199 |
)
|
200 |
-
|
201 |
-
|
202 |
resid_pcas = np.array(resid_pcas).flatten().tolist()
|
203 |
self.resid_pca_list.pop(0)
|
204 |
self.resid_pca_list.append(resid_pcas)
|
@@ -206,12 +206,14 @@ class RTUAnomalizer1:
|
|
206 |
return np.array(dist)
|
207 |
def fault_windowing(self):
|
208 |
rtu_1_dist = np.array(self.distance_list).T[0]>1.5 #rtu_3_threshold
|
209 |
-
|
|
|
210 |
self.fault_1 = 1
|
211 |
else:
|
212 |
self.fault_1 = 0
|
213 |
rtu_2_dist = np.array(self.distance_list).T[1]>1.5 #rtu_4_threshold
|
214 |
-
|
|
|
215 |
self.fault_2 = 1
|
216 |
else:
|
217 |
self.fault_2 = 0
|
@@ -235,7 +237,7 @@ class RTUAnomalizer1:
|
|
235 |
actual, pred = self.inverse_transform(scaler, pred, df_trans)
|
236 |
actual_list, pred_list, resid_list = self.update_lists(actual, pred, resid)
|
237 |
dist = self.calculate_distances(resid)
|
238 |
-
|
239 |
return (
|
240 |
actual_list,
|
241 |
pred_list,
|
|
|
3 |
import joblib
|
4 |
|
5 |
|
6 |
+
class RTUAnomalizer2:
|
7 |
"""
|
8 |
Class for performing anomaly detection on RTU (Roof Top Unit) data.
|
9 |
"""
|
|
|
44 |
self.initialize_lists()
|
45 |
)
|
46 |
|
47 |
+
self.fault_1 = 0
|
48 |
+
self.fault_2 = 0
|
49 |
|
50 |
def initialize_lists(self, size=30):
|
51 |
"""
|
|
|
197 |
axis=1,
|
198 |
)
|
199 |
)
|
200 |
+
self.distance_list.pop(0)
|
201 |
+
self.distance_list.append(np.concatenate(dist).tolist())
|
202 |
resid_pcas = np.array(resid_pcas).flatten().tolist()
|
203 |
self.resid_pca_list.pop(0)
|
204 |
self.resid_pca_list.append(resid_pcas)
|
|
|
206 |
return np.array(dist)
|
207 |
def fault_windowing(self):
|
208 |
rtu_1_dist = np.array(self.distance_list).T[0]>1.5 #rtu_3_threshold
|
209 |
+
rtu_1_dist = [int(x) for x in rtu_1_dist]
|
210 |
+
if sum(rtu_1_dist)>0.8*60: # 80% of the 60 min window
|
211 |
self.fault_1 = 1
|
212 |
else:
|
213 |
self.fault_1 = 0
|
214 |
rtu_2_dist = np.array(self.distance_list).T[1]>1.5 #rtu_4_threshold
|
215 |
+
rtu_2_dist = [int(x) for x in rtu_2_dist]
|
216 |
+
if sum(rtu_2_dist)>0.8*60: # 80% of the 60 min window
|
217 |
self.fault_2 = 1
|
218 |
else:
|
219 |
self.fault_2 = 0
|
|
|
237 |
actual, pred = self.inverse_transform(scaler, pred, df_trans)
|
238 |
actual_list, pred_list, resid_list = self.update_lists(actual, pred, resid)
|
239 |
dist = self.calculate_distances(resid)
|
240 |
+
self.fault_windowing()
|
241 |
return (
|
242 |
actual_list,
|
243 |
pred_list,
|