|
|
@@ -124,7 +124,7 @@ def data_analyse(path: List[str]):
|
|
|
rotate_angle = float(path[5]) # 偏航角
|
|
|
skew_angle_meas = 0 # 偏航角
|
|
|
noise_reduction = 0.000001 # 如果一个距离值的所有样本量小于总样本量的noise_reduction,则被去掉
|
|
|
- min_difference = 2 # 如果相邻2个点的距离差大于min_difference,则被注意是否是周期节点
|
|
|
+ min_difference = 1.5 # 如果相邻2个点的距离差大于min_difference,则被注意是否是周期节点
|
|
|
group_length = [10000, 10000, 5000, 10000] # 计算叶片轮廓时每个小切片的长度,4个数分别为叶中、叶根、叶尖、轴线计算切片长度
|
|
|
lift_up_limit = 0 # 如果法兰中的数据大于这个值,则提升5m
|
|
|
return_list = []
|
|
|
@@ -235,22 +235,24 @@ def data_analyse(path: List[str]):
|
|
|
|
|
|
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)))
|
|
|
|
|
|
- blade_axis = blade_axis_cal(filtered_data_flange, start_flange, end_flange,
|
|
|
- angle_flange + angle_cone + axial_inclination, group_length[3])
|
|
|
- blade_axis_new, angle_flange_new = flange_coordinate_normalize(blade_axis, angle_flange)
|
|
|
-
|
|
|
# 对叶片的边界点表做半径计算
|
|
|
flange_r = radius_cal(border_rows_flange_new, angle_flange_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)
|
|
|
nan_r = radius_cal(border_rows_nan_new, angle_nan_new, dist_cen, angle_cen, axial_inclination, angle_cone)
|
|
|
|
|
|
+ blade_axis, blade_axis_tuple, result_line_flange = blade_axis_cal(filtered_data_flange, start_flange, end_flange,
|
|
|
+ angle_flange + angle_cone + axial_inclination, group_length[3], flange_r)
|
|
|
+
|
|
|
+ blade_axis_new, angle_flange_new = flange_coordinate_normalize(blade_axis, angle_flange)
|
|
|
+ blade_axis_tuple_new, angle_flange_new = flange_coordinate_normalize(blade_axis_tuple, angle_flange)
|
|
|
+
|
|
|
if np.abs((root_r - flange_r) - d_radius) > 0.5:
|
|
|
print(str(root_r - flange_r) + "对比" + str(d_radius))
|
|
|
- raise ValueError("Radius err1.")
|
|
|
+ root_r = flange_r + d_radius
|
|
|
|
|
|
if np.abs(flange_root_dist - d_radius) > 0.5:
|
|
|
print(str(flange_root_dist) + "对比" + str(d_radius))
|
|
|
- raise ValueError("Radius err2.")
|
|
|
+ root_r = flange_r + flange_root_dist
|
|
|
|
|
|
# root_r = d_radius + blade_axis_new["旋转半径"].iloc[0]
|
|
|
# root_flange_dist = d_radius / np.cos(np.deg2rad(angle_cone))
|
|
|
@@ -259,38 +261,30 @@ def data_analyse(path: List[str]):
|
|
|
# * np.cos(np.deg2rad(90 - angle_cone - axial_inclination - angle_flange_new)))
|
|
|
|
|
|
blade_axis_new["中心y"] = blade_axis_new["中心y"] - (flange_ava - root_ava)
|
|
|
+ blade_axis_tuple_new["中心y"] = blade_axis_tuple_new["中心y"] - (flange_ava - root_ava)
|
|
|
|
|
|
# 计算叶片测量位置处的绝对桨距角、相对桨距角、线速度、叶片内部中心点距离
|
|
|
aero_dist_flange, v_speed_flange, cen_blade_flange = (
|
|
|
blade_angle_aero_dist(border_rows_flange, flange_r, cycle_len_flange, tower_dist_flange, angle_flange_new))
|
|
|
- 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))
|
|
|
aero_dist_nan, v_speed_nan, cen_blade_nan = (
|
|
|
blade_angle_aero_dist(border_rows_nan_new, nan_r, cycle_len_nan, tower_dist_nan, angle_nan_new))
|
|
|
- pitch_angle_root, v_speed_root = (
|
|
|
- blade_angle(border_rows_root, blade_axis_new, root_r, cycle_len_root, angle_root + axial_inclination))
|
|
|
+ pitch_angle_root, v_speed_root, blade_axis_tuple_new = (
|
|
|
+ blade_angle(border_rows_root, blade_axis_tuple_new, root_r, cycle_len_root, angle_root + angle_cone + axial_inclination))
|
|
|
|
|
|
- blade_axis_new["中心y"] = blade_axis_new["中心y"]*np.cos(np.deg2rad(angle_root + angle_cone + axial_inclination))
|
|
|
+ blade_axis_tuple_new["中心y"] = blade_axis_tuple_new["中心y"]*np.cos(np.deg2rad(angle_root + angle_cone + axial_inclination))
|
|
|
|
|
|
# 将列表转换为 numpy 数组
|
|
|
- cen_blade_flange_array = np.array(cen_blade_flange)
|
|
|
cen_blade_nan_array = np.array(cen_blade_nan)
|
|
|
- min_flange_array = np.array(min_flange)
|
|
|
min_nan_array = np.array(min_nan)
|
|
|
|
|
|
# 计算叶片内部中心点距离与叶片最小值之间的差值
|
|
|
- abs_diff = np.abs(cen_blade_flange_array - min_flange_array)
|
|
|
abs_diff_nan = np.abs(cen_blade_nan_array - min_nan_array)
|
|
|
- blade_dist_flange = abs_diff * np.cos(np.deg2rad(angle_flange_new))
|
|
|
blade_dist_nan = abs_diff_nan * np.cos(np.deg2rad(angle_nan_new))
|
|
|
- blade_dist_flange.tolist()
|
|
|
blade_dist_nan.tolist()
|
|
|
|
|
|
# 计算叶片转速-净空散点表
|
|
|
- dist_distribute = blade_dist_distribute_cal(filtered_data_flange, start_flange, end_flange,
|
|
|
- tower_dist_flange, angle_flange_new, blade_dist_flange)
|
|
|
dist_distribute_nan = blade_dist_distribute_cal(filtered_data_nan, start_nan, end_nan,
|
|
|
- tower_dist_nan, angle_nan_new, blade_dist_nan)
|
|
|
+ tower_dist_nan, angle_nan_new + angle_cone + axial_inclination, blade_dist_nan)
|
|
|
# dist_distribute = [df.round(5) for df in dist_distribute]
|
|
|
dist_distribute = [df.round(5) for df in dist_distribute_nan]
|
|
|
|
|
|
@@ -314,20 +308,25 @@ def data_analyse(path: List[str]):
|
|
|
mean_values.append(round((max_values[i] + min_values[i]) / 2, 2))
|
|
|
|
|
|
# 将叶片线表数据乘以线速度,和俯仰角,得到叶片横截面的真实轮廓
|
|
|
- for df in result_line_flange:
|
|
|
- first_column = df.iloc[:, 0]
|
|
|
- sec_column = df.iloc[:, 1]
|
|
|
- df.iloc[:, 0] = first_column * v_speed_flange
|
|
|
- min_time = df.iloc[:, 0].min()
|
|
|
- df.iloc[:, 0] -= min_time
|
|
|
- df.iloc[:, 1] = sec_column * np.cos(np.deg2rad(angle_flange_new + angle_cone + axial_inclination))
|
|
|
+ # for i in range(3):
|
|
|
+ # df = result_line_flange[i]
|
|
|
+ # first_column = df.iloc[:, 0]
|
|
|
+ # sec_column = df.iloc[:, 1]
|
|
|
+ # df.iloc[:, 0] = first_column * v_speed_flange
|
|
|
+ # blade_axis_tuple.iloc[i, 1] = blade_axis_tuple.iloc[i, 1] * v_speed_flange * 5000000
|
|
|
+ # min_time = df.iloc[:, 0].min()
|
|
|
+ # df.iloc[:, 0] -= min_time
|
|
|
+ # blade_axis_tuple.iloc[i, 1] -= min_time
|
|
|
+
|
|
|
|
|
|
- for df in result_line_root:
|
|
|
+ for i in range(3):
|
|
|
+ df = result_line_root[i]
|
|
|
first_column = df.iloc[:, 0]
|
|
|
sec_column = df.iloc[:, 1]
|
|
|
df.iloc[:, 0] = first_column * v_speed_root
|
|
|
min_time = df.iloc[:, 0].min()
|
|
|
df.iloc[:, 0] -= min_time
|
|
|
+ blade_axis_tuple_new.iloc[i, 1] -= min_time
|
|
|
df.iloc[:, 1] = sec_column * np.cos(np.deg2rad(angle_root + angle_cone + axial_inclination))
|
|
|
|
|
|
for df in result_scatter_flange:
|
|
|
@@ -363,6 +362,45 @@ def data_analyse(path: List[str]):
|
|
|
data_root.iloc[:, 0] = data_root.iloc[:, 0] / 5000000
|
|
|
lowpass_data.iloc[:, 0] = lowpass_data.iloc[:, 0] / 5000000
|
|
|
|
|
|
+ # 将叶片轮廓旋转重合
|
|
|
+ rotated_root = [pd.DataFrame() for _ in range(3)]
|
|
|
+ for i in range(3):
|
|
|
+ angle_rad = np.deg2rad(-pitch_angle_root[i])
|
|
|
+ rotation_matrix = np.array([
|
|
|
+ [np.cos(angle_rad), -np.sin(angle_rad)],
|
|
|
+ [np.sin(angle_rad), np.cos(angle_rad)]
|
|
|
+ ])
|
|
|
+
|
|
|
+ # 获取中心点坐标
|
|
|
+ center_x = blade_axis_tuple_new.iloc[i, 1]
|
|
|
+ center_y = blade_axis_tuple_new.iloc[i, 2]
|
|
|
+
|
|
|
+ # 创建结果DataFrame
|
|
|
+ rotated_points = result_line_root[i].copy()
|
|
|
+
|
|
|
+ # 对每个点进行旋转
|
|
|
+ for idx, row in result_line_root[i].iterrows():
|
|
|
+ # 获取当前点坐标
|
|
|
+ x = row.iloc[0] # 获取第一列作为x坐标
|
|
|
+ y = row.iloc[1] # 获取第二列作为y坐标
|
|
|
+
|
|
|
+ # 将点平移到原点
|
|
|
+ translated_x = x - center_x
|
|
|
+ translated_y = y - center_y
|
|
|
+
|
|
|
+ # 应用旋转矩阵
|
|
|
+ rotated = rotation_matrix @ np.array([translated_x, translated_y])
|
|
|
+
|
|
|
+ # 将点平移回原位置
|
|
|
+ final_x = rotated[0] + center_x
|
|
|
+ final_y = rotated[1] + center_y
|
|
|
+
|
|
|
+ # 更新结果DataFrame
|
|
|
+ rotated_points.iloc[idx, 0] = final_x
|
|
|
+ rotated_points.iloc[idx, 1] = final_y
|
|
|
+
|
|
|
+ rotated_root[i % 3] = pd.concat([rotated_root[i % 3], rotated_points])
|
|
|
+
|
|
|
# 将需要保存到CSV的数据添加到return_list中
|
|
|
return_list.append(str(time_code))
|
|
|
return_list.append(str(wind_name))
|
|
|
@@ -436,6 +474,10 @@ def data_analyse(path: List[str]):
|
|
|
'avg_blade': {
|
|
|
'xdata': result_avg_flange.iloc[:, 0].tolist(),
|
|
|
'ydata': result_avg_flange.iloc[:, 1].tolist()
|
|
|
+ },
|
|
|
+ 'blade_center': {
|
|
|
+ 'xdata': blade_axis_tuple.iloc[:, 1].tolist(),
|
|
|
+ 'ydata': blade_axis_tuple.iloc[:, 2].tolist()
|
|
|
}
|
|
|
},
|
|
|
'blade_root': {
|
|
|
@@ -454,6 +496,22 @@ def data_analyse(path: List[str]):
|
|
|
'avg_blade': {
|
|
|
'xdata': result_avg_root.iloc[:, 0].tolist(),
|
|
|
'ydata': result_avg_root.iloc[:, 1].tolist()
|
|
|
+ },
|
|
|
+ 'first_rotate_blade': {
|
|
|
+ 'xdata': rotated_root[0].iloc[:, 0].tolist(),
|
|
|
+ 'ydata': rotated_root[0].iloc[:, 1].tolist()
|
|
|
+ },
|
|
|
+ 'second_rotate_blade': {
|
|
|
+ 'xdata': rotated_root[1].iloc[:, 0].tolist(),
|
|
|
+ 'ydata': rotated_root[1].iloc[:, 1].tolist()
|
|
|
+ },
|
|
|
+ 'third_rotate_blade': {
|
|
|
+ 'xdata': rotated_root[2].iloc[:, 0].tolist(),
|
|
|
+ 'ydata': rotated_root[2].iloc[:, 1].tolist()
|
|
|
+ },
|
|
|
+ 'blade_center': {
|
|
|
+ 'xdata': blade_axis_tuple_new.iloc[:, 1].tolist(),
|
|
|
+ 'ydata': blade_axis_tuple_new.iloc[:, 2].tolist()
|
|
|
}
|
|
|
},
|
|
|
'dist_distribution': {
|
|
|
@@ -558,12 +616,13 @@ def data_analyse(path: List[str]):
|
|
|
print('叶根原始数据采样时间长度' + str(data_root.iloc[-1, 0]))
|
|
|
print('-' * 50)
|
|
|
|
|
|
- # plot_data(result_line_flange, 'line', 'data1')
|
|
|
+ plot_data(result_line_flange, blade_axis_tuple, 'line', 'data1')
|
|
|
# plot_data(result_diff_flange, 'line', 'data_diff_1')
|
|
|
# plot_data(result_scatter_flange, 'scatter', 'data1')
|
|
|
- plot_data(result_line_root, blade_axis_new, 'line', 'data2')
|
|
|
+ plot_data(result_line_root, blade_axis_tuple_new, 'line', 'data2')
|
|
|
+ plot_data(rotated_root, blade_axis_tuple_new, 'line', 'data3')
|
|
|
# plot_data(result_diff_root, 'line', 'data_diff_2')
|
|
|
- # plot_data(result_scatter_root, blade_axis_new, 'scatter', 'data2')
|
|
|
+ # plot_data(result_scatter_root, blade_axis_tuple_new, 'scatter', 'data2')
|
|
|
# plot_data(dist_distribute, 'scatter', 'dist_distribute')
|
|
|
|
|
|
return json_output
|
|
|
@@ -699,7 +758,7 @@ def tower_filter(data_group: pd.DataFrame, noise_threshold: float):
|
|
|
# 选择频率最大的5个值
|
|
|
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.loc[(data_group['distance'] < mean_values*0.9) | (
|
|
|
data_group['distance'] > mean_values*1.1), 'distance'] = np.nan
|
|
|
|
|
|
nan_count = data_group['distance'].isna().sum()
|
|
|
@@ -733,17 +792,21 @@ def cycle_calculate(data_group: pd.DataFrame, noise_threshold: float, min_distan
|
|
|
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
|
|
|
+ print(distance_counts.get(0, 0))
|
|
|
|
|
|
- if 0 in distance_counts.nlargest(3).index:
|
|
|
- pass
|
|
|
+ if distance_counts.get(0, 0) >= 0.1:
|
|
|
+ top_5_distances = distance_counts[distance_counts.index != 0].head(5).index
|
|
|
+ mean_values = data_group[data_group['distance'].isin(top_5_distances)]['distance'].mean()
|
|
|
+ data_group.loc[((data_group['distance'] > 0) & (data_group['distance'] < mean_values - 30)) |
|
|
|
+ (data_group['distance'] > mean_values * 1.1), 'distance'] = np.nan
|
|
|
else:
|
|
|
# 选择频率最大的5个值
|
|
|
- top_5_distances = distance_counts.head(5).index
|
|
|
+ top_5_distances = distance_counts[distance_counts.index != 0].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
|
|
|
- print(f"中值是:{mean_values}")
|
|
|
|
|
|
+ print(f"中值是:{mean_values}")
|
|
|
nan_count = data_group['distance'].isna().sum()
|
|
|
all_count = data_group.shape[0]
|
|
|
print(f"替换为NaN的distance异常值的数量是: {nan_count}, 总数量是: {all_count},"
|
|
|
@@ -830,7 +893,7 @@ def data_normalize(data_group: pd.DataFrame, start_points: pd.DataFrame, end_poi
|
|
|
time.sleep(1)
|
|
|
|
|
|
|
|
|
- normalize_cycle = start_times[1] - start_times[0]
|
|
|
+ normalize_cycle = int(start_times[1] - start_times[0])
|
|
|
full_cycle = int((start_times[2] - start_times[0]) * 3)
|
|
|
turbines = [pd.DataFrame() for _ in range(3)]
|
|
|
|
|
|
@@ -844,16 +907,14 @@ def data_normalize(data_group: pd.DataFrame, start_points: pd.DataFrame, end_poi
|
|
|
# 根据当前起始时间点和结束时间点对数据进行分段
|
|
|
segment = data_group[(data_group['time'] > start_time) & (data_group['time'] <= end_time)]
|
|
|
|
|
|
- if segment is None:
|
|
|
- pass
|
|
|
- else:
|
|
|
+ if not segment.empty:
|
|
|
# 周期归一化
|
|
|
ratio = (end_time - start_time) / normalize_cycle
|
|
|
segment.loc[:, 'time'] = (segment['time'] - start_time) / ratio
|
|
|
# segment.loc[:, 'distance'] = ff.butter_lowpass_filter(segment['distance'], cutoff_low, fs)
|
|
|
|
|
|
# 将结果添加到相应的 turbine 数据框中
|
|
|
- turbines[i % 3] = pd.concat([turbines[i % 3], segment])
|
|
|
+ turbines[int(i / 2) % 3] = pd.concat([turbines[int(i / 2) % 3], segment])
|
|
|
|
|
|
|
|
|
# 数据分组清洗、求平均
|
|
|
@@ -873,8 +934,18 @@ def data_normalize(data_group: pd.DataFrame, start_points: pd.DataFrame, end_poi
|
|
|
grey_start_index = int(len(turbine_sorted) * 0.1)
|
|
|
grey_end_index = int(len(turbine_sorted) * 0.9)
|
|
|
subset_grey = turbine_sorted[grey_start_index:grey_end_index]
|
|
|
+ turbine_sorted = ff.median_filter_correction(turbine_sorted, 2, 10)
|
|
|
mean_grey = subset_grey['grey'].mean() * 0.8 # 0.8
|
|
|
- turbine_sorted = turbine_sorted[turbine_sorted['grey'] > mean_grey]
|
|
|
+ # 计算分界点
|
|
|
+ n = len(turbine_sorted)
|
|
|
+ n_10 = int(0.1 * n)
|
|
|
+
|
|
|
+ # 创建筛选掩码
|
|
|
+ is_extreme = (turbine_sorted.index < n_10) | (turbine_sorted.index >= len(turbine_sorted) - n_10)
|
|
|
+ meets_condition = turbine_sorted['grey'] > mean_grey
|
|
|
+
|
|
|
+ # 筛选:如果是前10%或后10%,需要满足条件;如果是中间80%,直接保留
|
|
|
+ turbine_sorted = turbine_sorted[~is_extreme | (is_extreme & meets_condition)]
|
|
|
|
|
|
# 找到time列的第一个值
|
|
|
first_time = turbine_sorted['time'].iloc[0]
|
|
|
@@ -1080,10 +1151,11 @@ def flange_coordinate_normalize(flange_cen_row: pd.DataFrame, flange_angle):
|
|
|
:return: 归一化后法兰数据,新俯仰角
|
|
|
"""
|
|
|
flange_angle1 = np.deg2rad(flange_angle)
|
|
|
+ center_y_mean = flange_cen_row['中心y'].mean()
|
|
|
|
|
|
# 计算新的俯仰角
|
|
|
- flange_angle_cal0 = ((np.sin(flange_angle1) * flange_cen_row['中心y'] - 0.07608) /
|
|
|
- (np.cos(flange_angle1) * flange_cen_row['中心y']))
|
|
|
+ flange_angle_cal0 = ((np.sin(flange_angle1) * center_y_mean - 0.07608) /
|
|
|
+ (np.cos(flange_angle1) * center_y_mean))
|
|
|
flange_angle_cal = np.arctan(flange_angle_cal0)
|
|
|
|
|
|
# 更新中心y列
|
|
|
@@ -1099,8 +1171,7 @@ def flange_coordinate_normalize(flange_cen_row: pd.DataFrame, flange_angle):
|
|
|
|
|
|
|
|
|
def blade_axis_cal(data_group: pd.DataFrame, start_points: pd.DataFrame, end_points: pd.DataFrame, horizon_angle: float,
|
|
|
- group_len: int) \
|
|
|
- -> pd.DataFrame:
|
|
|
+ group_len: int, radius_blade: float):
|
|
|
|
|
|
"""
|
|
|
每个叶片周期计算旋转中心及半径
|
|
|
@@ -1109,14 +1180,15 @@ def blade_axis_cal(data_group: pd.DataFrame, start_points: pd.DataFrame, end_poi
|
|
|
:param end_points: 叶片后缘突变点。
|
|
|
:param horizon_angle: 叶根法兰水平角度。
|
|
|
:param group_len: 每数据长度。
|
|
|
+ :param radius_blade: 半径。
|
|
|
:return: 叶根法兰圆轮廓的圆心、测量点的旋转半径
|
|
|
"""
|
|
|
print('正在进行叶片轴线计算......')
|
|
|
|
|
|
- def fit_circle(df, v_bounds=(2, 10.0), top_k=5, prefilter=True):
|
|
|
+ def fit_circle(df, v_fixed, top_k=5, prefilter=True):
|
|
|
"""
|
|
|
+ 修改版:速度v作为已知量,只优化圆心和半径
|
|
|
Savitzky–Golay 平滑 + 差分进化 + least_squares 精修
|
|
|
- Savitzky–Golay 平滑在每个局部窗口里用多项式拟合来代替原始点,从而减少噪声影响,同时保留曲线的整体趋势和细节
|
|
|
"""
|
|
|
|
|
|
# ========== Savitzky–Golay 平滑 ==========
|
|
|
@@ -1134,13 +1206,19 @@ def blade_axis_cal(data_group: pd.DataFrame, start_points: pd.DataFrame, end_poi
|
|
|
# ---------- 平滑 ----------
|
|
|
d_smooth = smooth_savgol(d_raw, window_length=101, polyorder=3) if prefilter else d_raw
|
|
|
|
|
|
- bounds = [v_bounds, (0, 5), (200, 201), (1, 3)]
|
|
|
+ # 计算x坐标(已知速度v)
|
|
|
+ x = v_fixed * t
|
|
|
+
|
|
|
+ # 新的参数边界:只优化圆心坐标(xc, yc)和半径R
|
|
|
+ bounds = [(min(x) - 5, max(x) + 5), # xc范围:x值范围附近
|
|
|
+ (min(d_smooth), max(d_smooth) + 10), # yc范围:y值范围附近
|
|
|
+ (0.5, 10)] # R范围
|
|
|
|
|
|
def residuals_sq(params):
|
|
|
- v, xc, yc, R = params
|
|
|
- if v <= 0 or R <= 0:
|
|
|
+ # 参数现在只有三个:xc, yc, R
|
|
|
+ xc, yc, R = params
|
|
|
+ if R <= 0:
|
|
|
return 1e6 * np.ones_like(t)
|
|
|
- x = v * t
|
|
|
return (x - xc) ** 2 + (d_smooth - yc) ** 2 - R ** 2
|
|
|
|
|
|
def objective_mean_sq(params):
|
|
|
@@ -1174,8 +1252,8 @@ def blade_axis_cal(data_group: pd.DataFrame, start_points: pd.DataFrame, end_poi
|
|
|
res = least_squares(
|
|
|
residuals_sq,
|
|
|
x0=cand,
|
|
|
- bounds=([v_bounds[0], -np.inf, -np.inf, 1e-6],
|
|
|
- [v_bounds[1], np.inf, np.inf, np.inf]),
|
|
|
+ bounds=([-np.inf, -np.inf, 1e-6], # 下界
|
|
|
+ [np.inf, np.inf, np.inf]), # 上界
|
|
|
method='trf',
|
|
|
loss='linear',
|
|
|
max_nfev=50000,
|
|
|
@@ -1183,17 +1261,16 @@ def blade_axis_cal(data_group: pd.DataFrame, start_points: pd.DataFrame, end_poi
|
|
|
ftol=1e-12,
|
|
|
gtol=1e-12
|
|
|
)
|
|
|
- v_opt, xc_opt, yc_opt, R_opt = res.x
|
|
|
- x_all = v_opt * t
|
|
|
- Ri_all = np.sqrt((x_all - xc_opt) ** 2 + (d_smooth - yc_opt) ** 2)
|
|
|
+ xc_opt, yc_opt, R_opt = res.x
|
|
|
+ Ri_all = np.sqrt((x - xc_opt) ** 2 + (d_smooth - yc_opt) ** 2)
|
|
|
geo_rmse = np.sqrt(np.mean((Ri_all - R_opt) ** 2))
|
|
|
|
|
|
if geo_rmse < best_rmse:
|
|
|
best_rmse = geo_rmse
|
|
|
- best_result = [v_opt, xc_opt, yc_opt, R_opt, geo_rmse]
|
|
|
+ best_result = [v_fixed, xc_opt, yc_opt, R_opt, geo_rmse]
|
|
|
|
|
|
result_df = pd.DataFrame([best_result],
|
|
|
- columns=['旋转半径', '中心x', '中心y', '圆半径', '几何RMSE']) # 旋转半径本身为测量点线速度
|
|
|
+ columns=['旋转半径', '中心x', '中心y', '圆半径', '几何RMSE'])
|
|
|
return result_df
|
|
|
|
|
|
def plot_circle_fit(df, fit_result):
|
|
|
@@ -1231,7 +1308,6 @@ def blade_axis_cal(data_group: pd.DataFrame, start_points: pd.DataFrame, end_poi
|
|
|
plt.title('速度乘时间后的散点与拟合圆')
|
|
|
plt.show()
|
|
|
|
|
|
- group_len = group_len
|
|
|
combined_df_sorted = pd.concat([start_points, end_points]).sort_values(by='time')
|
|
|
# 检查排序后的数据从start开始,end结束
|
|
|
if combined_df_sorted.iloc[0].equals(end_points.iloc[0]):
|
|
|
@@ -1246,6 +1322,7 @@ def blade_axis_cal(data_group: pd.DataFrame, start_points: pd.DataFrame, end_poi
|
|
|
data_group['distance'] = data_group['distance'] * np.cos(np.deg2rad(horizon_angle))
|
|
|
normalize_cycle = start_times[1] - start_times[0]
|
|
|
full_cycle = int((start_times[2] - start_times[0]) * 3)
|
|
|
+ v_blade = 10000000 * np.pi * radius_blade / full_cycle
|
|
|
angle_speed = (np.pi / full_cycle) * 5000000
|
|
|
turbines = [pd.DataFrame() for _ in range(3)]
|
|
|
|
|
|
@@ -1262,7 +1339,7 @@ def blade_axis_cal(data_group: pd.DataFrame, start_points: pd.DataFrame, end_poi
|
|
|
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[int(i / 2) % 3] = pd.concat([turbines[int(i / 2) % 3], segment])
|
|
|
|
|
|
turbines_processed = []
|
|
|
turbines_scattered = []
|
|
|
@@ -1290,24 +1367,26 @@ def blade_axis_cal(data_group: pd.DataFrame, start_points: pd.DataFrame, end_poi
|
|
|
|
|
|
process_df['time'] = process_df['time'] / 5000000
|
|
|
lower_bound = process_df['time'].quantile(0.2)
|
|
|
- upper_bound = process_df['time'].quantile(0.7)
|
|
|
+ upper_bound = process_df['time'].quantile(0.8)
|
|
|
processed_df = process_df[(process_df['time'] >= lower_bound) & (process_df['time'] <= upper_bound)]
|
|
|
- blade_cen_est = fit_circle(processed_df)
|
|
|
+ blade_cen_est = fit_circle(processed_df, v_blade)
|
|
|
|
|
|
plot_circle_fit(processed_df, blade_cen_est)
|
|
|
+ processed_df['time'] = processed_df['time'] * v_blade
|
|
|
turbines_processed.append(processed_df)
|
|
|
turbines_scattered.append(turbine)
|
|
|
result_df = pd.concat([result_df, blade_cen_est], ignore_index=True)
|
|
|
if blade_cen_est['几何RMSE'].iloc[0] >= 0.1:
|
|
|
raise ValueError("叶片几何误差过大")
|
|
|
|
|
|
- result_df = result_df.mean(numeric_only=True).to_frame().T
|
|
|
+ result_df_mean = result_df.mean(numeric_only=True).to_frame().T
|
|
|
+ result_df_mean["中心y"] = result_df_mean["中心y"] / np.cos(np.deg2rad(horizon_angle))
|
|
|
result_df["中心y"] = result_df["中心y"] / np.cos(np.deg2rad(horizon_angle))
|
|
|
# turbines_mean["中心x"] = turbines_mean["中心x"] * 5000000
|
|
|
# turbines_mean["圆半径"] = turbines_mean["圆半径"] / np.cos(np.deg2rad(horizon_angle))
|
|
|
# turbines_mean['旋转半径'] = turbines_mean['旋转半径'] / angle_speed
|
|
|
print(result_df)
|
|
|
- return result_df
|
|
|
+ return result_df_mean, result_df, turbines_processed
|
|
|
|
|
|
|
|
|
def radius_cal(border_rows, meas_angle, cen_dist, cen_angle, angle_main, angle_rotate):
|
|
|
@@ -1387,26 +1466,32 @@ def blade_angle(border_rows: List[pd.DataFrame], cen_data: pd.DataFrame, radius:
|
|
|
|
|
|
mean_value = sum(values) / len(values) if values else float('nan')
|
|
|
|
|
|
- if np.abs(cen_data['中心y'].iloc[0] - mean_value) > 0.3:
|
|
|
- cen_data['中心y'].iloc[0] = mean_value
|
|
|
- print('y_change')
|
|
|
- if cen_data['中心x'].iloc[0] > 1.5:
|
|
|
- cen_data['中心x'].iloc[0] = 1.5
|
|
|
- print('x_change')
|
|
|
- if cen_data['中心x'].iloc[0] < 0.75:
|
|
|
- cen_data['中心x'].iloc[0] = 0.75
|
|
|
- print('x_change')
|
|
|
- print(cen_data['中心x'].iloc[0])
|
|
|
+ for i in [0, 1, 2]:
|
|
|
+ if np.abs(cen_data['中心y'].iloc[i] - mean_value) > 0.5:
|
|
|
+ print('原本:' + str(cen_data['中心y'].iloc[i]) + '标准:' + str(mean_value))
|
|
|
+ cen_data['中心y'].iloc[i] = mean_value
|
|
|
+ print('y_change')
|
|
|
+ if cen_data['中心x'].iloc[i] > 1.5:
|
|
|
+ cen_data['中心x'].iloc[i] = 1.5
|
|
|
+ print('x_change')
|
|
|
+ if cen_data['中心x'].iloc[i] < 0.75:
|
|
|
+ cen_data['中心x'].iloc[i] = 0.75
|
|
|
+ print('x_change')
|
|
|
+ print(cen_data['中心x'].iloc[i])
|
|
|
|
|
|
pitch_angle_list = []
|
|
|
for idx, turbine in enumerate(border_rows, start=1):
|
|
|
+ # 使用圆拟合的情况(注释掉的是备选方案)
|
|
|
+ diff_time = np.abs(cen_data['中心x'].iloc[idx - 1] - turbine.iloc[1, 0] * v_speed)
|
|
|
+ # diff_time = np.abs((turbine.iloc[0, 0] - turbine.iloc[1, 0]) * 0.66 * v_speed)
|
|
|
+
|
|
|
+ # 计算长度差,使用对应的cen_data行
|
|
|
+ diff_len = np.abs((cen_data['中心y'].iloc[idx - 1] - turbine.iloc[1, 1]) * np.cos(np.deg2rad(v_angle)))
|
|
|
|
|
|
- # diff_time = np.abs(cen_data['中心x'].iloc[0] - turbine.iloc[1, 0] * v_speed)
|
|
|
- # TODO 如果圆拟合成功,则使用上面代码,删除下面的
|
|
|
- diff_time = np.abs((turbine.iloc[0, 0] - turbine.iloc[1, 0]) * 0.66 * v_speed)
|
|
|
- diff_len = np.abs((cen_data['中心y'].iloc[0] - turbine.iloc[1, 1]) * np.cos(np.deg2rad(v_angle)))
|
|
|
+ # 计算桨距角
|
|
|
pitch_angle = np.degrees(np.arctan(diff_len / diff_time))
|
|
|
- print('单个叶片绝对桨距角' + str(pitch_angle))
|
|
|
+
|
|
|
+ print(f'第{idx}个叶片绝对桨距角: {pitch_angle}')
|
|
|
pitch_angle_list.append(pitch_angle)
|
|
|
|
|
|
pitch_mean = np.mean(pitch_angle_list)
|
|
|
@@ -1415,7 +1500,7 @@ def blade_angle(border_rows: List[pd.DataFrame], cen_data: pd.DataFrame, radius:
|
|
|
pitch_angle_list = [round(num, 2) for num in pitch_angle_list]
|
|
|
print("\033[34m叶片相对角度偏差:\033[0m", pitch_angle_list)
|
|
|
|
|
|
- return pitch_angle_list, v_speed
|
|
|
+ return pitch_angle_list, v_speed, cen_data
|
|
|
|
|
|
|
|
|
def plot_data(data, point, plot_type: str, data_name: str):
|
|
|
@@ -1443,7 +1528,7 @@ def plot_data(data, point, plot_type: str, data_name: str):
|
|
|
else:
|
|
|
raise ValueError("plot_type must be either 'line' or 'scatter'")
|
|
|
|
|
|
- plt.scatter(point['中心x'].iloc[0], point['中心y'].iloc[0], color='black', s=1000, marker='o', label='测量点')
|
|
|
+ plt.scatter(point['中心x'], point['中心y'], color='black', s=1000, marker='o', label='测量点')
|
|
|
axy = plt.gca() # 获取当前坐标轴对象
|
|
|
plt.grid(which='both', linewidth=2) # 设置网格线宽度为2
|
|
|
axy.xaxis.set_major_locator(MaxNLocator(nbins=200)) # 设置x轴主刻度的最大数量为10
|
|
|
@@ -1588,60 +1673,20 @@ if __name__ == "__main__":
|
|
|
# locate_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/验证/gy_20-zz_20251011123102_50_25.23_32.98.csv"
|
|
|
# measure_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/验证/gy_20-zz_20251011122457_50_32.24_31.02.csv"
|
|
|
# 第七组右侧
|
|
|
- # locate_path0 = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/验证/gy_20-r-z_20251011124902_50_31.19_34.81.csv"
|
|
|
- # locate_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/验证/gy_20-r-z_20251011124620_50_24.85_32.90.csv"
|
|
|
- # measure_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/验证/gy_20-r-z_20251011124036_50_32.24_31.14.csv"
|
|
|
- # 21-l
|
|
|
locate_path0 = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/验证/gy_20-r-z_20251011124902_50_31.19_34.81.csv"
|
|
|
- locate_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/测试/gy_21-l_20251013154240_50_26.12_35.64.csv"
|
|
|
- measure_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/测试/gy_21-l_20251013153649_50_34.96_32.84.csv"
|
|
|
- # 10-170
|
|
|
+ locate_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/验证/gy_20-r-z_20251011124620_50_24.85_32.90.csv"
|
|
|
+ measure_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/验证/gy_20-r-z_20251011124036_50_32.24_31.14.csv"
|
|
|
+ # dq-8
|
|
|
# locate_path0 = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/验证/gy_20-r-z_20251011124902_50_31.19_34.81.csv"
|
|
|
- # locate_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/测试/gy_10_20251012110528_50_23.73_38.14.csv"
|
|
|
- # measure_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/测试/gy_10_20251012105925_50_36.92_34.99.csv"
|
|
|
- # 17
|
|
|
- # locate_path0 = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/验证/gy_20-rr_20251011114639_50_28.64_31.72.csv"
|
|
|
- # locate_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/测试第3天/gy_17_20251014101746_50_17.86_33.37.csv"
|
|
|
- # measure_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/测试第3天/gy_17_20251014101154_50_31.96_29.80.csv"
|
|
|
- # 17-1
|
|
|
- # locate_path0 = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/验证/gy_20-rr_20251011114639_50_28.64_31.72.csv"
|
|
|
- # locate_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/测试第3天/gy_17-1_20251014103313_50_16.24_30.50.csv"
|
|
|
- # measure_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/测试第3天/gy_17-1_20251014102718_50_29.27_27.02.csv"
|
|
|
- # 21-292
|
|
|
- # locate_path0 = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/验证/gy_20-rr_20251011114639_50_28.64_31.72.csv"
|
|
|
- # locate_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/测试/gy_21_20251013145823_50_23.04_31.70.csv"
|
|
|
- # measure_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/测试/gy_21_20251013145148_50_31.24_29.51.csv"
|
|
|
- # 5-232
|
|
|
- # locate_path0 = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/验证/gy_20-rr_20251011114639_50_28.64_31.72.csv"
|
|
|
- # locate_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/测试/gy_5_20251012115014_50_18.06_29.47.csv"
|
|
|
- # measure_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/测试/gy_5_20251012114417_50_28.88_26.92.csv"
|
|
|
- # 5右侧-231.8
|
|
|
- # locate_path0 = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/验证/gy_20-rr_20251011114639_50_28.64_31.72.csv"
|
|
|
- # locate_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/测试/gy_5_20251012115014_50_18.06_29.47.csv"
|
|
|
- # measure_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/测试/gy_5-1_20251012120929_50_28.9_26.98.csv"
|
|
|
- # 5左侧
|
|
|
- # locate_path0 = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/验证/gy_20-rr_20251011114639_50_28.64_31.72.csv"
|
|
|
- # locate_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/测试/gy_5_20251012115014_50_18.06_29.47.csv"
|
|
|
- # measure_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/测试/gy_5-l_20251012102212_50_26.60_24.66.csv"
|
|
|
- # 1--198
|
|
|
- # locate_path0 = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/验证/gy_20-rr_20251011114639_50_28.64_31.72.csv"
|
|
|
- # locate_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/测试/gy_1-6_20251013114932_50_20.26_34.14.csv"
|
|
|
- # measure_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/测试/gy_1-6_20251013114336_50_33.39_31.41.csv"
|
|
|
- # 2--154
|
|
|
- # locate_path0 = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/验证/gy_20-rr_20251011114639_50_28.64_31.72.csv"
|
|
|
- # locate_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/测试/gy_2-2_20251013112737_50_26.43_42.10.csv"
|
|
|
- # measure_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/测试/gy_2-2_20251013112018_50_40.99_38.86.csv"
|
|
|
- # 7--198.2
|
|
|
- # locate_path0 = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/验证/gy_20-rr_20251011114639_50_28.64_31.72.csv"
|
|
|
- # locate_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/测试/gy_7_20251012123914_50_20.36_32.06.csv"
|
|
|
- # measure_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/测试/gy_7_20251012123253_50_31.15_28.97.csv"
|
|
|
- # 8-219
|
|
|
- # locate_path0 = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/验证/gy_20-rr_20251011114639_50_28.64_31.72.csv"
|
|
|
- # locate_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/测试/gy_8_20251013122350_50_14.79_26.51.csv"
|
|
|
- # measure_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/测试/gy_8_20251013121806_50_26.02_24.14.csv"
|
|
|
+ # locate_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251023大庆/第三天/dh_8_20251109102949_50_17.22_27.45.csv"
|
|
|
+ # measure_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251023大庆/第三天/dh_8_20251109102255_50_26.18_24.06.csv"
|
|
|
+ # zb-9
|
|
|
+ # locate_path0 = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251011沽源/验证/gy_20-r-z_20251011124902_50_31.19_34.81.csv"
|
|
|
+ # locate_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251121淄博/数据/zb_9_20251122110132_50_14.19_19.83.csv"
|
|
|
+ # measure_path = "C:/Users/laiwe/Desktop/风电/激光测量/测试数据/20251121淄博/数据/zb_9_20251122105534_50_19.37_17.73.csv"
|
|
|
|
|
|
start_t = time.time() # 记录开始时间
|
|
|
- data_path = [locate_path0, locate_path, measure_path, 5, 5, 1.54] # 偏斜测量数据、轮毂数据、叶根数据、锥角、轴向倾角、偏航角
|
|
|
+ data_path = [locate_path0, locate_path, measure_path, 3.5, 5, 1.54] # 偏斜测量数据、轮毂数据、叶根数据、锥角、轴向倾角、偏航角
|
|
|
list_1 = data_analyse(data_path)
|
|
|
print(f"耗时: {time.time() - start_t:.2f} 秒")
|
|
|
|