CMSAnalyst.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593
  1. import ast
  2. import json
  3. import math
  4. import numpy as np
  5. import pandas as pd
  6. from scipy.signal import hilbert
  7. from app.config import dataBase
  8. from app.database import get_engine
  9. from app.logger import logger
  10. class CMSAnalyst:
  11. def __init__(self, fmin, fmax, table_name, ids):
  12. # 从数据库获取原始数据
  13. self.datas = self._get_by_id(table_name, ids)
  14. self.datas = [df[['mesure_data', 'time_stamp', 'sampling_frequency', 'wind_turbine_number', 'rotational_speed',
  15. 'mesure_point_name']] for df in self.datas]
  16. # 只输入一个id,返回一个[df],所以拿到self.data[0]
  17. self.data_filter = self.datas[0]
  18. # 取数据列
  19. self.data = np.array(ast.literal_eval(self.data_filter['mesure_data'][0]))
  20. self.envelope_spectrum_m = self.data.shape[0]
  21. self.envelope_spectrum_n = 1
  22. # 设置分析参数
  23. self.fs = int(self.data_filter['sampling_frequency'].iloc[0])
  24. self.envelope_spectrum_t = np.arange(self.envelope_spectrum_m) / self.fs
  25. self.fmin = fmin if fmin is not None else 0
  26. self.fmax = fmax if fmax is not None else float('inf')
  27. self.envelope_spectrum_y = self._bandpass_filter(self.data)
  28. self.f, self.HP = self._calculate_envelope_spectrum(self.envelope_spectrum_y)
  29. # 设备信息
  30. self.wind_code = self.data_filter['wind_turbine_number'].iloc[0]
  31. self.rpm_Gen = self.data_filter['rotational_speed'].iloc[0]
  32. self.mesure_point_name = self.data_filter['mesure_point_name'].iloc[0]
  33. self.fn_Gen = round(self.rpm_Gen / 60, 2)
  34. self.CF = self.Characteristic_Frequency()
  35. self.CF = pd.DataFrame(self.CF, index=[0])
  36. n_rolls_m = self.CF['n_rolls'].iloc[0]
  37. d_rolls_m = self.CF['d_rolls'].iloc[0]
  38. D_diameter_m = self.CF['D_diameter'].iloc[0]
  39. theta_deg_m = self.CF['theta_deg'].iloc[0]
  40. self.bearing_frequencies = self.calculate_bearing_frequencies(n_rolls_m, d_rolls_m, D_diameter_m, theta_deg_m,
  41. self.rpm_Gen)
  42. self.bearing_frequencies = pd.DataFrame(self.bearing_frequencies, index=[0])
  43. # frequency_domain_analysis
  44. (
  45. self.frequency_domain_analysis_t,
  46. self.frequency_domain_analysis_f,
  47. self.frequency_domain_analysis_m,
  48. self.frequency_domain_analysis_mag,
  49. self.frequency_domain_analysis_Xrms,
  50. ) = self._calculate_spectrum(self.data)
  51. # time_domain_analysis
  52. self.time_domain_analysis_t = np.arange(self.data.shape[0]) / self.fs
  53. def _get_by_id(self, windcode, ids):
  54. df_res = []
  55. engine = get_engine(dataBase.DATA_DB)
  56. for id in ids:
  57. table_name = windcode + '_wave'
  58. lastday_df_sql = f"SELECT * FROM {table_name} where id = {id} "
  59. df = pd.read_sql(lastday_df_sql, engine)
  60. df_res.append(df)
  61. return df_res
  62. # envelope_spectrum_analysis 包络谱分析
  63. def _bandpass_filter(self, data):
  64. """带通滤波"""
  65. m = data.shape[0]
  66. ni = round(self.fmin * self.envelope_spectrum_m / self.fs + 1)
  67. if self.fmax == float('inf'):
  68. na = m
  69. else:
  70. na = round(self.fmax * m / self.fs + 1)
  71. col = 1
  72. y = np.zeros((self.envelope_spectrum_m, col))
  73. z = np.fft.fft(data)
  74. a = np.zeros(self.envelope_spectrum_m, dtype=complex)
  75. a[ni:na] = z[ni:na]
  76. a[self.envelope_spectrum_m - na + 1: self.envelope_spectrum_m - ni + 1] = z[
  77. self.envelope_spectrum_m - na + 1: self.envelope_spectrum_m - ni + 1
  78. ]
  79. z = np.fft.ifft(a)
  80. y[:, 0] = np.real(z)
  81. return y
  82. def _calculate_envelope_spectrum(self, y):
  83. """计算包络谱"""
  84. m, n = y.shape
  85. HP = np.zeros((m, n))
  86. col = 1
  87. for p in range(col):
  88. H = np.abs(hilbert(y[:, p] - np.mean(y[:, p])))
  89. HP[:, p] = np.abs(np.fft.fft(H - np.mean(H))) * 2 / m
  90. f = np.fft.fftfreq(m, d=1 / self.fs)
  91. return f, HP
  92. def envelope_spectrum(self):
  93. """绘制包络谱"""
  94. # 只取正频率部分
  95. positive_frequencies = self.f[: self.envelope_spectrum_m // 2]
  96. positive_HP = self.HP[: self.envelope_spectrum_m // 2, 0]
  97. x = positive_frequencies
  98. y = positive_HP
  99. title = "包络谱"
  100. xaxis = "频率(Hz)"
  101. yaxis = "加速度(m/s^2)"
  102. # 加速度均方根值(有效值)
  103. Xrms = np.sqrt(np.mean(y ** 2))
  104. rpm_Gen = round(self.rpm_Gen, 2)
  105. BPFI_1X = round(self.bearing_frequencies['BPFI'].iloc[0], 2)
  106. BPFO_1X = round(self.bearing_frequencies['BPFO'].iloc[0], 2)
  107. BSF_1X = round(self.bearing_frequencies['BSF'].iloc[0], 2)
  108. FTF_1X = round(self.bearing_frequencies['FTF'].iloc[0], 2)
  109. fn_Gen = round(self.fn_Gen, 2)
  110. _3P_1X = round(self.fn_Gen, 2) * 3
  111. result = {
  112. "fs": self.fs,
  113. "Xrms": round(Xrms, 2),
  114. "x": list(x),
  115. "y": list(y),
  116. "title": title,
  117. "xaxis": xaxis,
  118. "yaxis": yaxis,
  119. "rpm_Gen": round(rpm_Gen, 2), # 转速r/min
  120. "BPFI": [{"Xaxis": BPFI_1X, "val": "1BPFI"}, {"Xaxis": BPFI_1X * 2, "val": "2BPFI"},
  121. {"Xaxis": BPFI_1X * 3, "val": "3BPFI"}, {"Xaxis": BPFI_1X * 4, "val": "4BPFI"},
  122. {"Xaxis": BPFI_1X * 5, "val": "5BPFI"}, {"Xaxis": BPFI_1X * 6, "val": "6BPFI"}],
  123. "BPFO": [{"Xaxis": BPFO_1X, "val": "1BPFO"}, {"Xaxis": BPFO_1X * 2, "val": "2BPFO"},
  124. {"Xaxis": BPFO_1X * 3, "val": "3BPFO"}, {"Xaxis": BPFO_1X * 4, "val": "4BPFO"},
  125. {"Xaxis": BPFO_1X * 5, "val": "5BPFO"}, {"Xaxis": BPFO_1X * 6, "val": "6BPFO"}],
  126. "BSF": [{"Xaxis": BSF_1X, "val": "1BSF"}, {"Xaxis": BSF_1X * 2, "val": "2BSF"},
  127. {"Xaxis": BSF_1X * 3, "val": "3BSF"}, {"Xaxis": BSF_1X * 4, "val": "4BSF"},
  128. {"Xaxis": BSF_1X * 5, "val": "5BSF"}, {"Xaxis": BSF_1X * 6, "val": "6BSF"}],
  129. "FTF": [{"Xaxis": FTF_1X, "val": "1FTF"}, {"Xaxis": FTF_1X * 2, "val": "2FTF"},
  130. {"Xaxis": FTF_1X * 3, "val": "3FTF"}, {"Xaxis": FTF_1X * 4, "val": "4FTF"},
  131. {"Xaxis": FTF_1X * 5, "val": "5FTF"}, {"Xaxis": FTF_1X * 6, "val": "6FTF"}],
  132. "fn_Gen": [{"Xaxis": fn_Gen, "val": "1X"}, {"Xaxis": fn_Gen * 2, "val": "2X"},
  133. {"Xaxis": fn_Gen * 3, "val": "3X"}, {"Xaxis": fn_Gen * 4, "val": "4X"},
  134. {"Xaxis": fn_Gen * 5, "val": "5X"}, {"Xaxis": fn_Gen * 6, "val": "6X"}],
  135. "B3P": _3P_1X,
  136. }
  137. # result = json.dumps(result, ensure_ascii=False)
  138. result = self.replace_nan(result)
  139. return result
  140. # frequency_domain_analysis 频谱分析
  141. def _calculate_spectrum(self, data):
  142. """计算频谱"""
  143. m = data.shape[0]
  144. n = 1
  145. t = np.arange(m) / self.fs
  146. mag = np.zeros((m, n))
  147. Xrms = np.sqrt(np.mean(data ** 2)) # 加速度均方根值(有效值)
  148. # col=1
  149. # for p in range(col):
  150. mag = np.abs(np.fft.fft(data - np.mean(data))) * 2 / m
  151. f = np.fft.fftfreq(m, d=1 / self.fs)
  152. return t, f, m, mag, Xrms
  153. def frequency_domain(self):
  154. """绘制频域波形参数"""
  155. # 只取正频率部分
  156. positive_frequencies = self.frequency_domain_analysis_f[
  157. : self.frequency_domain_analysis_m // 2
  158. ]
  159. positive_mag = self.frequency_domain_analysis_mag[
  160. : self.frequency_domain_analysis_m // 2
  161. ]
  162. x = positive_frequencies
  163. y = positive_mag
  164. title = "频域信号"
  165. xaxis = "频率(Hz)"
  166. yaxis = "加速度(m/s^2)"
  167. Xrms = self.frequency_domain_analysis_Xrms
  168. rpm_Gen = round(self.rpm_Gen, 2)
  169. BPFI_1X = round(self.bearing_frequencies['BPFI'].iloc[0], 2)
  170. BPFO_1X = round(self.bearing_frequencies['BPFO'].iloc[0], 2)
  171. BSF_1X = round(self.bearing_frequencies['BSF'].iloc[0], 2)
  172. FTF_1X = round(self.bearing_frequencies['FTF'].iloc[0], 2)
  173. fn_Gen = round(self.fn_Gen, 2)
  174. _3P_1X = round(self.fn_Gen, 2) * 3
  175. result = {
  176. "fs": self.fs,
  177. "Xrms": round(Xrms, 2),
  178. "x": list(x),
  179. "y": list(y),
  180. "title": title,
  181. "xaxis": xaxis,
  182. "yaxis": yaxis,
  183. "rpm_Gen": round(rpm_Gen, 2), # 转速r/min
  184. "BPFI": [{"Xaxis": BPFI_1X, "val": "1BPFI"}, {"Xaxis": BPFI_1X * 2, "val": "2BPFI"},
  185. {"Xaxis": BPFI_1X * 3, "val": "3BPFI"}, {"Xaxis": BPFI_1X * 4, "val": "4BPFI"},
  186. {"Xaxis": BPFI_1X * 5, "val": "5BPFI"}, {"Xaxis": BPFI_1X * 6, "val": "6BPFI"}],
  187. "BPFO": [{"Xaxis": BPFO_1X, "val": "1BPFO"}, {"Xaxis": BPFO_1X * 2, "val": "2BPFO"},
  188. {"Xaxis": BPFO_1X * 3, "val": "3BPFO"}, {"Xaxis": BPFO_1X * 4, "val": "4BPFO"},
  189. {"Xaxis": BPFO_1X * 5, "val": "5BPFO"}, {"Xaxis": BPFO_1X * 6, "val": "6BPFO"}],
  190. "BSF": [{"Xaxis": BSF_1X, "val": "1BSF"}, {"Xaxis": BSF_1X * 2, "val": "2BSF"},
  191. {"Xaxis": BSF_1X * 3, "val": "3BSF"}, {"Xaxis": BSF_1X * 4, "val": "4BSF"},
  192. {"Xaxis": BSF_1X * 5, "val": "5BSF"}, {"Xaxis": BSF_1X * 6, "val": "6BSF"}],
  193. "FTF": [{"Xaxis": FTF_1X, "val": "1FTF"}, {"Xaxis": FTF_1X * 2, "val": "2FTF"},
  194. {"Xaxis": FTF_1X * 3, "val": "3FTF"}, {"Xaxis": FTF_1X * 4, "val": "4FTF"},
  195. {"Xaxis": FTF_1X * 5, "val": "5FTF"}, {"Xaxis": FTF_1X * 6, "val": "6FTF"}],
  196. "fn_Gen": [{"Xaxis": fn_Gen, "val": "1X"}, {"Xaxis": fn_Gen * 2, "val": "2X"},
  197. {"Xaxis": fn_Gen * 3, "val": "3X"}, {"Xaxis": fn_Gen * 4, "val": "4X"},
  198. {"Xaxis": fn_Gen * 5, "val": "5X"}, {"Xaxis": fn_Gen * 6, "val": "6X"}],
  199. "B3P": _3P_1X,
  200. }
  201. result = self.replace_nan(result)
  202. result = json.dumps(result, ensure_ascii=False)
  203. return result
  204. # time_domain_analysis 时域分析
  205. def time_domain(self):
  206. """绘制时域波形参数"""
  207. x = self.time_domain_analysis_t
  208. y = self.data
  209. rpm_Gen = self.rpm_Gen
  210. title = "时间域信号"
  211. xaxis = "时间(s)"
  212. yaxis = "加速度(m/s^2)"
  213. # 图片右侧统计量
  214. # 平均值
  215. mean_value = np.mean(y)
  216. # 最大值
  217. max_value = np.max(y)
  218. # 最小值
  219. min_value = np.min(y)
  220. # 加速度均方根值(有效值)
  221. Xrms = np.sqrt(np.mean(y ** 2))
  222. # 峰值(单峰最大值) # 峰值
  223. Xp = (max_value - min_value) / 2
  224. # 峰峰值
  225. Xpp = max_value - min_value
  226. # 峰值指标
  227. Cf = Xp / Xrms
  228. # 波形指标
  229. Sf = Xrms / mean_value
  230. # 脉冲指标
  231. If = Xp / np.mean(np.abs(y))
  232. # 方根幅值
  233. Xr = np.mean(np.sqrt(np.abs(y))) ** 2
  234. # 裕度指标
  235. Ce = Xp / Xr
  236. # 计算每个数据点的绝对值减去均值后的三次方,并求和
  237. sum_abs_diff_cubed_3 = np.mean((np.abs(y) - mean_value) ** 3)
  238. # 计算偏度指标
  239. Cw = sum_abs_diff_cubed_3 / (Xrms ** 3)
  240. # 计算每个数据点的绝对值减去均值后的四次方,并求和
  241. sum_abs_diff_cubed_4 = np.mean((np.abs(y) - mean_value) ** 4)
  242. # 计算峭度指标
  243. Cq = sum_abs_diff_cubed_4 / (Xrms ** 4)
  244. result = {
  245. "x": list(x),
  246. "y": list(y),
  247. "title": title,
  248. "xaxis": xaxis,
  249. "yaxis": yaxis,
  250. "fs": self.fs,
  251. "Xrms": round(Xrms, 2), # 有效值
  252. "mean_value": round(mean_value, 2), # 均值
  253. "max_value": round(max_value, 2), # 最大值
  254. "min_value": round(min_value, 2), # 最小值
  255. "Xp": round(Xp, 2), # 峰值
  256. "Xpp": round(Xpp, 2), # 峰峰值
  257. "Cf": round(Cf, 2), # 峰值指标
  258. "Sf": round(Sf, 2), # 波形因子
  259. "If": round(If, 2), # 脉冲指标
  260. "Ce": round(Ce, 2), # 裕度指标
  261. "Cw": round(Cw, 2), # 偏度指标
  262. "Cq": round(Cq, 2), # 峭度指标
  263. "rpm_Gen": round(rpm_Gen, 2), # 转速r/min
  264. }
  265. result = self.replace_nan(result)
  266. result = json.dumps(result, ensure_ascii=False)
  267. return result
  268. # trend_analysis 趋势图
  269. def trend_analysis(self):
  270. all_stats = []
  271. # 定义积分函数
  272. def _integrate(data, dt):
  273. return np.cumsum(data) * dt
  274. # 定义计算统计指标的函数
  275. def _calculate_stats(data):
  276. mean_value = np.mean(data)
  277. max_value = np.max(data)
  278. min_value = np.min(data)
  279. Xrms = np.sqrt(np.mean(data ** 2)) # 加速度均方根值(有效值)
  280. Xp = (max_value - min_value) / 2 # 峰值(单峰最大值) # 峰值
  281. Cf = Xp / Xrms # 峰值指标
  282. Sf = Xrms / mean_value # 波形指标
  283. If = Xp / np.mean(np.abs(data)) # 脉冲指标
  284. Xr = np.mean(np.sqrt(np.abs(data))) ** 2 # 方根幅值
  285. Ce = Xp / Xr # 裕度指标
  286. # 计算每个数据点的绝对值减去均值后的三次方,并求和
  287. sum_abs_diff_cubed_3 = np.mean((np.abs(data) - mean_value) ** 3)
  288. # 计算偏度指标
  289. Cw = sum_abs_diff_cubed_3 / (Xrms ** 3)
  290. # 计算每个数据点的绝对值减去均值后的四次方,并求和
  291. sum_abs_diff_cubed_4 = np.mean((np.abs(data) - mean_value) ** 4)
  292. # 计算峭度指标
  293. Cq = sum_abs_diff_cubed_4 / (Xrms ** 4)
  294. #
  295. return {
  296. "fs": self.fs, # 采样频率
  297. "Mean": round(mean_value, 2), # 平均值
  298. "Max": round(max_value, 2), # 最大值
  299. "Min": round(min_value, 2), # 最小值
  300. "Xrms": round(Xrms, 2), # 有效值
  301. "Xp": round(Xp, 2), # 峰值
  302. "If": round(If, 2), # 脉冲指标
  303. "Cf": round(Cf, 2), # 峰值指标
  304. "Sf": round(Sf, 2), # 波形指标
  305. "Ce": round(Ce, 2), # 裕度指标
  306. "Cw": round(Cw, 2), # 偏度指标
  307. "Cq": round(Cq, 2), # 峭度指标
  308. # velocity_rms :速度有效值
  309. # time_stamp:时间戳
  310. }
  311. for data in self.datas:
  312. fs = int(self.data_filter['sampling_frequency'].iloc[0])
  313. dt = 1 / fs
  314. time_stamp = data['time_stamp'][0]
  315. data = np.array(ast.literal_eval(data['mesure_data'][0]))
  316. velocity = _integrate(data, dt)
  317. velocity_rms = np.sqrt(np.mean(velocity ** 2))
  318. stats = _calculate_stats(data)
  319. # 速度有效值
  320. stats["velocity_rms"] = round(velocity_rms, 2)
  321. # 时间戳
  322. stats["time_stamp"] = str(time_stamp)
  323. all_stats.append(stats)
  324. all_stats = [self.replace_nan(stats) for stats in all_stats]
  325. all_stats = json.dumps(all_stats, ensure_ascii=False)
  326. return all_stats
  327. def Characteristic_Frequency(self):
  328. """提取轴承、齿轮等参数"""
  329. # 1、从测点名称中提取部件名称(计算特征频率的部件)
  330. str1 = self.mesure_point_name
  331. # 2、连接233的数据库'energy_show',从表'wind_engine_group'查找风机编号'engine_code'对应的机型编号'mill_type_code'
  332. engine_code = self.wind_code
  333. engine = get_engine(dataBase.PLATFORM_DB)
  334. df_sql2 = f"SELECT * FROM wind_engine_group WHERE engine_code = '{engine_code}'"
  335. df2 = pd.read_sql(df_sql2, engine)
  336. mill_type_code = df2['mill_type_code'].iloc[0]
  337. # 3、从相关的表中通过机型编号'mill_type_code'或者齿轮箱编号gearbox_code查找部件'brand'、'model'的参数信息
  338. # unit_bearings主轴承参数表 关键词"main_bearing"
  339. if 'main_bearing' in str1:
  340. logger.info("main_bearing")
  341. # df_sql3 = f"SELECT * FROM {'unit_bearings'} where mill_type_code = {'mill_type_code'} "
  342. df_sql3 = f"SELECT * FROM unit_bearings WHERE mill_type_code = '{mill_type_code}' "
  343. df3 = pd.read_sql(df_sql3, engine)
  344. if df3.empty:
  345. logger.info("警告: 没有找到有效的机型信息")
  346. if 'front' in str1:
  347. brand = 'front_bearing' + '_brand'
  348. model = 'front_bearing' + '_model'
  349. front_has_value = not pd.isna(df3[brand].iloc[0]) and not pd.isna(df3[model].iloc[0])
  350. if not front_has_value:
  351. logger.info("警告: 没有找到有效的品牌信息")
  352. elif 'rear' in str1:
  353. brand = 'rear_bearing' + '_brand'
  354. model = 'rear_bearing' + '_model'
  355. end_has_value = not pd.isna(df3[brand].iloc[0]) and not pd.isna(df3[model].iloc[0])
  356. if not end_has_value:
  357. logger.info("警告: 没有找到有效的品牌信息")
  358. else:
  359. # 当没有指定 front 或 end 时,自动选择有值的轴承信息
  360. front_brand_col = 'front_bearing_brand'
  361. front_model_col = 'front_bearing_model'
  362. rear_brand_col = 'rear_bearing_brand'
  363. rear_model_col = 'rear_bearing_model'
  364. # 检查 front_bearing 是否有值
  365. front_has_value = not pd.isna(df3[front_brand_col].iloc[0]) and not pd.isna(
  366. df3[front_model_col].iloc[0])
  367. # 检查 end_bearing 是否有值
  368. end_has_value = not pd.isna(df3[rear_brand_col].iloc[0]) and not pd.isna(df3[rear_model_col].iloc[0])
  369. # 根据检查结果选择合适的列
  370. if front_has_value and end_has_value:
  371. # 如果两者都有值,默认选择 front
  372. brand = front_brand_col
  373. model = front_model_col
  374. elif front_has_value:
  375. brand = front_brand_col
  376. model = front_model_col
  377. elif end_has_value:
  378. brand = rear_brand_col
  379. model = rear_model_col
  380. else:
  381. # 如果两者都没有有效值,设置默认值或抛出异常
  382. logger.info("警告: 没有找到有效的轴承信息")
  383. brand = front_brand_col # 默认使用 front
  384. model = front_model_col # 默认使用 front
  385. _brand = df3[brand].iloc[0]
  386. _model = df3[model].iloc[0]
  387. logger.info(f"brand = {_brand}, model = {_model}")
  388. # unit_dynamo 发电机参数表 关键词generator stator
  389. elif 'generator' in str1 or 'stator' in str1:
  390. logger.info("generator or 'stator'")
  391. df_sql3 = f"SELECT * FROM unit_dynamo WHERE mill_type_code = '{mill_type_code}' "
  392. df3 = pd.read_sql(df_sql3, engine)
  393. if 'non' in str1:
  394. brand = 'non_drive_end_bearing' + '_brand'
  395. model = 'non_drive_end_bearing' + '_model'
  396. else:
  397. brand = 'drive_end_bearing' + '_brand'
  398. model = 'drive_end_bearing' + '_model'
  399. _brand = df3[brand].iloc[0]
  400. _model = df3[model].iloc[0]
  401. logger.info(f"brand = {_brand}, model = {_model}")
  402. # 齿轮箱区分行星轮/平行轮 和 轴承两个表
  403. elif 'gearbox' in str1:
  404. logger.info("gearbox")
  405. # 根据mill_type_code从unit_gearbox表中获得gearbox_code
  406. df_sql3 = f"SELECT * FROM unit_gearbox WHERE mill_type_code = '{mill_type_code}' "
  407. df3 = pd.read_sql(df_sql3, engine)
  408. gearbox_code = df3['code'].iloc[0]
  409. logger.info(gearbox_code)
  410. # 如果是行星轮/平行轮 则从unit_gearbox_structure 表中取数据
  411. if 'planet' in str1 or 'sun' in str1:
  412. logger.info("'planet' or 'sun' ")
  413. gearbox_structure = 1 if 'planet' in str1 else 2
  414. planetary_gear_grade = 1
  415. if 'first' in str1:
  416. planetary_gear_grade = 1
  417. elif 'second' in str1:
  418. planetary_gear_grade = 2
  419. elif 'third' in str1:
  420. planetary_gear_grade = 3
  421. df_sql33 = f"""
  422. SELECT bearing_brand, bearing_model
  423. FROM unit_gearbox_structure
  424. WHERE gearbox_code = '{gearbox_code}'
  425. AND gearbox_structure = '{gearbox_structure}'
  426. AND planetary_gear_grade = '{planetary_gear_grade}'
  427. """
  428. df33 = pd.read_sql(df_sql33, engine)
  429. if df33.empty:
  430. logger.info("unit_gearbox_structure没有该测点的参数")
  431. else:
  432. brand = 'bearing' + '_brand'
  433. model = 'bearing' + '_model'
  434. logger.info(brand)
  435. _brand = df33[brand].iloc[0]
  436. _model = df33[model].iloc[0]
  437. has_value = not pd.isna(df33[brand].iloc[0]) and not pd.isna(df33[model].iloc[0])
  438. if has_value:
  439. logger.info(_brand)
  440. logger.info(_model)
  441. else:
  442. logger.info("警告: 没有找到有效的轴承信息")
  443. # 如果是齿轮箱轴承 则从unit_gearbox_bearings 表中取数据
  444. elif 'shaft' in str1 or 'input' in str1:
  445. logger.info("'shaft'or'input'")
  446. # df_sql33 = f"SELECT * FROM unit_gearbox_bearings WHERE gearbox_code = '{gearbox_code}' "
  447. # df33 = pd.read_sql(df_sql33, Engine33)
  448. # 高速轴 低速中间轴 取bearing_rs/gs均可
  449. parallel_wheel_grade = 1
  450. if 'low_speed' in str1:
  451. parallel_wheel_grade = 1
  452. elif 'low_speed_intermediate' in str1:
  453. parallel_wheel_grade = 2
  454. elif 'high_speed' in str1:
  455. parallel_wheel_grade = 3
  456. df_sql33 = f"""
  457. SELECT bearing_rs_brand, bearing_rs_model, bearing_gs_brand, bearing_gs_model
  458. FROM unit_gearbox_bearings
  459. WHERE gearbox_code = '{gearbox_code}'
  460. AND parallel_wheel_grade = '{parallel_wheel_grade}'
  461. """
  462. df33 = pd.read_sql(df_sql33, engine)
  463. if not df33.empty:
  464. if 'high_speed' in str1 or 'low_speed_intermediate' in str1:
  465. rs_brand = 'bearing_rs' + '_brand'
  466. rs_model = 'bearing_rs' + '_model'
  467. gs_brand = 'bearing_gs' + '_brand'
  468. gs_model = 'bearing_gs' + '_model'
  469. rs_has_value = not pd.isna(df33[rs_brand].iloc[0]) and not pd.isna(df33[rs_model].iloc[0])
  470. gs_has_value = not pd.isna(df33[gs_brand].iloc[0]) and not pd.isna(df33[gs_model].iloc[0])
  471. if rs_has_value and gs_has_value:
  472. brand = rs_brand
  473. model = rs_model
  474. elif rs_has_value:
  475. brand = rs_brand
  476. model = rs_model
  477. elif gs_has_value:
  478. brand = gs_brand
  479. model = gs_model
  480. else:
  481. logger.info("警告: 没有找到有效的品牌信息")
  482. brand = rs_brand
  483. model = rs_model
  484. # 低速轴 取bearing_model
  485. elif 'low_speed' in str1:
  486. brand = 'bearing' + '_brand'
  487. model = 'bearing' + '_model'
  488. else:
  489. logger.info("警告: 没有找到有效的轴承信息")
  490. logger.info(f"brand = {brand}")
  491. _brand = df33[brand].iloc[0]
  492. _model = df33[model].iloc[0]
  493. logger.info(f"brand = {_brand}, model = {_model}")
  494. # 4、从表'unit_dict_brand_model'中通过'_brand'、'_model'查找部件的参数信息
  495. df_sql4 = f"SELECT * FROM unit_dict_brand_model where manufacture = %s AND model_number = %s"
  496. params = [(_brand, _model)]
  497. df4 = pd.read_sql(df_sql4, engine, params=params)
  498. n_rolls = df4['rolls_number'].iloc[0]
  499. d_rolls = df4['rolls_diameter'].iloc[0]
  500. D_diameter = df4['circle_diameter'].iloc[0]
  501. theta_deg = df4['theta_deg'].iloc[0]
  502. result = {
  503. "type": 'bearing',
  504. "n_rolls": round(n_rolls, 2),
  505. "d_rolls": round(d_rolls, 2),
  506. "D_diameter": round(D_diameter, 2),
  507. "theta_deg": round(theta_deg, 2),
  508. }
  509. return result
  510. def calculate_bearing_frequencies(self, n, d, D, theta_deg, rpm):
  511. """
  512. 计算轴承各部件特征频率
  513. 参数:
  514. n (int): 滚动体数量
  515. d (float): 滚动体直径(单位:mm)
  516. D (float): 轴承节圆直径(滚动体中心圆直径,单位:mm)
  517. theta_deg (float): 接触角(单位:度)
  518. rpm (float): 转速(转/分钟)
  519. 返回:
  520. dict: 包含各特征频率的字典(单位:Hz)
  521. """
  522. # 转换角度为弧度
  523. theta = math.radians(theta_deg)
  524. # 转换直径单位为米(保持单位一致性,实际计算中比值抵消单位影响)
  525. # 注意:由于公式中使用的是比值,单位可以保持mm不需要转换
  526. ratio = d / D
  527. # 基础频率计算(转/秒)
  528. f_r = rpm / 60.0
  529. # 计算各特征频率
  530. BPFI = n / 2 * (1 + ratio * math.cos(theta)) * f_r # 内圈故障频率
  531. BPFO = n / 2 * (1 - ratio * math.cos(theta)) * f_r # 外圈故障频率
  532. BSF = (D / (2 * d)) * (1 - (ratio ** 2) * (math.cos(theta) ** 2)) * f_r # 滚动体故障频率
  533. FTF = 0.5 * (1 - ratio * math.cos(theta)) * f_r # 保持架故障频率
  534. return {
  535. "BPFI": round(BPFI, 2),
  536. "BPFO": round(BPFO, 2),
  537. "BSF": round(BSF, 2),
  538. "FTF": round(FTF, 2),
  539. }
  540. #检查返回结果是否有nan 若有,则替换成none
  541. def replace_nan(self, obj):
  542. if isinstance(obj, dict):
  543. return {k: self.replace_nan(v) for k, v in obj.items()}
  544. elif isinstance(obj, list):
  545. return [self.replace_nan(item) for item in obj]
  546. elif isinstance(obj, float) and math.isnan(obj):
  547. return None
  548. return obj