|
@@ -55,8 +55,8 @@ class MSET_Temp:
|
|
"""
|
|
"""
|
|
table_name = f"{self.windCode}_minute"
|
|
table_name = f"{self.windCode}_minute"
|
|
engine = create_engine(
|
|
engine = create_engine(
|
|
- # "mysql+pymysql://root:admin123456@106.120.102.238:10336/energy_data_prod"
|
|
|
|
- "mysql+pymysql://root:admin123456@192.168.50.235:30306/energy_data_prod"
|
|
|
|
|
|
+ "mysql+pymysql://root:admin123456@106.120.102.238:10336/energy_data_prod"
|
|
|
|
+ # "mysql+pymysql://root:admin123456@192.168.50.235:30306/energy_data_prod"
|
|
)
|
|
)
|
|
|
|
|
|
# 准备 wind_turbine_number 列表的 SQL 片段:('WT1','WT2',...)
|
|
# 准备 wind_turbine_number 列表的 SQL 片段:('WT1','WT2',...)
|
|
@@ -203,199 +203,103 @@ class MSET_Temp:
|
|
|
|
|
|
def check_threshold(self) -> pd.DataFrame:
|
|
def check_threshold(self) -> pd.DataFrame:
|
|
"""
|
|
"""
|
|
- 阈值分析(阈值固定 0.99)。返回长格式 DataFrame,列:
|
|
|
|
- ["time_stamp", "temp_channel", "SPRT_score", "status"]
|
|
|
|
- status = "危险" if SPRT_score > 0.99 else "正常"。
|
|
|
|
|
|
+ 阈值分析(阈值 0.99),长格式:
|
|
|
|
+ 返回所有存在通道的数据,缺失的通道自动跳过。
|
|
"""
|
|
"""
|
|
THRESHOLD = 0.99
|
|
THRESHOLD = 0.99
|
|
-
|
|
|
|
- # 1) 按风机编号 + 时间范围查询原始数据
|
|
|
|
- df_concat = self._get_data_by_filter()
|
|
|
|
- if df_concat.empty:
|
|
|
|
|
|
+ df = self._get_data_by_filter()
|
|
|
|
+ if df.empty:
|
|
return pd.DataFrame(columns=["time_stamp", "temp_channel", "SPRT_score", "status"])
|
|
return pd.DataFrame(columns=["time_stamp", "temp_channel", "SPRT_score", "status"])
|
|
|
|
|
|
- # 2) 筛选存在的温度列
|
|
|
|
|
|
+ # 四个通道英文名
|
|
temp_cols_all = [
|
|
temp_cols_all = [
|
|
'main_bearing_temperature',
|
|
'main_bearing_temperature',
|
|
'gearbox_oil_temperature',
|
|
'gearbox_oil_temperature',
|
|
'generatordrive_end_bearing_temperature',
|
|
'generatordrive_end_bearing_temperature',
|
|
'generatornon_drive_end_bearing_temperature'
|
|
'generatornon_drive_end_bearing_temperature'
|
|
]
|
|
]
|
|
- temp_cols = [c for c in temp_cols_all if c in df_concat.columns]
|
|
|
|
|
|
+ # 只保留存在的列
|
|
|
|
+ temp_cols = [c for c in temp_cols_all if c in df.columns]
|
|
if not temp_cols:
|
|
if not temp_cols:
|
|
return pd.DataFrame(columns=["time_stamp", "temp_channel", "SPRT_score", "status"])
|
|
return pd.DataFrame(columns=["time_stamp", "temp_channel", "SPRT_score", "status"])
|
|
|
|
|
|
- # 3) 转数值 & 删除 NaN
|
|
|
|
- df_concat[temp_cols] = df_concat[temp_cols].apply(pd.to_numeric, errors='coerce')
|
|
|
|
- df_concat = df_concat.dropna(subset=temp_cols + ['time_stamp'])
|
|
|
|
- if df_concat.empty:
|
|
|
|
- return pd.DataFrame(columns=["time_stamp", "temp_channel", "SPRT_score", "status"])
|
|
|
|
-
|
|
|
|
- # 4) time_stamp 转 datetime
|
|
|
|
- df_concat['time_stamp'] = pd.to_datetime(df_concat['time_stamp'])
|
|
|
|
- x_date = df_concat['time_stamp']
|
|
|
|
-
|
|
|
|
- # 5) 抽取温度列到 NumPy 数组
|
|
|
|
- arr = df_concat[temp_cols].values # shape = [总记录数, 通道数]
|
|
|
|
- m, n = arr.shape
|
|
|
|
- half = m // 2
|
|
|
|
-
|
|
|
|
- all_flags: list[list[float]] = []
|
|
|
|
- for i in range(n):
|
|
|
|
- channel = arr[:, i]
|
|
|
|
- train = channel[:half].reshape(-1, 1)
|
|
|
|
- test = channel[half:].reshape(-1, 1)
|
|
|
|
-
|
|
|
|
- # 用训练集构造 D/L 矩阵
|
|
|
|
- if self.genDLMatrix(train, dataSize4D=60, dataSize4L=5) != 0:
|
|
|
|
- # 如果训练集样本不足,直接返回空表
|
|
|
|
- return pd.DataFrame(columns=["time_stamp", "temp_channel", "SPRT_score", "status"])
|
|
|
|
-
|
|
|
|
- feature_w = np.array([1.0])
|
|
|
|
- flags = self.calcSPRT(test, feature_w, decisionGroup=1)
|
|
|
|
- all_flags.append(flags)
|
|
|
|
-
|
|
|
|
- # 6) 合并为宽表,再 melt 成长表
|
|
|
|
- flags_arr = np.array(all_flags) # shape = [通道数, 测试样本数]
|
|
|
|
- num_test = flags_arr.shape[1]
|
|
|
|
- ts = x_date.iloc[half : half + num_test].reset_index(drop=True)
|
|
|
|
-
|
|
|
|
- wide = pd.DataFrame({"time_stamp": ts})
|
|
|
|
- for idx, col in enumerate(temp_cols):
|
|
|
|
- wide[col] = flags_arr[idx, :]
|
|
|
|
-
|
|
|
|
- df_long = wide.melt(
|
|
|
|
- id_vars=["time_stamp"],
|
|
|
|
- value_vars=temp_cols,
|
|
|
|
- var_name="temp_channel",
|
|
|
|
- value_name="SPRT_score"
|
|
|
|
- )
|
|
|
|
- # 把 time_stamp 从 datetime 转成字符串,格式 "YYYY-MM-DD HH:MM:SS"
|
|
|
|
- df_long['time_stamp'] = pd.to_datetime(df_long['time_stamp']).dt.strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
-
|
|
|
|
- # 7) 添加状态列:SPRT_score > 0.99 → “危险”,否则 “正常”
|
|
|
|
- df_long['status'] = df_long['SPRT_score'].apply(
|
|
|
|
- lambda x: "危险" if x > THRESHOLD else "正常"
|
|
|
|
- )
|
|
|
|
-
|
|
|
|
- # 8) 将 temp_channel 列的英文名称改为中文
|
|
|
|
- temp_channel_mapping = {
|
|
|
|
|
|
+ # 转数值 & 时间
|
|
|
|
+ df[temp_cols] = df[temp_cols].apply(pd.to_numeric, errors='coerce')
|
|
|
|
+ df['time_stamp'] = pd.to_datetime(df['time_stamp'], errors='coerce')
|
|
|
|
+ records = []
|
|
|
|
+ # 英文→中文映射
|
|
|
|
+ cn_map = {
|
|
'main_bearing_temperature': '主轴承温度',
|
|
'main_bearing_temperature': '主轴承温度',
|
|
'gearbox_oil_temperature': '齿轮箱油温',
|
|
'gearbox_oil_temperature': '齿轮箱油温',
|
|
'generatordrive_end_bearing_temperature': '发电机驱动端轴承温度',
|
|
'generatordrive_end_bearing_temperature': '发电机驱动端轴承温度',
|
|
'generatornon_drive_end_bearing_temperature': '发电机非驱动端轴承温度'
|
|
'generatornon_drive_end_bearing_temperature': '发电机非驱动端轴承温度'
|
|
}
|
|
}
|
|
|
|
|
|
- df_long['temp_channel'] = df_long['temp_channel'].map(temp_channel_mapping)
|
|
|
|
|
|
+ for col in temp_cols:
|
|
|
|
+ sub = df[['time_stamp', col]].dropna()
|
|
|
|
+ if sub.empty:
|
|
|
|
+ continue
|
|
|
|
+ arr = sub[col].values.reshape(-1,1)
|
|
|
|
+ ts = sub['time_stamp'].dt.strftime("%Y-%m-%d %H:%M:%S").tolist()
|
|
|
|
+ half = len(arr) // 2
|
|
|
|
+ train = arr[:half]
|
|
|
|
+ test = arr[half:]
|
|
|
|
+ # 不足则跳过该通道
|
|
|
|
+ if self.genDLMatrix(train, dataSize4D=60, dataSize4L=5) != 0:
|
|
|
|
+ continue
|
|
|
|
+
|
|
|
|
+ flags = self.calcSPRT(test, np.array([1.0]), decisionGroup=1)
|
|
|
|
+ for i, score in enumerate(flags):
|
|
|
|
+ records.append({
|
|
|
|
+ "time_stamp": ts[half + i],
|
|
|
|
+ "temp_channel": cn_map[col],
|
|
|
|
+ "SPRT_score": score,
|
|
|
|
+ "status": "危险" if score > THRESHOLD else "正常"
|
|
|
|
+ })
|
|
|
|
|
|
- return df_long
|
|
|
|
-
|
|
|
|
|
|
+ return pd.DataFrame(records, columns=["time_stamp", "temp_channel", "SPRT_score", "status"])
|
|
|
|
|
|
def get_trend(self) -> dict:
|
|
def get_trend(self) -> dict:
|
|
"""
|
|
"""
|
|
- 趋势分析(SPRT_score)
|
|
|
|
|
|
+ 趋势分析:对每个通道单独计算,缺失或训练不足时输出空结构。
|
|
"""
|
|
"""
|
|
- # 1) 按风机编号 + 时间范围查询原始数据
|
|
|
|
df = self._get_data_by_filter()
|
|
df = self._get_data_by_filter()
|
|
- # 如果没有任何数据,则四通道均为空
|
|
|
|
- if df.empty:
|
|
|
|
- return {
|
|
|
|
- "data": {
|
|
|
|
- "main_bearing": {},
|
|
|
|
- "gearbox_oil": {},
|
|
|
|
- "generator_drive_end": {},
|
|
|
|
- "generator_nondrive_end": {}
|
|
|
|
- },
|
|
|
|
- "code": 200,
|
|
|
|
- "message": "success"
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- # 2) 筛选存在的温度列
|
|
|
|
- temp_cols_all = [
|
|
|
|
- 'main_bearing_temperature',
|
|
|
|
- 'gearbox_oil_temperature',
|
|
|
|
- 'generatordrive_end_bearing_temperature',
|
|
|
|
- 'generatornon_drive_end_bearing_temperature'
|
|
|
|
- ]
|
|
|
|
- temp_cols = [c for c in temp_cols_all if c in df.columns]
|
|
|
|
- if not temp_cols:
|
|
|
|
- return {
|
|
|
|
- "data": {
|
|
|
|
- "main_bearing": {},
|
|
|
|
- "gearbox_oil": {},
|
|
|
|
- "generator_drive_end": {},
|
|
|
|
- "generator_nondrive_end": {}
|
|
|
|
- },
|
|
|
|
- "code": 200,
|
|
|
|
- "message": "success"
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- # 3) 转数值 & 删除 NaN
|
|
|
|
- df[temp_cols] = df[temp_cols].apply(pd.to_numeric, errors='coerce')
|
|
|
|
- df = df.dropna(subset=temp_cols + ['time_stamp'])
|
|
|
|
- if df.empty:
|
|
|
|
- return {
|
|
|
|
- "data": {
|
|
|
|
- "main_bearing": {},
|
|
|
|
- "gearbox_oil": {},
|
|
|
|
- "generator_drive_end": {},
|
|
|
|
- "generator_nondrive_end": {}
|
|
|
|
- },
|
|
|
|
- "code": 200,
|
|
|
|
- "message": "success"
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- # 4) time_stamp 转 datetime 并排序
|
|
|
|
- df['time_stamp'] = pd.to_datetime(df['time_stamp'])
|
|
|
|
- df = df.sort_values('time_stamp').reset_index(drop=True)
|
|
|
|
-
|
|
|
|
- # 5) 准备后半段时间戳列表
|
|
|
|
- all_timestamps = df['time_stamp'].dt.strftime("%Y-%m-%d %H:%M:%S").tolist()
|
|
|
|
- half = len(all_timestamps) // 2
|
|
|
|
- trend_timestamps = all_timestamps[half:]
|
|
|
|
-
|
|
|
|
- # 6) 计算每个通道的 SPRT_score
|
|
|
|
- # 中文映射(如果需要保留中文名称可在这儿用,但输出不用)
|
|
|
|
- # temp_channel_mapping = { ... }
|
|
|
|
-
|
|
|
|
- # 初始化四通道输出结构,默认空对象
|
|
|
|
- result_data = {
|
|
|
|
- "main_bearing": {},
|
|
|
|
- "gearbox_oil": {},
|
|
|
|
- "generator_drive_end": {},
|
|
|
|
- "generator_nondrive_end": {}
|
|
|
|
- }
|
|
|
|
- # key 映射:DataFrame 列名 -> 输出字段名
|
|
|
|
|
|
+ # 英文→输出字段名
|
|
key_map = {
|
|
key_map = {
|
|
'main_bearing_temperature': 'main_bearing',
|
|
'main_bearing_temperature': 'main_bearing',
|
|
'gearbox_oil_temperature': 'gearbox_oil',
|
|
'gearbox_oil_temperature': 'gearbox_oil',
|
|
'generatordrive_end_bearing_temperature': 'generator_drive_end',
|
|
'generatordrive_end_bearing_temperature': 'generator_drive_end',
|
|
'generatornon_drive_end_bearing_temperature': 'generator_nondrive_end'
|
|
'generatornon_drive_end_bearing_temperature': 'generator_nondrive_end'
|
|
}
|
|
}
|
|
|
|
+ # 预置结果
|
|
|
|
+ result = {v: {} for v in key_map.values()}
|
|
|
|
|
|
- for col in temp_cols:
|
|
|
|
- series = df[col].values
|
|
|
|
- train = series[:half].reshape(-1, 1)
|
|
|
|
- test = series[half:].reshape(-1, 1)
|
|
|
|
-
|
|
|
|
- # 生成 DL 矩阵并计算 SPRT
|
|
|
|
|
|
+ if df.empty:
|
|
|
|
+ return {"data": result, "code": 200, "message": "success"}
|
|
|
|
+
|
|
|
|
+ df['time_stamp'] = pd.to_datetime(df['time_stamp'], errors='coerce')
|
|
|
|
+ for col, out_key in key_map.items():
|
|
|
|
+ if col not in df.columns:
|
|
|
|
+ continue
|
|
|
|
+ sub = df[['time_stamp', col]].dropna()
|
|
|
|
+ if sub.empty:
|
|
|
|
+ continue
|
|
|
|
+ vals = pd.to_numeric(sub[col], errors='coerce').values
|
|
|
|
+ ts_list = sub['time_stamp'].dt.strftime("%Y-%m-%d %H:%M:%S").tolist()
|
|
|
|
+ half = len(vals) // 2
|
|
|
|
+ train = vals[:half].reshape(-1,1)
|
|
|
|
+ test = vals[half:].reshape(-1,1)
|
|
|
|
+ # 训练不足时输出空列表
|
|
if self.genDLMatrix(train, dataSize4D=60, dataSize4L=5) != 0:
|
|
if self.genDLMatrix(train, dataSize4D=60, dataSize4L=5) != 0:
|
|
- flags = [None] * len(test)
|
|
|
|
|
|
+ flags = []
|
|
else:
|
|
else:
|
|
flags = self.calcSPRT(test, np.array([1.0]), decisionGroup=1)
|
|
flags = self.calcSPRT(test, np.array([1.0]), decisionGroup=1)
|
|
-
|
|
|
|
- # 填充对应 key
|
|
|
|
- key = key_map[col]
|
|
|
|
- result_data[key] = {
|
|
|
|
- "timestamps": trend_timestamps,
|
|
|
|
|
|
+ result[out_key] = {
|
|
|
|
+ "timestamps": ts_list[half:],
|
|
"values": flags
|
|
"values": flags
|
|
}
|
|
}
|
|
|
|
|
|
- return {
|
|
|
|
- "data": result_data,
|
|
|
|
- "code": 200,
|
|
|
|
- "message": "success"
|
|
|
|
- }
|
|
|
|
|
|
+ return {"data": result, "code": 200, "message": "success"}
|
|
|
|
|
|
|
|
|
|
# def get_trend(self) -> dict:
|
|
# def get_trend(self) -> dict:
|