import os import json import pandas as pd import numpy as np import matplotlib.pyplot as plt from typing import Tuple, List import warnings import sys import frequency_filter as ff from datetime import datetime warnings.filterwarnings("ignore", category=FutureWarning) plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False def result_main(): python_interpreter_path = sys.executable project_directory = os.path.dirname(python_interpreter_path) data_folder = os.path.join(project_directory, 'data') if not os.path.exists(data_folder): os.makedirs(data_folder) csv_file_path = os.path.join(data_folder, 'history_data.csv') if not os.path.exists(csv_file_path): pd.DataFrame(columns=['时间', '场站', '风机编号', '采样频率', '叶片1角度偏差', '叶片2角度偏差', '叶片3角度偏差', '相对角度偏差', '叶片1净空值', '叶片2净空值', '叶片3净空值', '叶片1扭转', '叶片2扭转', '叶片3扭转', '平均扭转', '振动幅值', '振动主频']).to_csv(csv_file_path, index=False) return csv_file_path def delete_data(name): python_interpreter_path = sys.executable project_directory = os.path.dirname(python_interpreter_path) data_folder = os.path.join(project_directory, 'data') csv_file_path = os.path.join(data_folder, 'history_data.csv') df = pd.read_csv(csv_file_path) condition = ((df['时间'].astype(str).str.contains(name[0])) & (df['场站'].astype(str).str.contains(name[1])) & (df['风机编号'].astype(str).str.contains(name[2]))) df = df[~condition] df.to_csv(csv_file_path, index=False) return csv_file_path def history_data(name): time_code = name[0] wind_name = name[1] turbine_code = name[2] python_interpreter_path = sys.executable project_directory = os.path.dirname(python_interpreter_path) data_folder = os.path.join(project_directory, 'data') time_code_cleaned = time_code.replace("-", "").replace(":", "").replace(" ", "") json_filename = f"{wind_name}_{turbine_code}_{time_code_cleaned}.json" json_file_path = os.path.join(data_folder, json_filename) if not os.path.exists(json_file_path): raise ValueError("文件不存在") with open(json_file_path, 'r') as f: data = json.load(f) return data def data_analyse(path: List[str]): locate_file = path[0] measure_file = path[1] noise_reduction = 0.000001 min_difference = 1.5 angle_cone = float(path[2]) axial_inclination = float(path[3]) return_list = [] wind_name, turbine_code, time_code, sampling_fq, angle_nan, angle_cen = find_param(locate_file) wind_name_1, turbine_code_1, time_code_1, sampling_fq_1, angle_tip, angle_root = find_param(measure_file) sampling_fq_1 = sampling_fq_1 * 1000 sampling_fq = sampling_fq * 1000 data_nan, data_cen = process_data(locate_file) data_tip, data_root = process_data(measure_file) start_tip, end_tip, filtered_data_tip = cycle_calculate(data_tip, noise_reduction, min_difference) start_root, end_root, filtered_data_root = cycle_calculate(data_root, noise_reduction, min_difference) filtered_data_cen = tower_filter(data_cen, noise_reduction) dist_cen = np.mean(filtered_data_cen.iloc[:, 1].tolist()) filtered_data_cen.iloc[:, 1] = filtered_data_cen.iloc[:, 1] * np.cos(np.deg2rad(angle_cen)) if end_tip.iloc[0, 0] < start_root.iloc[0, 0]: start_tip = start_tip.drop(start_tip.index[0]) end_tip = end_tip.drop(end_tip.index[0]) if start_root.iloc[0, 0] < start_tip.iloc[0, 0] < end_tip.iloc[0, 0] < end_root.iloc[0, 0]: pass else: raise ValueError("The elements are not in the expected order.") tower_dist_tip = ff.tower_cal(filtered_data_tip, start_tip, end_tip, sampling_fq_1) tower_dist_root = ff.tower_cal(filtered_data_root, start_root, end_root, sampling_fq_1) lowpass_data, fft_x, fft_y, tower_freq, tower_max = ff.process_fft(filtered_data_cen, sampling_fq) result_line_tip, result_scatter_tip, border_rows_tip, cycle_len_tip, min_tip \ = data_normalize(filtered_data_tip, start_tip, end_tip) result_line_root, result_scatter_root, border_rows_root, cycle_len_root, min_root \ = data_normalize(filtered_data_root, start_root, end_root) result_avg_tip, result_diff_tip = blade_shape(result_line_tip) result_avg_root, result_diff_root = blade_shape(result_line_root) border_rows_tip_new, angle_tip_new = coordinate_normalize(border_rows_tip, angle_tip) tip_r = radius_cal(border_rows_tip_new, angle_tip_new, dist_cen, angle_cen, axial_inclination, angle_cone) root_r = radius_cal(border_rows_root, angle_root, dist_cen, angle_cen, axial_inclination, angle_cone) pitch_angle_tip, aero_dist_tip, v_speed_tip, cen_blade_tip = ( blade_angle_aero_dist(border_rows_tip, tip_r, cycle_len_tip, tower_dist_tip, angle_tip_new)) pitch_angle_root, aero_dist_root, v_speed_root, cen_blade_root = ( blade_angle_aero_dist(border_rows_root, root_r, cycle_len_root, tower_dist_root, angle_root)) cen_blade_tip_array = np.array(cen_blade_tip) min_tip_array = np.array(min_tip) abs_diff = np.abs(cen_blade_tip_array - min_tip_array) blade_dist_tip = abs_diff * np.cos(np.deg2rad(angle_tip_new)) blade_dist_tip.tolist() dist_distribute = blade_dist_distribute_cal(filtered_data_tip, start_tip, end_tip, tower_dist_tip, angle_tip_new, blade_dist_tip) dist_distribute = [df.round(5) for df in dist_distribute] min_values = [] min_keys = [] max_values = [] max_keys = [] mean_values = [] for df in dist_distribute: second_col_min = df[df.columns[1]].min() second_col_max = df[df.columns[1]].max() min_row = df[df[df.columns[1]] == second_col_min] max_row = df[df[df.columns[1]] == second_col_max] min_values.append(round(second_col_min, 2)) min_keys.append(round(min_row.iloc[0][df.columns[0]], 2)) max_values.append(round(second_col_max, 2)) max_keys.append(round(max_row.iloc[0][df.columns[0]], 2)) for i in range(3): mean_values.append(round((max_values[i] + min_values[i]) / 2, 2)) for df in result_line_tip: first_column = df.iloc[:, 0] sec_column = df.iloc[:, 1] df.iloc[:, 0] = first_column * v_speed_tip df.iloc[:, 1] = sec_column * np.cos(np.deg2rad(angle_tip_new)) for df in result_line_root: first_column = df.iloc[:, 0] sec_column = df.iloc[:, 1] df.iloc[:, 0] = first_column * v_speed_root df.iloc[:, 1] = sec_column * np.cos(np.deg2rad(angle_root)) avg_tip = result_avg_tip.iloc[:, 0] result_avg_tip.iloc[:, 0] = avg_tip * v_speed_tip avg_root = result_avg_root.iloc[:, 0] result_avg_root.iloc[:, 0] = avg_root * v_speed_root twist_1 = round(np.abs(pitch_angle_root[0] - pitch_angle_tip[0]), 2) twist_2 = round(np.abs(pitch_angle_root[1] - pitch_angle_tip[1]), 2) twist_3 = round(np.abs(pitch_angle_root[2] - pitch_angle_tip[2]), 2) twist_avg = round((twist_1 + twist_2 + twist_3) / 3, 2) sampling_num = int(0.015 * sampling_fq_1) data_tip.iloc[:, 0] = data_tip.iloc[:, 0] / 5000000 data_root.iloc[:, 0] = data_root.iloc[:, 0] / 5000000 lowpass_data.iloc[:, 0] = lowpass_data.iloc[:, 0] / 5000000 return_list.append(str(time_code)) return_list.append(str(wind_name)) return_list.append(str(turbine_code)) return_list.append(sampling_fq_1) return_list.append(pitch_angle_root[0]) return_list.append(pitch_angle_root[1]) return_list.append(pitch_angle_root[2]) return_list.append(pitch_angle_root[3]) return_list.append(mean_values[0]) return_list.append(mean_values[1]) return_list.append(mean_values[2]) return_list.append(twist_1) return_list.append(twist_2) return_list.append(twist_3) return_list.append(twist_avg) return_list.append(tower_max) return_list.append(tower_freq) df_new_row = pd.DataFrame([return_list], columns=['时间', '场站', '风机编号', '采样频率', '叶片1角度偏差', '叶片2角度偏差', '叶片3角度偏差', '相对角度偏差', '叶片1净空值', '叶片2净空值', '叶片3净空值', '叶片1扭转', '叶片2扭转', '叶片3扭转', '平均扭转', '振动幅值', '振动主频']) json_output = { 'original_plot': { 'blade_tip': { 'xdata': data_tip.iloc[:, 0].tolist()[::sampling_num], 'ydata': data_tip.iloc[:, 1].tolist()[::sampling_num] }, 'blade_root': { 'xdata': data_root.iloc[:, 0].tolist()[::sampling_num], 'ydata': data_root.iloc[:, 1].tolist()[::sampling_num] } }, 'fft_plot': { 'lowpass': { 'xdata': lowpass_data['time'].tolist()[::sampling_num], 'ydata': lowpass_data['distance_filtered'].tolist()[::sampling_num], 'xmax': max(lowpass_data['time'].tolist()), 'xmin': min(lowpass_data['time'].tolist()), 'ymax': max(lowpass_data['distance_filtered'].tolist()) + 0.02, 'ymin': min(lowpass_data['distance_filtered'].tolist()) - 0.02 }, 'fft': { 'xdata': fft_x, 'ydata': fft_y, 'xmax': max(fft_x), 'xmin': min(fft_x), 'ymax': max(fft_y) + 0.02, 'ymin': 0 } }, 'blade_tip': { 'first_blade': { 'xdata': result_line_tip[0].iloc[:, 0].tolist(), 'ydata': result_line_tip[0].iloc[:, 1].tolist() }, 'second_blade': { 'xdata': result_line_tip[1].iloc[:, 0].tolist(), 'ydata': result_line_tip[1].iloc[:, 1].tolist() }, 'third_blade': { 'xdata': result_line_tip[2].iloc[:, 0].tolist(), 'ydata': result_line_tip[2].iloc[:, 1].tolist() }, 'avg_blade': { 'xdata': result_avg_tip.iloc[:, 0].tolist(), 'ydata': result_avg_tip.iloc[:, 1].tolist() } }, 'blade_root': { 'first_blade': { 'xdata': result_line_root[0].iloc[:, 0].tolist(), 'ydata': result_line_root[0].iloc[:, 1].tolist() }, 'second_blade': { 'xdata': result_line_root[1].iloc[:, 0].tolist(), 'ydata': result_line_root[1].iloc[:, 1].tolist() }, 'third_blade': { 'xdata': result_line_root[2].iloc[:, 0].tolist(), 'ydata': result_line_root[2].iloc[:, 1].tolist() }, 'avg_blade': { 'xdata': result_avg_root.iloc[:, 0].tolist(), 'ydata': result_avg_root.iloc[:, 1].tolist() } }, 'dist_distribution': { 'first_blade': { 'xdata': dist_distribute[0].iloc[:, 0].tolist(), 'ydata': dist_distribute[0].iloc[:, 1].tolist() }, 'second_blade': { 'xdata': dist_distribute[1].iloc[:, 0].tolist(), 'ydata': dist_distribute[1].iloc[:, 1].tolist() }, 'third_blade': { 'xdata': dist_distribute[2].iloc[:, 0].tolist(), 'ydata': dist_distribute[2].iloc[:, 1].tolist() } }, 'analyse_table': { 'pitch_angle_diff': { 'blade_1': pitch_angle_root[0], 'blade_2': pitch_angle_root[1], 'blade_3': pitch_angle_root[2], 'blade_relate': pitch_angle_root[3] }, 'aero_dist': { 'first_blade': { 'x_min': min_keys[0], 'y_min': min_values[0], 'x_max': max_keys[0], 'y_max': max_values[0], 'y_diff': np.abs(max_values[0] - min_values[0]), 'y_ava': mean_values[0] }, 'second_blade': { 'x_min': min_keys[1], 'y_min': min_values[1], 'x_max': max_keys[1], 'y_max': max_values[1], 'y_diff': np.abs(max_values[1] - min_values[1]), 'y_ava': mean_values[1] }, 'third_blade': { 'x_min': min_keys[2], 'y_min': min_values[2], 'x_max': max_keys[2], 'y_max': max_values[2], 'y_diff': np.abs(max_values[2] - min_values[2]), 'y_ava': mean_values[2] } }, 'blade_twist': { 'blade_1': twist_1, 'blade_2': twist_2, 'blade_3': twist_3, 'blade_avg': twist_avg }, 'tower_vibration': { 'max_vibration': tower_max, 'main_vibration_freq': tower_freq } } } python_interpreter_path = sys.executable project_directory = os.path.dirname(python_interpreter_path) data_folder = os.path.join(project_directory, 'data') if not os.path.exists(data_folder): os.makedirs(data_folder) csv_file_path = os.path.join(data_folder, 'history_data.csv') if not os.path.exists(csv_file_path): pd.DataFrame(columns=['时间', '场站', '风机编号', '采样频率', '叶片1角度偏差', '叶片2角度偏差', '叶片3角度偏差', '相对角度偏差', '叶片1净空值', '叶片2净空值', '叶片3净空值', '叶片1扭转', '叶片2扭转', '叶片3扭转', '平均扭转', '振动幅值', '振动主频']).to_csv(csv_file_path, index=False) df_new_row.to_csv(csv_file_path, mode='a', header=False, index=False) time_code_cleaned = time_code.replace("-", "").replace(":", "").replace(" ", "") json_filename = f"{wind_name}_{turbine_code}_{time_code_cleaned}.json" json_file_path = os.path.join(data_folder, json_filename) with open(json_file_path, 'w') as json_file: json.dump(json_output, json_file, indent=4) return json_output def process_data(file_path): data = pd.read_csv(file_path, usecols=[1, 3, 8], header=None, engine='c') data = data.head(int(len(data) * 0.95)) max_value = data.iloc[:, 0].max() max_index = data.iloc[:, 0].idxmax() min_index = data.iloc[:, 0].idxmin() if min_index == max_index + 1: data.iloc[min_index:, 0] += max_value last_time = data.iloc[-1, 0] first_time = data.iloc[0, 0] data = data[data.iloc[:, 0] >= first_time] data = data[data.iloc[:, 0] <= last_time] data.reset_index(drop=True, inplace=True) min_time = data.iloc[:, 0].min() data.iloc[:, 0] -= min_time data_1 = data.iloc[:, [0, 1]] data_2 = data.iloc[:, [0, 2]] data_1.columns = ['time', 'distance'] data_2.columns = ['time', 'distance'] return data_1, data_2 def tower_filter(data_group: pd.DataFrame, noise_threshold: float): distance_counts = data_group['distance'].value_counts(normalize=True) noise_distance_threshold = distance_counts[distance_counts < noise_threshold].index noise_indices = data_group[data_group['distance'].isin(noise_distance_threshold)].index data_group.loc[noise_indices, 'distance'] = np.nan top_5_distances = distance_counts.head(5).index mean_values = data_group[data_group['distance'].isin(top_5_distances)]['distance'].mean() data_group.loc[(data_group['distance'] < mean_values - 20) | ( data_group['distance'] > mean_values * 1.1), 'distance'] = np.nan data_group['distance'] = data_group['distance'].fillna(method='ffill') filtered_data = data_group return filtered_data def cycle_calculate(data_group: pd.DataFrame, noise_threshold: float, min_distance: float): distance_counts = data_group['distance'].value_counts(normalize=True) noise_distance_threshold = distance_counts[distance_counts < noise_threshold].index noise_indices = data_group[data_group['distance'].isin(noise_distance_threshold)].index data_group.loc[noise_indices, 'distance'] = np.nan top_5_distances = distance_counts.head(5).index mean_values = data_group[data_group['distance'].isin(top_5_distances)]['distance'].mean() data_group.loc[(data_group['distance'] < mean_values - 30) | ( data_group['distance'] > mean_values * 1.1), 'distance'] = np.nan data_group['distance'] = data_group['distance'].fillna(method='ffill') filtered_data = data_group filtered_data['distance_diff'] = filtered_data['distance'].diff() large_diff_indices = filtered_data[filtered_data['distance_diff'] > min_distance].index small_diff_indices = filtered_data[filtered_data['distance_diff'] < -min_distance].index filtered_data = filtered_data.drop(columns=['distance_diff']) start_points = pd.DataFrame() end_points = pd.DataFrame() for idx in large_diff_indices: current_distance = filtered_data.loc[idx, 'distance'] next_rows_large = filtered_data.loc[idx - 200: idx - 1] if next_rows_large['distance'].le(current_distance - min_distance).all(): end_points = pd.concat([end_points, filtered_data.loc[[idx - 1]]]) for idx in small_diff_indices: current_distance = filtered_data.loc[idx - 1, 'distance'] next_rows_small = filtered_data.iloc[idx: idx + 200] if next_rows_small['distance'].le(current_distance - min_distance).all(): start_points = pd.concat([start_points, filtered_data.loc[[idx]]]) if end_points.iloc[0, 0] < start_points.iloc[0, 0]: end_points = end_points.drop(end_points.index[0]) if end_points.iloc[-1, 0] < start_points.iloc[-1, 0]: start_points = start_points.drop(start_points.index[-1]) else: pass return start_points, end_points, filtered_data def data_normalize(data_group: pd.DataFrame, start_points: pd.DataFrame, end_points: pd.DataFrame) \ -> Tuple[List[pd.DataFrame], List[pd.DataFrame], List[pd.DataFrame], int, list]: combined_df_sorted = pd.concat([start_points, end_points]).sort_values(by='time') if combined_df_sorted.iloc[0].equals(end_points.iloc[0]): combined_df_sorted = combined_df_sorted.iloc[1:] if combined_df_sorted.iloc[-1].equals(start_points.iloc[-1]): combined_df_sorted = combined_df_sorted.iloc[:-1] combined_df_sorted.reset_index(drop=True, inplace=True) start_times = combined_df_sorted['time'].tolist() normalize_cycle = start_times[1] - start_times[0] full_cycle = int((start_times[2] - start_times[0]) * 3) turbines = [pd.DataFrame() for _ in range(3)] for i in range(0, len(start_times), 2): start_time = start_times[i] end_time = start_times[i + 1] segment = data_group[(data_group['time'] > start_time) & (data_group['time'] <= end_time)] if segment is None: pass else: ratio = (end_time - start_time) / normalize_cycle segment.loc[:, 'time'] = (segment['time'] - start_time) / ratio turbines[i % 3] = pd.concat([turbines[i % 3], segment]) turbines_processed = [] turbines_scattered = [] min_list = [] sd_time = [-1, -1] time_list = list(range(0, normalize_cycle, 9000)) for turbine in turbines: turbine_sorted = turbine.sort_values(by='time').reset_index(drop=True) first_time = turbine_sorted['time'].iloc[0] bins = list(range(int(first_time), int(turbine_sorted['time'].max()), 9000)) grouped = turbine_sorted.groupby(pd.cut(turbine_sorted['time'], bins=bins, right=False)) processed_df = pd.DataFrame() scattered_df = pd.DataFrame() mean_points = [] diff_points = [] for _, group in grouped: quantile_5 = group['distance'].quantile(0.05) quantile_95 = group['distance'].quantile(0.95) filtered_group = group[(group['distance'] > quantile_5) & (group['distance'] < quantile_95)] mean_point = filtered_group['distance'].mean() mean_points.append(mean_point) for i in range(len(mean_points) - 1): diff = abs(mean_points[i + 1] - mean_points[i]) diff_points.append(diff) start_index = int(len(diff_points) * 0.05) end_index = int(len(diff_points) * 0.95) subset1 = diff_points[start_index:end_index] sdr_diff = np.max(subset1) * 1.1 min_list.append(min(mean_points)) first_index = np.where(diff_points < sdr_diff)[0][0] last_index = np.where(diff_points < sdr_diff)[0][-1] for index, (bin, group) in enumerate(grouped): quantile_5 = group['distance'].quantile(0.05) quantile_95 = group['distance'].quantile(0.95) filtered_group = group[(group['distance'] > quantile_5) & (group['distance'] < quantile_95)] if first_index <= index < last_index: mid_point = filtered_group.mean() mid_point_df = pd.DataFrame([mid_point]) mid_point_df.iloc[0, 0] = time_list[index] processed_df = pd.concat([processed_df, mid_point_df], ignore_index=True) scattered_df = pd.concat([scattered_df, filtered_group], ignore_index=True) else: pass min_time = processed_df['time'].min() max_time = processed_df['time'].max() if sd_time == [-1, -1]: sd_time = [min_time, max_time] elif sd_time[0] < min_time: sd_time[0] = min_time elif sd_time[1] > max_time: sd_time[1] = max_time turbines_processed.append(processed_df) turbines_scattered.append(scattered_df) border_rows = [] for i, turbine in enumerate(turbines_processed): closest_index_0 = (turbine['time'] - sd_time[0]).abs().idxmin() turbine.at[closest_index_0, 'time'] = sd_time[0] sd_time_row_0 = turbine.loc[closest_index_0] closest_index_1 = (turbine['time'] - sd_time[1]).abs().idxmin() turbine.at[closest_index_1, 'time'] = sd_time[1] sd_time_row_1 = turbine.loc[closest_index_1] turbines_processed[i] = turbine.iloc[closest_index_0:closest_index_1 + 1].reset_index(drop=True) sd_time_rows_turbine = pd.concat([pd.DataFrame([sd_time_row_0]), pd.DataFrame([sd_time_row_1])] , ignore_index=True) border_rows.append(sd_time_rows_turbine) return turbines_processed, turbines_scattered, border_rows, full_cycle, min_list def blade_shape(turbines_processed: List[pd.DataFrame]): row_counts = [df.shape[0] for df in turbines_processed] num_rows = min(row_counts) turbine_avg = pd.DataFrame(index=range(num_rows), columns=['time', 'distance']) turbine_diff = [pd.DataFrame(index=range(num_rows), columns=['time', 'distance']) for _ in turbines_processed] for i in range(num_rows): distances = [df.loc[i, 'distance'] for df in turbines_processed] avg_distance = sum(distances) / len(distances) time_value = turbines_processed[0].loc[i, 'time'] turbine_avg.loc[i, 'time'] = time_value turbine_avg.loc[i, 'distance'] = avg_distance for j in range(len(distances)): distances[j] = distances[j] - avg_distance turbine_diff[j].loc[i, 'time'] = time_value turbine_diff[j].loc[i, 'distance'] = distances[j] return turbine_avg, turbine_diff def coordinate_normalize(tip_border_rows: List[pd.DataFrame], tip_angle): tip_angle1 = np.deg2rad(tip_angle) tip_angle_list = [] for turbine in tip_border_rows: tip_angle_cal0 = ((np.sin(tip_angle1) * turbine['distance'] - 0.07608) / (np.cos(tip_angle1) * turbine['distance'])) tip_angle_cal = np.arctan(tip_angle_cal0) turbine['distance'] = (turbine['distance'] ** 2 + 0.0057881664 - 0.15216 * turbine['distance'] * np.sin(tip_angle1)) ** 0.5 tip_angle_list.append(tip_angle_cal) tip_angle_new = float(np.mean(tip_angle_list)) tip_angle_new1 = np.rad2deg(tip_angle_new) return tip_border_rows, tip_angle_new1 def radius_cal(border_rows, meas_angle, cen_dist, cen_angle, angle_main, angle_rotate): aero_dist = (pd.concat([df['distance'] for df in border_rows]).mean()) cen_x = np.cos(np.deg2rad(cen_angle)) * cen_dist cen_y = np.sin(np.deg2rad(cen_angle)) * cen_dist aero_x = np.cos(np.deg2rad(meas_angle)) * aero_dist aero_y = np.sin(np.deg2rad(meas_angle)) * aero_dist theta_4 = np.tan(np.pi - np.deg2rad(angle_main)) theta_5 = np.tan(np.pi / 2 - np.deg2rad(angle_main) - np.deg2rad(angle_rotate)) if theta_5 > 1000: radius = np.abs((cen_y - aero_y) - theta_4 * (cen_x - aero_x)) else: radius = (np.abs((theta_4 * (cen_x - aero_x) - (cen_y - aero_y)) / (theta_4 - theta_5)) * (1 + theta_5 ** 2) ** 0.5) return radius def blade_angle_aero_dist(border_rows: List[pd.DataFrame], radius: float, full_cycle: int, tower_dist: float, v_angle: float): v_speed = 2 * np.pi * radius / full_cycle pitch_angle_list = [] aero_dist_list = [] cen_blade = [] for turbine in border_rows: diff_time = turbine.iloc[1, 0] - turbine.iloc[0, 0] diff_len = turbine.iloc[1, 1] - turbine.iloc[0, 1] mean_col2 = (turbine.iloc[1, 1] + turbine.iloc[0, 1]) / 2 aero_dist = abs(mean_col2 - tower_dist) * np.cos(np.deg2rad(v_angle)) pitch_angle = np.degrees(np.arctan(diff_len / (diff_time * v_speed))) pitch_angle_list.append(pitch_angle) aero_dist_list.append(aero_dist) cen_blade.append(mean_col2) pitch_mean = np.mean(pitch_angle_list) pitch_angle_list = [angle - pitch_mean for angle in pitch_angle_list] pitch_angle_list.append(max(pitch_angle_list) - min(pitch_angle_list)) aero_dist_list.append(np.mean(aero_dist_list)) pitch_angle_list = [round(num, 2) for num in pitch_angle_list] aero_dist_list = [round(num, 2) for num in aero_dist_list] return pitch_angle_list, aero_dist_list, v_speed, cen_blade def find_param(path: str): path = path.replace('\\', '/') last_slash_index = path.rfind('/') result = path[last_slash_index + 1:] underscore_indices = [] start = 0 while True: index = result.find('_', start) if index == -1: break underscore_indices.append(index) start = index + 1 wind_name = result[: underscore_indices[0]] turbine_code = result[underscore_indices[0] + 1: underscore_indices[1]] time_code = result[underscore_indices[1] + 1: underscore_indices[2]] sampling_fq = int(result[underscore_indices[2] + 1: underscore_indices[3]]) tunnel_1 = float(result[underscore_indices[3] + 1: underscore_indices[4]]) tunnel_2 = float(result[underscore_indices[4] + 1: -4]) dt = datetime.strptime(time_code, "%Y%m%d%H%M%S") standard_time_str = dt.strftime("%Y-%m-%d %H:%M:%S") return wind_name, turbine_code, standard_time_str, sampling_fq, tunnel_1, tunnel_2 def blade_dist_distribute_cal(data_group: pd.DataFrame, start_points: pd.DataFrame, end_points: pd.DataFrame, tower_dist: float, v_angle: float, blade_cen_dist: list): combined_df_sorted = pd.concat([start_points, end_points]).sort_values(by='time') if combined_df_sorted.iloc[0].equals(end_points.iloc[0]): combined_df_sorted = combined_df_sorted.iloc[1:] if combined_df_sorted.iloc[-1].equals(start_points.iloc[-1]): combined_df_sorted = combined_df_sorted.iloc[:-1] combined_df_sorted.reset_index(drop=True, inplace=True) start_times = combined_df_sorted['time'].tolist() normalize_cycle = start_times[1] - start_times[0] tower_clearance = [pd.DataFrame() for _ in range(3)] for i in range(0, len(start_times) - 2, 2): start_time = start_times[i] end_time = start_times[i + 1] segment = data_group[(data_group['time'] > start_time) & (data_group['time'] <= end_time)] min_distance = segment['distance'].min() clearance = np.abs(tower_dist - min_distance - blade_cen_dist[i % 3]) * np.cos(np.deg2rad(v_angle)) r_speed = round(60 / ((start_times[i + 2] - start_times[i]) * 3 / 5000000), 2) ratio = (end_time - start_time) / normalize_cycle segment.loc[:, 'time'] = (segment['time'] - start_time) / ratio new_df = pd.DataFrame({ 'r_speed': [r_speed], 'clearance': [clearance] }) tower_clearance[i % 3] = pd.concat([tower_clearance[i % 3], new_df]) tower_clearance = [df.sort_values(by='r_speed') for df in tower_clearance] return tower_clearance