data_clean.py 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129
  1. import os
  2. import json
  3. import pandas as pd
  4. import numpy as np
  5. import matplotlib.pyplot as plt
  6. from typing import Tuple, List
  7. import warnings
  8. import sys
  9. import frequency_filter as ff
  10. from datetime import datetime
  11. from scipy.optimize import least_squares, differential_evolution
  12. from scipy.signal import savgol_filter
  13. warnings.filterwarnings("ignore", category=FutureWarning)
  14. plt.rcParams['font.sans-serif'] = ['SimHei']
  15. plt.rcParams['axes.unicode_minus'] = False
  16. def result_main():
  17. python_interpreter_path = sys.executable
  18. project_directory = os.path.dirname(python_interpreter_path)
  19. data_folder = os.path.join(project_directory, 'data')
  20. if not os.path.exists(data_folder):
  21. os.makedirs(data_folder)
  22. csv_file_path = os.path.join(data_folder, 'history_data.csv')
  23. if not os.path.exists(csv_file_path):
  24. pd.DataFrame(columns=['时间', '场站', '风机编号', '采样频率',
  25. '叶片1角度偏差', '叶片2角度偏差', '叶片3角度偏差', '相对角度偏差',
  26. '叶片1净空值', '叶片2净空值', '叶片3净空值',
  27. '叶片1扭转', '叶片2扭转', '叶片3扭转', '平均扭转',
  28. '振动幅值', '振动主频']).to_csv(csv_file_path, index=False)
  29. return csv_file_path
  30. def delete_data(name):
  31. python_interpreter_path = sys.executable
  32. project_directory = os.path.dirname(python_interpreter_path)
  33. data_folder = os.path.join(project_directory, 'data')
  34. csv_file_path = os.path.join(data_folder, 'history_data.csv')
  35. df = pd.read_csv(csv_file_path)
  36. condition = ((df['时间'].astype(str).str.contains(name[0])) &
  37. (df['场站'].astype(str).str.contains(name[1])) &
  38. (df['风机编号'].astype(str).str.contains(name[2])))
  39. df = df[~condition]
  40. df.to_csv(csv_file_path, index=False)
  41. return csv_file_path
  42. def history_data(name):
  43. time_code = name[0]
  44. wind_name = name[1]
  45. turbine_code = name[2]
  46. python_interpreter_path = sys.executable
  47. project_directory = os.path.dirname(python_interpreter_path)
  48. data_folder = os.path.join(project_directory, 'data')
  49. time_code_cleaned = time_code.replace("-", "").replace(":", "").replace(" ", "")
  50. json_filename = f"{wind_name}_{turbine_code}_{time_code_cleaned}.json"
  51. json_file_path = os.path.join(data_folder, json_filename)
  52. if not os.path.exists(json_file_path):
  53. raise ValueError("文件不存在")
  54. with open(json_file_path, 'r') as f:
  55. data = json.load(f)
  56. return data
  57. def data_analyse(path: List[str]):
  58. locate_file = path[0]
  59. measure_file = path[1]
  60. noise_reduction = 0.000001
  61. min_difference = 1.5
  62. angle_cone = float(path[2])
  63. axial_inclination = float(path[3])
  64. lift_up_limit = float(path[4])
  65. group_length = [10000, 10000, 5000, 10000]
  66. return_list = []
  67. wind_name, turbine_code, time_code, sampling_fq, angle_nan, angle_cen = find_param(locate_file)
  68. wind_name_1, turbine_code_1, time_code_1, sampling_fq_1, angle_flange, angle_root = find_param(measure_file)
  69. sampling_fq_1 = sampling_fq_1 * 1000
  70. sampling_fq = sampling_fq * 1000
  71. data_nan, data_cen = process_data(locate_file)
  72. data_flange, data_root = process_data(measure_file)
  73. if lift_up_limit >= 0.1:
  74. discrete_values = np.arange(0, 0.101, 0.001)
  75. condition = data_flange['distance'] > lift_up_limit
  76. n = condition.sum()
  77. random_discrete = np.random.choice(discrete_values, size=n)
  78. data_flange.loc[condition, 'distance'] = lift_up_limit + 3 + random_discrete
  79. elif np.abs(lift_up_limit) < 0.1:
  80. pass
  81. else:
  82. raise ValueError("lift_up_limit error.")
  83. start_flange, end_flange, filtered_data_flange = cycle_calculate(data_flange, noise_reduction, min_difference)
  84. start_root, end_root, filtered_data_root = cycle_calculate(data_root, noise_reduction, min_difference)
  85. start_nan, end_nan, filtered_data_nan = cycle_calculate(data_nan, noise_reduction, min_difference)
  86. filtered_data_cen = tower_filter(data_cen, noise_reduction)
  87. dist_cen = np.mean(filtered_data_cen.iloc[:, 1].tolist())
  88. filtered_data_cen.iloc[:, 1] = filtered_data_cen.iloc[:, 1] * np.cos(np.deg2rad(angle_cen + axial_inclination))
  89. tower_dist_flange = ff.tower_cal(filtered_data_flange, start_flange, end_flange, sampling_fq_1)
  90. tower_dist_root = ff.tower_cal(filtered_data_root, start_root, end_root, sampling_fq_1)
  91. tower_dist_nan = ff.tower_cal(filtered_data_nan, start_nan, end_nan, sampling_fq)
  92. lowpass_data, fft_x, fft_y, tower_freq, tower_max = ff.process_fft(filtered_data_cen, sampling_fq)
  93. result_line_flange, result_scatter_flange, border_rows_flange, cycle_len_flange, min_flange \
  94. = data_normalize(filtered_data_flange, start_flange, end_flange, group_length[0])
  95. result_line_root, result_scatter_root, border_rows_root, cycle_len_root, min_root \
  96. = data_normalize(filtered_data_root, start_root, end_root, group_length[1])
  97. result_line_nan, result_scatter_nan, border_rows_nan, cycle_len_nan, min_nan \
  98. = data_normalize(filtered_data_nan, start_nan, end_nan, group_length[2])
  99. result_avg_flange, result_diff_flange = blade_shape(result_line_flange)
  100. result_avg_root, result_diff_root = blade_shape(result_line_root)
  101. border_rows_flange_new, angle_flange_new = coordinate_normalize(border_rows_flange, angle_flange)
  102. border_rows_nan_new, angle_nan_new = coordinate_normalize(border_rows_nan, angle_nan)
  103. flange_ava = pd.concat([df['distance'] for df in border_rows_flange_new]).mean(numeric_only=True).mean()
  104. root_ava = pd.concat([df['distance'] for df in border_rows_root]).mean(numeric_only=True).mean()
  105. d_radius = np.abs((flange_ava * np.cos(np.deg2rad(angle_flange_new))
  106. - root_ava * np.cos(np.deg2rad(angle_root))) * np.sin(np.deg2rad(axial_inclination))
  107. + (flange_ava * np.sin(np.deg2rad(angle_flange_new))
  108. - root_ava * np.sin(np.deg2rad(angle_root))) * np.cos(np.deg2rad(axial_inclination)))
  109. flange_root_dist = np.sqrt(flange_ava ** 2 + root_ava ** 2 - 2 * flange_ava * root_ava * np.cos(np.deg2rad(angle_flange_new - angle_root)))
  110. flange_r = radius_cal(border_rows_flange_new, angle_flange_new, dist_cen, angle_cen, axial_inclination, angle_cone)
  111. root_r = radius_cal(border_rows_root, angle_root, dist_cen, angle_cen, axial_inclination, angle_cone)
  112. nan_r = radius_cal(border_rows_nan_new, angle_nan_new, dist_cen, angle_cen, axial_inclination, angle_cone)
  113. blade_axis, blade_axis_tuple, result_line_flange = blade_axis_cal(filtered_data_flange, start_flange, end_flange,
  114. angle_flange + angle_cone + axial_inclination, group_length[3], flange_r)
  115. blade_axis_new, angle_flange_new = flange_coordinate_normalize(blade_axis, angle_flange)
  116. blade_axis_tuple_new0, angle_flange_new = flange_coordinate_normalize(blade_axis_tuple, angle_flange)
  117. blade_axis_tuple["中心y"] = blade_axis_tuple["中心y"] * np.cos(np.deg2rad(angle_flange + angle_cone + axial_inclination))
  118. if np.abs((root_r - flange_r) - d_radius) > 0.5:
  119. root_r = flange_r + d_radius
  120. if np.abs(flange_root_dist - d_radius) > 0.5:
  121. root_r = flange_r + flange_root_dist
  122. blade_axis_new["中心y"] = blade_axis_new["中心y"] - (flange_ava - root_ava)
  123. blade_axis_tuple_new0["中心y"] = blade_axis_tuple_new0["中心y"] - (flange_ava - root_ava)
  124. aero_dist_flange, v_speed_flange, cen_blade_flange = (
  125. blade_angle_aero_dist(border_rows_flange, flange_r, cycle_len_flange, tower_dist_flange, angle_flange_new))
  126. aero_dist_nan, v_speed_nan, cen_blade_nan = (
  127. blade_angle_aero_dist(border_rows_nan_new, nan_r, cycle_len_nan, tower_dist_nan, angle_nan_new))
  128. pitch_angle_root, v_speed_root, blade_axis_tuple_new = (
  129. blade_angle(border_rows_root, blade_axis_tuple_new0, root_r, cycle_len_root, angle_root + angle_cone + axial_inclination))
  130. blade_axis_tuple_new["中心y"] = blade_axis_tuple_new["中心y"]*np.cos(np.deg2rad(angle_root + angle_cone + axial_inclination))
  131. cen_blade_nan_array = np.array(cen_blade_nan)
  132. min_nan_array = np.array(min_nan)
  133. abs_diff_nan = np.abs(cen_blade_nan_array - min_nan_array)
  134. blade_dist_nan = abs_diff_nan * np.cos(np.deg2rad(angle_nan_new))
  135. blade_dist_nan.tolist()
  136. dist_distribute_nan = blade_dist_distribute_cal(filtered_data_nan, start_nan, end_nan,
  137. tower_dist_nan, angle_nan_new + angle_cone + axial_inclination, blade_dist_nan)
  138. dist_distribute = [df.round(5) for df in dist_distribute_nan]
  139. min_values = []
  140. min_keys = []
  141. max_values = []
  142. max_keys = []
  143. mean_values = []
  144. for df in dist_distribute:
  145. second_col_min = df[df.columns[1]].min()
  146. second_col_max = df[df.columns[1]].max()
  147. min_row = df[df[df.columns[1]] == second_col_min]
  148. max_row = df[df[df.columns[1]] == second_col_max]
  149. min_values.append(round(second_col_min, 2))
  150. min_keys.append(round(min_row.iloc[0][df.columns[0]], 2))
  151. max_values.append(round(second_col_max, 2))
  152. max_keys.append(round(max_row.iloc[0][df.columns[0]], 2))
  153. for i in range(3):
  154. mean_values.append(round((max_values[i] + min_values[i]) / 2, 2))
  155. for i in range(3):
  156. df = result_line_root[i]
  157. first_column = df.iloc[:, 0]
  158. sec_column = df.iloc[:, 1]
  159. df.iloc[:, 0] = first_column * v_speed_root
  160. min_time = df.iloc[:, 0].min()
  161. df.iloc[:, 0] -= min_time
  162. blade_axis_tuple_new.iloc[i, 1] -= min_time
  163. df.iloc[:, 1] = sec_column * np.cos(np.deg2rad(angle_root + angle_cone + axial_inclination))
  164. avg_flange = result_avg_flange.iloc[:, 0]
  165. result_avg_flange.iloc[:, 0] = avg_flange * v_speed_flange
  166. avg_root = result_avg_root.iloc[:, 0]
  167. result_avg_root.iloc[:, 0] = avg_root * v_speed_root
  168. pitch_angle_flange = [0, 0, 0]
  169. twist_1 = round(np.abs(pitch_angle_root[0] - pitch_angle_flange[0]), 2)
  170. twist_2 = round(np.abs(pitch_angle_root[1] - pitch_angle_flange[1]), 2)
  171. twist_3 = round(np.abs(pitch_angle_root[2] - pitch_angle_flange[2]), 2)
  172. twist_avg = round((twist_1 + twist_2 + twist_3) / 3, 2)
  173. sampling_num = int(0.015 * sampling_fq_1)
  174. data_flange.iloc[:, 0] = data_flange.iloc[:, 0] / 5000000
  175. data_root.iloc[:, 0] = data_root.iloc[:, 0] / 5000000
  176. lowpass_data.iloc[:, 0] = lowpass_data.iloc[:, 0] / 5000000
  177. rotated_root = [pd.DataFrame() for _ in range(3)]
  178. for i in range(3):
  179. angle_rad = np.deg2rad(-pitch_angle_root[i])
  180. rotation_matrix = np.array([
  181. [np.cos(angle_rad), -np.sin(angle_rad)],
  182. [np.sin(angle_rad), np.cos(angle_rad)]
  183. ])
  184. center_x = blade_axis_tuple_new.iloc[i, 1]
  185. center_y = blade_axis_tuple_new.iloc[i, 2]
  186. rotated_points = result_line_root[i].copy()
  187. for idx, row in result_line_root[i].iterrows():
  188. x = row.iloc[0]
  189. y = row.iloc[1]
  190. translated_x = x - center_x
  191. translated_y = y - center_y
  192. rotated = rotation_matrix @ np.array([translated_x, translated_y])
  193. final_x = rotated[0] + center_x
  194. final_y = rotated[1] + center_y
  195. rotated_points.iloc[idx, 0] = final_x
  196. rotated_points.iloc[idx, 1] = final_y
  197. rotated_root[i % 3] = pd.concat([rotated_root[i % 3], rotated_points])
  198. circle_fit = [pd.DataFrame() for _ in range(3)]
  199. for i in range(3):
  200. v, xc, yc, circle_r = blade_axis_tuple[['旋转半径', '中心x', '中心y', '圆半径']].values[i]
  201. theta = np.linspace(0, 2 * np.pi, 500)
  202. x_circle = xc + circle_r * np.cos(theta)
  203. y_circle = yc + circle_r * np.sin(theta)
  204. circle_fit[i] = pd.DataFrame({
  205. 'x_circle': x_circle,
  206. 'y_circle': y_circle
  207. })
  208. return_list.append(str(time_code))
  209. return_list.append(str(wind_name))
  210. return_list.append(str(turbine_code))
  211. return_list.append(sampling_fq_1)
  212. return_list.append(pitch_angle_root[0])
  213. return_list.append(pitch_angle_root[1])
  214. return_list.append(pitch_angle_root[2])
  215. return_list.append(pitch_angle_root[3])
  216. return_list.append(mean_values[0])
  217. return_list.append(mean_values[1])
  218. return_list.append(mean_values[2])
  219. return_list.append(twist_1)
  220. return_list.append(twist_2)
  221. return_list.append(twist_3)
  222. return_list.append(twist_avg)
  223. return_list.append(tower_max)
  224. return_list.append(tower_freq)
  225. df_new_row = pd.DataFrame([return_list],
  226. columns=['时间', '场站', '风机编号', '采样频率',
  227. '叶片1角度偏差', '叶片2角度偏差', '叶片3角度偏差', '相对角度偏差',
  228. '叶片1净空值', '叶片2净空值', '叶片3净空值',
  229. '叶片1扭转', '叶片2扭转', '叶片3扭转', '平均扭转',
  230. '振动幅值', '振动主频'])
  231. json_output = {
  232. 'original_plot': {
  233. 'blade_tip': {
  234. 'xdata': data_flange.iloc[:, 0].tolist()[::sampling_num],
  235. 'ydata': data_flange.iloc[:, 1].tolist()[::sampling_num]
  236. },
  237. 'blade_root': {
  238. 'xdata': data_root.iloc[:, 0].tolist()[::sampling_num],
  239. 'ydata': data_root.iloc[:, 1].tolist()[::sampling_num]
  240. }
  241. },
  242. 'fft_plot': {
  243. 'lowpass': {
  244. 'xdata': lowpass_data['time'].tolist()[::sampling_num],
  245. 'ydata': lowpass_data['distance_filtered'].tolist()[::sampling_num],
  246. 'xmax': max(lowpass_data['time'].tolist()),
  247. 'xmin': min(lowpass_data['time'].tolist()),
  248. 'ymax': max(lowpass_data['distance_filtered'].tolist()) + 0.02,
  249. 'ymin': min(lowpass_data['distance_filtered'].tolist()) - 0.02
  250. },
  251. 'fft': {
  252. 'xdata': fft_x,
  253. 'ydata': fft_y,
  254. 'xmax': max(fft_x),
  255. 'xmin': min(fft_x),
  256. 'ymax': max(fft_y) + 0.02,
  257. 'ymin': 0
  258. }
  259. },
  260. 'blade_tip': {
  261. 'first_blade': {
  262. 'xdata': result_line_flange[0].iloc[:, 0].tolist(),
  263. 'ydata': result_line_flange[0].iloc[:, 1].tolist()
  264. },
  265. 'second_blade': {
  266. 'xdata': result_line_flange[1].iloc[:, 0].tolist(),
  267. 'ydata': result_line_flange[1].iloc[:, 1].tolist()
  268. },
  269. 'third_blade': {
  270. 'xdata': result_line_flange[2].iloc[:, 0].tolist(),
  271. 'ydata': result_line_flange[2].iloc[:, 1].tolist()
  272. },
  273. 'avg_blade': {
  274. 'xdata': result_avg_flange.iloc[:, 0].tolist(),
  275. 'ydata': result_avg_flange.iloc[:, 1].tolist()
  276. },
  277. 'blade_center': {
  278. 'xdata': blade_axis_tuple.iloc[:, 1].tolist(),
  279. 'ydata': blade_axis_tuple.iloc[:, 2].tolist()
  280. },
  281. 'first_circle': {
  282. 'xdata': circle_fit[0].iloc[:, 0].tolist(),
  283. 'ydata': circle_fit[0].iloc[:, 1].tolist()
  284. },
  285. 'second_circle': {
  286. 'xdata': circle_fit[1].iloc[:, 0].tolist(),
  287. 'ydata': circle_fit[1].iloc[:, 1].tolist()
  288. },
  289. 'third_circle': {
  290. 'xdata': circle_fit[2].iloc[:, 0].tolist(),
  291. 'ydata': circle_fit[2].iloc[:, 1].tolist()
  292. }
  293. },
  294. 'blade_root': {
  295. 'first_blade': {
  296. 'xdata': result_line_root[0].iloc[:, 0].tolist(),
  297. 'ydata': result_line_root[0].iloc[:, 1].tolist()
  298. },
  299. 'second_blade': {
  300. 'xdata': result_line_root[1].iloc[:, 0].tolist(),
  301. 'ydata': result_line_root[1].iloc[:, 1].tolist()
  302. },
  303. 'third_blade': {
  304. 'xdata': result_line_root[2].iloc[:, 0].tolist(),
  305. 'ydata': result_line_root[2].iloc[:, 1].tolist()
  306. },
  307. 'avg_blade': {
  308. 'xdata': result_avg_root.iloc[:, 0].tolist(),
  309. 'ydata': result_avg_root.iloc[:, 1].tolist()
  310. },
  311. 'first_rotate_blade': {
  312. 'xdata': rotated_root[0].iloc[:, 0].tolist(),
  313. 'ydata': rotated_root[0].iloc[:, 1].tolist()
  314. },
  315. 'second_rotate_blade': {
  316. 'xdata': rotated_root[1].iloc[:, 0].tolist(),
  317. 'ydata': rotated_root[1].iloc[:, 1].tolist()
  318. },
  319. 'third_rotate_blade': {
  320. 'xdata': rotated_root[2].iloc[:, 0].tolist(),
  321. 'ydata': rotated_root[2].iloc[:, 1].tolist()
  322. },
  323. 'blade_center': {
  324. 'xdata': blade_axis_tuple_new.iloc[:, 1].tolist(),
  325. 'ydata': blade_axis_tuple_new.iloc[:, 2].tolist()
  326. }
  327. },
  328. 'dist_distribution': {
  329. 'first_blade': {
  330. 'xdata': dist_distribute[0].iloc[:, 0].tolist(),
  331. 'ydata': dist_distribute[0].iloc[:, 1].tolist()
  332. },
  333. 'second_blade': {
  334. 'xdata': dist_distribute[1].iloc[:, 0].tolist(),
  335. 'ydata': dist_distribute[1].iloc[:, 1].tolist()
  336. },
  337. 'third_blade': {
  338. 'xdata': dist_distribute[2].iloc[:, 0].tolist(),
  339. 'ydata': dist_distribute[2].iloc[:, 1].tolist()
  340. }
  341. },
  342. 'analyse_table': {
  343. 'pitch_angle_diff': {
  344. 'blade_1': pitch_angle_root[0],
  345. 'blade_2': pitch_angle_root[1],
  346. 'blade_3': pitch_angle_root[2],
  347. 'blade_relate': pitch_angle_root[3]
  348. },
  349. 'aero_dist': {
  350. 'first_blade': {
  351. 'x_min': min_keys[0],
  352. 'y_min': min_values[0],
  353. 'x_max': max_keys[0],
  354. 'y_max': max_values[0],
  355. 'y_diff': np.abs(max_values[0] - min_values[0]),
  356. 'y_ava': mean_values[0]
  357. },
  358. 'second_blade': {
  359. 'x_min': min_keys[1],
  360. 'y_min': min_values[1],
  361. 'x_max': max_keys[1],
  362. 'y_max': max_values[1],
  363. 'y_diff': np.abs(max_values[1] - min_values[1]),
  364. 'y_ava': mean_values[1]
  365. },
  366. 'third_blade': {
  367. 'x_min': min_keys[2],
  368. 'y_min': min_values[2],
  369. 'x_max': max_keys[2],
  370. 'y_max': max_values[2],
  371. 'y_diff': np.abs(max_values[2] - min_values[2]),
  372. 'y_ava': mean_values[2]
  373. }
  374. },
  375. 'blade_twist': {
  376. 'blade_1': twist_1,
  377. 'blade_2': twist_2,
  378. 'blade_3': twist_3,
  379. 'blade_avg': twist_avg
  380. },
  381. 'tower_vibration': {
  382. 'max_vibration': tower_max,
  383. 'main_vibration_freq': tower_freq
  384. }
  385. }
  386. }
  387. python_interpreter_path = sys.executable
  388. project_directory = os.path.dirname(python_interpreter_path)
  389. data_folder = os.path.join(project_directory, 'data')
  390. if not os.path.exists(data_folder):
  391. os.makedirs(data_folder)
  392. csv_file_path = os.path.join(data_folder, 'history_data.csv')
  393. if not os.path.exists(csv_file_path):
  394. pd.DataFrame(columns=['时间', '场站', '风机编号', '采样频率',
  395. '叶片1角度偏差', '叶片2角度偏差', '叶片3角度偏差', '相对角度偏差',
  396. '叶片1净空值', '叶片2净空值', '叶片3净空值',
  397. '叶片1扭转', '叶片2扭转', '叶片3扭转', '平均扭转',
  398. '振动幅值', '振动主频']).to_csv(csv_file_path, index=False)
  399. df_new_row.to_csv(csv_file_path, mode='a', header=False, index=False)
  400. time_code_cleaned = time_code.replace("-", "").replace(":", "").replace(" ", "")
  401. json_filename = f"{wind_name}_{turbine_code}_{time_code_cleaned}.json"
  402. json_file_path = os.path.join(data_folder, json_filename)
  403. with open(json_file_path, 'w') as json_file:
  404. json.dump(json_output, json_file, indent=4)
  405. return json_output
  406. def process_data(file_path):
  407. data = pd.read_csv(file_path, usecols=[1, 3, 4, 8, 9], header=None, engine='c')
  408. data = data.head(int(len(data) * 0.95))
  409. max_value = data.iloc[:, 0].max()
  410. max_index = data.iloc[:, 0].idxmax()
  411. min_index = data.iloc[:, 0].idxmin()
  412. if min_index == max_index + 1:
  413. data.iloc[min_index:, 0] += max_value
  414. last_time = data.iloc[-1, 0]
  415. first_time = data.iloc[0, 0]
  416. data = data[data.iloc[:, 0] >= first_time]
  417. data = data[data.iloc[:, 0] <= last_time]
  418. data.reset_index(drop=True, inplace=True)
  419. min_time = data.iloc[:, 0].min()
  420. data.iloc[:, 0] -= min_time
  421. data_1 = data.iloc[:, [0, 1, 2]]
  422. data_2 = data.iloc[:, [0, 3, 4]]
  423. data_1.columns = ['time', 'distance', 'grey']
  424. data_2.columns = ['time', 'distance', 'grey']
  425. return data_1, data_2
  426. def tower_filter(data_group: pd.DataFrame, noise_threshold: float):
  427. distance_counts = data_group['distance'].value_counts(normalize=True)
  428. noise_distance_threshold = distance_counts[distance_counts < noise_threshold].index
  429. noise_indices = data_group[data_group['distance'].isin(noise_distance_threshold)].index
  430. data_group.loc[noise_indices, 'distance'] = np.nan
  431. top_5_distances = distance_counts.head(5).index
  432. mean_values = data_group[data_group['distance'].isin(top_5_distances)]['distance'].mean()
  433. data_group.loc[(data_group['distance'] < mean_values * 0.9) | (
  434. data_group['distance'] > mean_values * 1.1), 'distance'] = np.nan
  435. data_group['distance'] = data_group['distance'].fillna(method='ffill')
  436. filtered_data = data_group
  437. return filtered_data
  438. def cycle_calculate(data_group: pd.DataFrame, noise_threshold: float, min_distance: float):
  439. distance_counts = data_group['distance'].value_counts(normalize=True)
  440. noise_distance_threshold = distance_counts[distance_counts < noise_threshold].index
  441. noise_indices = data_group[data_group['distance'].isin(noise_distance_threshold)].index
  442. data_group.loc[noise_indices, 'distance'] = np.nan
  443. if distance_counts.get(0, 0) >= 0.1:
  444. top_5_distances = distance_counts[distance_counts.index != 0].head(5).index
  445. mean_values = data_group[data_group['distance'].isin(top_5_distances)]['distance'].mean()
  446. data_group.loc[((data_group['distance'] > 0) & (data_group['distance'] < mean_values - 30)) |
  447. (data_group['distance'] > mean_values * 1.1), 'distance'] = np.nan
  448. else:
  449. top_5_distances = distance_counts[distance_counts.index != 0].head(5).index
  450. mean_values = data_group[data_group['distance'].isin(top_5_distances)]['distance'].mean()
  451. data_group.loc[(data_group['distance'] < mean_values-30) | (
  452. data_group['distance'] > mean_values*1.1), 'distance'] = np.nan
  453. data_group['distance'] = data_group['distance'].fillna(method='ffill')
  454. filtered_data = data_group
  455. filtered_data['distance_diff'] = filtered_data['distance'].diff()
  456. large_diff_indices = filtered_data[filtered_data['distance_diff'] > min_distance].index
  457. small_diff_indices = filtered_data[filtered_data['distance_diff'] < -min_distance].index
  458. filtered_data = filtered_data.drop(columns=['distance_diff'])
  459. start_points = pd.DataFrame()
  460. end_points = pd.DataFrame()
  461. for idx in large_diff_indices:
  462. current_distance = filtered_data.loc[idx, 'distance']
  463. next_rows_large = filtered_data.loc[idx - 500: idx - 1]
  464. if next_rows_large['distance'].le(current_distance - min_distance).all():
  465. end_points = pd.concat([end_points, filtered_data.loc[[idx - 1]]])
  466. for idx in small_diff_indices:
  467. current_distance = filtered_data.loc[idx - 1, 'distance']
  468. next_rows_small = filtered_data.iloc[idx: idx + 500]
  469. if next_rows_small['distance'].le(current_distance - min_distance).all():
  470. start_points = pd.concat([start_points, filtered_data.loc[[idx]]])
  471. if 0 in distance_counts.nlargest(3).index:
  472. end_points, start_points = start_points, end_points
  473. if end_points.iloc[0, 0] < start_points.iloc[0, 0]:
  474. end_points = end_points.drop(end_points.index[0])
  475. if end_points.iloc[-1, 0] < start_points.iloc[-1, 0]:
  476. start_points = start_points.drop(start_points.index[-1])
  477. else:
  478. pass
  479. return start_points, end_points, filtered_data
  480. def data_normalize(data_group: pd.DataFrame, start_points: pd.DataFrame, end_points: pd.DataFrame, group_len: int) \
  481. -> Tuple[List[pd.DataFrame], List[pd.DataFrame], List[pd.DataFrame], int, list]:
  482. combined_df_sorted = pd.concat([start_points, end_points]).sort_values(by='time')
  483. if combined_df_sorted.iloc[0].equals(end_points.iloc[0]):
  484. combined_df_sorted = combined_df_sorted.iloc[1:]
  485. if combined_df_sorted.iloc[-1].equals(start_points.iloc[-1]):
  486. combined_df_sorted = combined_df_sorted.iloc[:-1]
  487. combined_df_sorted.reset_index(drop=True, inplace=True)
  488. start_times = combined_df_sorted['time'].tolist()
  489. normalize_cycle = int(start_times[1] - start_times[0])
  490. full_cycle = int((start_times[2] - start_times[0]) * 3)
  491. turbines = [pd.DataFrame() for _ in range(3)]
  492. for i in range(0, len(start_times), 2):
  493. start_time = start_times[i]
  494. end_time = start_times[i + 1]
  495. segment = data_group[(data_group['time'] > start_time) & (data_group['time'] <= end_time)]
  496. if not segment.empty:
  497. ratio = (end_time - start_time) / normalize_cycle
  498. segment.loc[:, 'time'] = (segment['time'] - start_time) / ratio
  499. turbines[int(i / 2) % 3] = pd.concat([turbines[int(i / 2) % 3], segment])
  500. turbines_processed = []
  501. turbines_scattered = []
  502. min_list = []
  503. sd_time = [-1, -1]
  504. time_list = list(range(0, normalize_cycle, group_len))
  505. for turbine in turbines:
  506. turbine_sorted = turbine.sort_values(by='time').reset_index(drop=True)
  507. grey_start_index = int(len(turbine_sorted) * 0.1)
  508. grey_end_index = int(len(turbine_sorted) * 0.9)
  509. subset_grey = turbine_sorted[grey_start_index:grey_end_index]
  510. turbine_sorted = ff.median_filter_correction(turbine_sorted, 2, 10)
  511. mean_grey = subset_grey['grey'].mean() * 0.8
  512. n = len(turbine_sorted)
  513. n_10 = int(0.1 * n)
  514. is_extreme = (turbine_sorted.index < n_10) | (turbine_sorted.index >= len(turbine_sorted) - n_10)
  515. meets_condition = turbine_sorted['grey'] > mean_grey
  516. turbine_sorted = turbine_sorted[~is_extreme | (is_extreme & meets_condition)]
  517. first_time = turbine_sorted['time'].iloc[0]
  518. bins = list(range(int(first_time), int(turbine_sorted['time'].max()), group_len))
  519. grouped = turbine_sorted.groupby(pd.cut(turbine_sorted['time'], bins=bins, right=False))
  520. processed_df = pd.DataFrame()
  521. scattered_df = pd.DataFrame()
  522. mean_points = []
  523. diff_points = []
  524. for _, group in grouped:
  525. quantile_5 = group['distance'].quantile(0.05)
  526. quantile_95 = group['distance'].quantile(0.95)
  527. filtered_group = group[(group['distance'] > quantile_5) & (group['distance'] < quantile_95)]
  528. mean_point = filtered_group['distance'].mean()
  529. mean_points.append(mean_point)
  530. for i in range(len(mean_points) - 1):
  531. diff = abs(mean_points[i + 1] - mean_points[i])
  532. diff_points.append(diff)
  533. start_index = int(len(diff_points) * 0.05)
  534. end_index = int(len(diff_points) * 0.95)
  535. subset1 = diff_points[start_index:end_index]
  536. sdr_diff = np.max(subset1) * 1.1
  537. min_list.append(min(mean_points))
  538. first_index = np.where(diff_points < sdr_diff)[0][0]
  539. last_index = np.where(diff_points < sdr_diff)[0][-1]
  540. for index, (bin, group) in enumerate(grouped):
  541. quantile_5 = group['distance'].quantile(0.05)
  542. quantile_95 = group['distance'].quantile(0.95)
  543. filtered_group = group[(group['distance'] > quantile_5) & (group['distance'] < quantile_95)]
  544. if first_index <= index < last_index:
  545. mid_point = filtered_group.mean()
  546. mid_point_df = pd.DataFrame([mid_point])
  547. mid_point_df.iloc[0, 0] = time_list[index]
  548. processed_df = pd.concat([processed_df, mid_point_df], ignore_index=True)
  549. scattered_df = pd.concat([scattered_df, filtered_group], ignore_index=True)
  550. else:
  551. pass
  552. min_time = processed_df['time'].min()
  553. max_time = processed_df['time'].max()
  554. if sd_time == [-1, -1]:
  555. sd_time = [min_time, max_time]
  556. elif sd_time[0] < min_time:
  557. sd_time[0] = min_time
  558. elif sd_time[1] > max_time:
  559. sd_time[1] = max_time
  560. turbines_processed.append(processed_df)
  561. turbines_scattered.append(scattered_df)
  562. border_rows = []
  563. for i, turbine in enumerate(turbines_processed):
  564. closest_index_0 = (turbine['time'] - sd_time[0]).abs().idxmin()
  565. turbine.at[closest_index_0, 'time'] = sd_time[0]
  566. sd_time_row_0 = turbine.loc[closest_index_0]
  567. closest_index_1 = (turbine['time'] - sd_time[1]).abs().idxmin()
  568. turbine.at[closest_index_1, 'time'] = sd_time[1]
  569. sd_time_row_1 = turbine.loc[closest_index_1]
  570. turbines_processed[i] = turbine.iloc[closest_index_0:closest_index_1 + 1].reset_index(drop=True)
  571. sd_time_rows_turbine = pd.concat([pd.DataFrame([sd_time_row_0]), pd.DataFrame([sd_time_row_1])]
  572. , ignore_index=True)
  573. border_rows.append(sd_time_rows_turbine)
  574. return turbines_processed, turbines_scattered, border_rows, full_cycle, min_list
  575. def blade_shape(turbines_processed: List[pd.DataFrame]):
  576. row_counts = [df.shape[0] for df in turbines_processed]
  577. num_rows = min(row_counts)
  578. turbine_avg = pd.DataFrame(index=range(num_rows), columns=['time', 'distance'])
  579. turbine_diff = [pd.DataFrame(index=range(num_rows), columns=['time', 'distance']) for _ in turbines_processed]
  580. for i in range(num_rows):
  581. distances = [df.loc[i, 'distance'] for df in turbines_processed]
  582. avg_distance = sum(distances) / len(distances)
  583. time_value = turbines_processed[0].loc[i, 'time']
  584. turbine_avg.loc[i, 'time'] = time_value
  585. turbine_avg.loc[i, 'distance'] = avg_distance
  586. for j in range(len(distances)):
  587. distances[j] = distances[j] - avg_distance
  588. turbine_diff[j].loc[i, 'time'] = time_value
  589. turbine_diff[j].loc[i, 'distance'] = distances[j]
  590. return turbine_avg, turbine_diff
  591. def coordinate_normalize(tip_border_rows: List[pd.DataFrame], tip_angle):
  592. tip_angle1 = np.deg2rad(tip_angle)
  593. tip_angle_list = []
  594. for turbine in tip_border_rows:
  595. tip_angle_cal0 = ((np.sin(tip_angle1) * turbine['distance'] - 0.07608) /
  596. (np.cos(tip_angle1) * turbine['distance']))
  597. tip_angle_cal = np.arctan(tip_angle_cal0)
  598. turbine['distance'] = (turbine['distance'] ** 2 + 0.0057881664 -
  599. 0.15216 * turbine['distance'] * np.sin(tip_angle1)) ** 0.5
  600. tip_angle_list.append(tip_angle_cal)
  601. tip_angle_new = float(np.mean(tip_angle_list))
  602. tip_angle_new1 = np.rad2deg(tip_angle_new)
  603. return tip_border_rows, tip_angle_new1
  604. def flange_coordinate_normalize(flange_cen_row: pd.DataFrame, flange_angle):
  605. flange_angle1 = np.deg2rad(flange_angle)
  606. center_y_mean = flange_cen_row['中心y'].mean()
  607. flange_cen_row_new = flange_cen_row.copy()
  608. flange_angle_cal0 = ((np.sin(flange_angle1) * center_y_mean - 0.07608) /
  609. (np.cos(flange_angle1) * center_y_mean))
  610. flange_angle_cal = np.arctan(flange_angle_cal0)
  611. flange_cen_row_new['中心y'] = (flange_cen_row_new['中心y'] ** 2 + 0.0057881664 -
  612. 0.15216 * flange_cen_row_new['中心y'] * np.sin(flange_angle1)) ** 0.5
  613. flange_angle_new = float(flange_angle_cal)
  614. flange_angle_new1 = np.rad2deg(flange_angle_new)
  615. return flange_cen_row_new, flange_angle_new1
  616. def blade_axis_cal(data_group: pd.DataFrame, start_points: pd.DataFrame, end_points: pd.DataFrame, horizon_angle: float,
  617. group_len: int, radius_blade: float):
  618. def fit_circle(df, v_fixed, top_k=5, prefilter=True):
  619. def smooth_savgol(y, window_length=101, polyorder=3):
  620. wl = min(window_length, len(y) if len(y) % 2 == 1 else len(y) - 1)
  621. if wl < 3:
  622. return y
  623. if wl % 2 == 0:
  624. wl -= 1
  625. return savgol_filter(y, wl, polyorder)
  626. t = np.asarray(df['time'])
  627. d_raw = np.asarray(df['distance'])
  628. d_smooth = smooth_savgol(d_raw, window_length=101, polyorder=3) if prefilter else d_raw
  629. x = v_fixed * t
  630. bounds = [(min(x) - 5, max(x) + 5),
  631. (min(d_smooth), max(d_smooth) + 10),
  632. (0.5, 10)]
  633. def residuals_sq(params):
  634. xc, yc, R = params
  635. if R <= 0:
  636. return 1e6 * np.ones_like(t)
  637. return (x - xc) ** 2 + (d_smooth - yc) ** 2 - R ** 2
  638. def objective_mean_sq(params):
  639. res = residuals_sq(params)
  640. return np.mean(res ** 2)
  641. result = differential_evolution(
  642. objective_mean_sq,
  643. bounds,
  644. strategy='rand2bin',
  645. mutation=(0.8, 1.2),
  646. recombination=0.8,
  647. popsize=30,
  648. maxiter=1000,
  649. polish=False,
  650. seed=42,
  651. workers=1
  652. )
  653. pop = result.population
  654. energies = result.population_energies
  655. idx = np.argsort(energies)[:top_k]
  656. candidates = pop[idx]
  657. best_rmse = np.inf
  658. best_result = None
  659. for cand in candidates:
  660. res = least_squares(
  661. residuals_sq,
  662. x0=cand,
  663. bounds=([-np.inf, -np.inf, 1e-6],
  664. [np.inf, np.inf, np.inf]),
  665. method='trf',
  666. loss='linear',
  667. max_nfev=50000,
  668. xtol=1e-12,
  669. ftol=1e-12,
  670. gtol=1e-12
  671. )
  672. xc_opt, yc_opt, R_opt = res.x
  673. Ri_all = np.sqrt((x - xc_opt) ** 2 + (d_smooth - yc_opt) ** 2)
  674. geo_rmse = np.sqrt(np.mean((Ri_all - R_opt) ** 2))
  675. if geo_rmse < best_rmse:
  676. best_rmse = geo_rmse
  677. best_result = [v_fixed, xc_opt, yc_opt, R_opt, geo_rmse]
  678. result_df = pd.DataFrame([best_result],
  679. columns=['旋转半径', '中心x', '中心y', '圆半径', '几何RMSE'])
  680. return result_df
  681. combined_df_sorted = pd.concat([start_points, end_points]).sort_values(by='time')
  682. if combined_df_sorted.iloc[0].equals(end_points.iloc[0]):
  683. combined_df_sorted = combined_df_sorted.iloc[1:]
  684. if combined_df_sorted.iloc[-1].equals(start_points.iloc[-1]):
  685. combined_df_sorted = combined_df_sorted.iloc[:-1]
  686. combined_df_sorted.reset_index(drop=True, inplace=True)
  687. start_times = combined_df_sorted['time'].tolist()
  688. data_group['distance'] = data_group['distance'] * np.cos(np.deg2rad(horizon_angle))
  689. normalize_cycle = start_times[1] - start_times[0]
  690. full_cycle = int((start_times[2] - start_times[0]) * 3)
  691. v_blade = 10000000 * np.pi * radius_blade / full_cycle
  692. angle_speed = (np.pi / full_cycle) * 5000000
  693. turbines = [pd.DataFrame() for _ in range(3)]
  694. for i in range(0, len(start_times), 2):
  695. start_time = start_times[i]
  696. end_time = start_times[i + 1]
  697. segment = data_group[(data_group['time'] > start_time) & (data_group['time'] <= end_time)]
  698. if segment is None or segment.empty:
  699. raise ValueError("Segment is empty")
  700. segment = segment.copy()
  701. ratio = (end_time - start_time) / normalize_cycle
  702. segment.loc[:, 'time'] = (segment['time'] - start_time) / ratio
  703. turbines[int(i / 2) % 3] = pd.concat([turbines[int(i / 2) % 3], segment])
  704. turbines_processed = []
  705. turbines_scattered = []
  706. result_df = pd.DataFrame()
  707. time_list = list(range(0, normalize_cycle, group_len))
  708. for turbine in turbines:
  709. turbine_sorted = turbine.sort_values(by='time').reset_index(drop=True)
  710. first_time = turbine_sorted['time'].iloc[0]
  711. bins = list(range(int(first_time), int(turbine_sorted['time'].max()), group_len))
  712. grouped = turbine_sorted.groupby(pd.cut(turbine_sorted['time'], bins=bins, right=False))
  713. process_df = pd.DataFrame()
  714. for index, (bin, group) in enumerate(grouped):
  715. mid_point = group.mean()
  716. mid_point_df = pd.DataFrame([mid_point])
  717. mid_point_df.iloc[0, 0] = time_list[index]
  718. process_df = pd.concat([process_df, mid_point_df], ignore_index=True)
  719. process_df['time'] = process_df['time'] / 5000000
  720. lower_bound = process_df['time'].quantile(0.2)
  721. upper_bound = process_df['time'].quantile(0.6)
  722. processed_df = process_df[(process_df['time'] >= lower_bound) & (process_df['time'] <= upper_bound)]
  723. blade_cen_est = fit_circle(processed_df, v_blade)
  724. processed_df['time'] = processed_df['time'] * v_blade
  725. turbines_processed.append(processed_df)
  726. turbines_scattered.append(turbine)
  727. result_df = pd.concat([result_df, blade_cen_est], ignore_index=True)
  728. if blade_cen_est['几何RMSE'].iloc[0] >= 0.1:
  729. raise ValueError("叶片几何误差过大")
  730. result_df_mean = result_df.mean(numeric_only=True).to_frame().T
  731. result_df_mean["中心y"] = result_df_mean["中心y"] / np.cos(np.deg2rad(horizon_angle))
  732. result_df["中心y"] = result_df["中心y"] / np.cos(np.deg2rad(horizon_angle))
  733. return result_df_mean, result_df, turbines_processed
  734. def radius_cal(border_rows, meas_angle, cen_dist, cen_angle, angle_main, angle_rotate):
  735. aero_dist = (pd.concat([df['distance'] for df in border_rows]).mean())
  736. radius = np.abs(aero_dist * np.sin(np.deg2rad(meas_angle - angle_main))
  737. - cen_dist * np.sin(np.deg2rad(cen_angle - angle_main)))
  738. return radius
  739. def blade_angle_aero_dist(border_rows: List[pd.DataFrame], radius: float, full_cycle: int,
  740. tower_dist: float, v_angle: float):
  741. v_speed = 2 * np.pi * radius / full_cycle
  742. aero_dist_list = []
  743. cen_blade = []
  744. for turbine in border_rows:
  745. mean_col2 = (turbine.iloc[1, 1] + turbine.iloc[0, 1]) / 2
  746. aero_dist = abs(mean_col2 - tower_dist) * np.cos(np.deg2rad(v_angle))
  747. aero_dist_list.append(aero_dist)
  748. cen_blade.append(mean_col2)
  749. aero_dist_list.append(np.mean(aero_dist_list))
  750. aero_dist_list = [round(num, 2) for num in aero_dist_list]
  751. return aero_dist_list, v_speed, cen_blade
  752. def blade_angle(border_rows: List[pd.DataFrame], cen_data: pd.DataFrame, radius: float, full_cycle: int,
  753. v_angle: float):
  754. v_speed = 2 * np.pi * radius / full_cycle
  755. values = []
  756. for df in border_rows:
  757. if df.shape[0] >= 2 and df.shape[1] >= 2:
  758. values.append(df.iloc[0, 1])
  759. values.append(df.iloc[1, 1])
  760. mean_value = sum(values) / len(values) if values else float('nan')
  761. for i in [0, 1, 2]:
  762. if np.abs(cen_data['中心y'].iloc[i] - mean_value) > 0.5:
  763. cen_data['中心y'].iloc[i] = mean_value
  764. if cen_data['中心x'].iloc[i] > 1.5:
  765. cen_data['中心x'].iloc[i] = 1.5
  766. if cen_data['中心x'].iloc[i] < 0.75:
  767. cen_data['中心x'].iloc[i] = 0.75
  768. pitch_angle_list = []
  769. for idx, turbine in enumerate(border_rows, start=1):
  770. diff_time = np.abs(cen_data['中心x'].iloc[idx - 1] - turbine.iloc[1, 0] * v_speed)
  771. diff_len = np.abs((cen_data['中心y'].iloc[idx - 1] - turbine.iloc[1, 1]) * np.cos(np.deg2rad(v_angle)))
  772. pitch_angle = np.degrees(np.arctan(diff_len / diff_time))
  773. pitch_angle_list.append(pitch_angle)
  774. pitch_mean = np.mean(pitch_angle_list)
  775. pitch_angle_list = [angle - pitch_mean for angle in pitch_angle_list]
  776. pitch_angle_list.append(max(pitch_angle_list) - min(pitch_angle_list))
  777. pitch_angle_list = [round(num, 2) for num in pitch_angle_list]
  778. return pitch_angle_list, v_speed, cen_data
  779. def find_param(path: str):
  780. path = path.replace('\\', '/')
  781. last_slash_index = path.rfind('/')
  782. result = path[last_slash_index + 1:]
  783. underscore_indices = []
  784. start = 0
  785. while True:
  786. index = result.find('_', start)
  787. if index == -1:
  788. break
  789. underscore_indices.append(index)
  790. start = index + 1
  791. wind_name = result[: underscore_indices[0]]
  792. turbine_code = result[underscore_indices[0] + 1: underscore_indices[1]]
  793. time_code = result[underscore_indices[1] + 1: underscore_indices[2]]
  794. sampling_fq = int(result[underscore_indices[2] + 1: underscore_indices[3]])
  795. tunnel_1 = float(result[underscore_indices[3] + 1: underscore_indices[4]])
  796. tunnel_2 = float(result[underscore_indices[4] + 1: -4])
  797. dt = datetime.strptime(time_code, "%Y%m%d%H%M%S")
  798. standard_time_str = dt.strftime("%Y-%m-%d %H:%M:%S")
  799. return wind_name, turbine_code, standard_time_str, sampling_fq, tunnel_1, tunnel_2
  800. def blade_dist_distribute_cal(data_group: pd.DataFrame, start_points: pd.DataFrame, end_points: pd.DataFrame,
  801. tower_dist: float, v_angle: float, blade_cen_dist: list):
  802. combined_df_sorted = pd.concat([start_points, end_points]).sort_values(by='time')
  803. if combined_df_sorted.iloc[0].equals(end_points.iloc[0]):
  804. combined_df_sorted = combined_df_sorted.iloc[1:]
  805. if combined_df_sorted.iloc[-1].equals(start_points.iloc[-1]):
  806. combined_df_sorted = combined_df_sorted.iloc[:-1]
  807. combined_df_sorted.reset_index(drop=True, inplace=True)
  808. start_times = combined_df_sorted['time'].tolist()
  809. normalize_cycle = start_times[1] - start_times[0]
  810. tower_clearance = [pd.DataFrame() for _ in range(3)]
  811. for i in range(0, len(start_times) - 2, 2):
  812. start_time = start_times[i]
  813. end_time = start_times[i + 1]
  814. segment = data_group[(data_group['time'] > start_time) & (data_group['time'] <= end_time)]
  815. min_distance = segment['distance'].min()
  816. clearance = np.abs(tower_dist - min_distance - blade_cen_dist[i % 3]) * np.cos(np.deg2rad(v_angle))
  817. r_speed = round(60 / ((start_times[i + 2] - start_times[i]) * 3 / 5000000), 2)
  818. ratio = (end_time - start_time) / normalize_cycle
  819. segment.loc[:, 'time'] = (segment['time'] - start_time) / ratio
  820. new_df = pd.DataFrame({
  821. 'r_speed': [r_speed],
  822. 'clearance': [clearance]
  823. })
  824. tower_clearance[i % 3] = pd.concat([tower_clearance[i % 3], new_df])
  825. tower_clearance = [df.sort_values(by='r_speed') for df in tower_clearance]
  826. return tower_clearance