yaw_miss_analysis.py 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. import pandas as pd
  2. import configparser
  3. import numpy as np
  4. from py_mybatis.sql.mybatis_sql_session import MybatisMapperScanner, MybatisSqlSession, PooledDB
  5. from py_mybatis.sql.pdbc_sql_template import *
  6. import pymysql
  7. import os
  8. import unittest
  9. import time
  10. def calculate_yaw_miss(filtered_data, wind_speed_range, wind_speed_step, wind_direct_step, cabin_temp_step):
  11. # 计算风向、机舱角度 分别和360取模运算
  12. filtered_data['风向'] = np.abs((filtered_data['风向'] % 360))
  13. filtered_data['机舱角度'] = np.abs((filtered_data['机舱角度'] % 360))
  14. # 计算偏航误差
  15. filtered_data['偏航误差'] = filtered_data['风向'] - filtered_data['机舱角度']
  16. # 定义风速和舱内温度的分组范围
  17. # wind_speed_bins = np.arange(wind_speed_range[0], wind_speed_range[1] + wind_speed_step, wind_speed_step)
  18. wind_speed_bins = np.arange(filtered_data['风速'].min(
  19. ), filtered_data['风速'].max() + wind_speed_step, wind_speed_step)
  20. wind_direct_bins = np.arange(filtered_data['风向'].min(
  21. ), filtered_data['风向'].max() + wind_direct_step, wind_direct_step)
  22. cabin_temp_bins = np.arange(filtered_data['舱内温度'].min(
  23. ), filtered_data['舱内温度'].max() + cabin_temp_step, cabin_temp_step)
  24. # 按风速和舱内温度分组
  25. grouped = filtered_data.groupby([pd.cut(filtered_data['风速'], wind_speed_bins),
  26. pd.cut(
  27. filtered_data['风向'], wind_direct_bins),
  28. pd.cut(filtered_data['舱内温度'], cabin_temp_bins)])
  29. # 从每个分组中找出有功功率最大的数据记录
  30. # max_powegrouped_power_maxr_rows = grouped.apply(lambda x: x[x['有功功率'] == x['有功功率'].max()])
  31. grouped_power_max = grouped.max()['有功功率'].reset_index()
  32. # 计算每个分组的偏航误差平均值
  33. yaw_error_avg = grouped['偏航误差'].mean().dropna()
  34. return grouped, grouped_power_max, yaw_error_avg
  35. def calculate_yaw_miss2(data, wind_speed_step, wind_direct_step, cabin_temp_step):
  36. # 按风速和舱内温度分组
  37. data['风向分组'] = np.floor(data['风向'] / wind_direct_step) * wind_direct_step
  38. data['风速分组'] = np.floor(data['风速'] / wind_speed_step) * wind_speed_step
  39. data['舱内温度分组'] = np.floor(data['舱内温度'] / cabin_temp_step) * cabin_temp_step
  40. # 计算每个分组的偏航误差平均值
  41. grouped = data.groupby(['风向分组', '风速分组', '舱内温度分组'])
  42. # 从每个分组中找出有功功率最大的行
  43. # grouped.apply(lambda x: x[x['有功功率'] == x['有功功率'].max()])
  44. idx = grouped["有功功率"].idxmax()
  45. max_power_rows = data.loc[idx]
  46. # yaw_error_avg = grouped['偏航误差'].mean().dropna()
  47. return grouped, max_power_rows, data
  48. def calculate_angle_deviations(array1, array2):
  49. """
  50. 计算两个相同长度角度数组中两两对应角度值的偏差。
  51. 结果限制在-90°到+90°之间,并保留两位小数。
  52. 参数:
  53. array1 (list): 第一个角度数组
  54. array2 (list): 第二个角度数组
  55. 返回:
  56. list: 两两对应角度的偏差列表
  57. """
  58. deviations = []
  59. for angle1, angle2 in zip(array1, array2):
  60. # 计算原始偏差
  61. deviation = angle1 - angle2
  62. # 调整偏差,使其位于-180°到+180°范围内
  63. if deviation == 0.0:
  64. deviation = 0.0
  65. else:
  66. deviation = (deviation + 180) % 360 - 180
  67. # 将偏差限制在-90°到+90°范围内
  68. if deviation > 90:
  69. deviation -= 180
  70. elif deviation < -90:
  71. deviation += 180
  72. # 保留两位小数
  73. deviations.append(round(deviation, 2))
  74. return deviations
  75. def recalculation(data):
  76. # 计算风向、机舱角度 分别和360取模运算
  77. data['风向'] = np.abs(data['风向'] % 360)
  78. data['机舱角度'] = np.abs(data['机舱角度'] % 360)
  79. # 计算偏航误差
  80. # data['偏航误差'] =np.where(data['风向'] < data['机舱角度'],
  81. # (data['风向'] - data['机舱角度'])%360,
  82. # -(data['风向'] - data['机舱角度']) )
  83. data['偏航误差'] = calculate_angle_deviations(
  84. data['风向'], data['机舱角度'])
  85. return data
  86. def load_data(file_path, encoding='utf-8'):
  87. # sql_template =PdbcSqlTemplate(dataSource=PooledDB(
  88. # creator=pymysql,
  89. # maxconnections=6,
  90. # mincached=2,
  91. # maxcached=5,
  92. # blocking=True,
  93. # maxusage=None,
  94. # setsession=[],
  95. # ping=0,
  96. # host="192.168.50.241",
  97. # user="root",
  98. # password="123456",
  99. # database="data2023",
  100. # cursorclass=pymysql.cursors.DictCursor,
  101. # charset='utf8'
  102. # ))
  103. # dic= sql_template.select_list(sql="show tables;")
  104. # print(dic)
  105. # Load the data
  106. data = pd.read_csv(file_path, encoding=encoding)
  107. return data
  108. def filter_data(data, wind_speed_range, active_power_range):
  109. # Filter criteria:
  110. # 1. "风机状态" (wind turbine status) must be 5
  111. # 2. No empty (null) values in the row
  112. filtered_data = data[(data['风机状态'] == 5)
  113. & (data["风速"] >= wind_speed_range[0])
  114. & (data["风速"] <= wind_speed_range[1])
  115. & (data['有功功率'] > 20)
  116. & (data['有功功率'] >= active_power_range[0])
  117. & (data['有功功率'] <= active_power_range[1])].dropna()
  118. filtered_data["时间"] = pd.to_datetime(filtered_data['时间'])
  119. """
  120. # 将时间列转换为13位长整型(Unix时间戳)
  121. # Excel 13位长整型转为时间 公式: =TEXT((K2/1000+8*3600)/86400+70*365+19,"yyyy-mm-dd hh:mm:ss")
  122. filtered_data["时间Unix"] = filtered_data['时间'].astype('int64') // 10**6
  123. """
  124. # 将时间列转换为10位长整型(Unix时间戳)
  125. # Excel 10位长整型转为时间 公式: =TEXT((A1+8*3600)/86400+70*365+19,"yyyy-mm-dd hh:mm:ss")
  126. filtered_data["时间Unix"] = filtered_data['时间'].astype('int64') // 10**9
  127. return filtered_data
  128. def read_config(config_file):
  129. """
  130. Reads configuration settings from an INI file.
  131. Parameters:
  132. config_file (str): Path to the INI configuration file.
  133. Returns:
  134. dict: Configuration settings.
  135. """
  136. config = configparser.ConfigParser()
  137. config.read(config_file)
  138. return config['DEFAULT']
  139. # Example usage
  140. # Replace with your file path
  141. file_path = 'E:\WorkSpace\Resource\Manage\项目\大唐\风电机组功率曲线异常检测分析服务项目\收资\data_process\data_second_scada_test.csv'
  142. def main():
  143. config_settings = read_config('config.ini')
  144. encoding = config_settings.get('Encoding', 'utf-8')
  145. wind_direct_step = float(config_settings.get('WindDirectStep', '1'))
  146. wind_speed_range = [float(x) for x in config_settings.get(
  147. 'WindSpeedRange', '3, 20').split(',')]
  148. wind_speed_step = float(config_settings.get('WindSpeedStep', '0.05'))
  149. cabin_temp_step = float(config_settings.get('CabinTempStep', '1'))
  150. active_power_range = [float(x) for x in config_settings.get(
  151. 'ActivePowerRange', '21, 1500').split(',')]
  152. raw_data = load_data(file_path, encoding)
  153. data = filter_data(raw_data, wind_speed_range, active_power_range)
  154. data=recalculation(data)
  155. # grouped,max_power_rows,yaw_error_avg = calculate_yaw_miss(data, wind_speed_range,wind_speed_step, wind_direct_step,cabin_temp_step)
  156. grouped, grouped_power_max, data = calculate_yaw_miss2(
  157. data, wind_speed_step, wind_direct_step, cabin_temp_step)
  158. yaw_miss_list=[]
  159. for index,row in data.iterrows():
  160. max_record = grouped_power_max[(grouped_power_max['风向分组'] == row['风向分组']) &
  161. (grouped_power_max['风速分组'] == row['风速分组']) &
  162. (grouped_power_max['舱内温度分组'] == row['舱内温度分组'])]
  163. data.at[index,'偏航误差']=row['偏航误差']-max_record['偏航误差']
  164. print(" grouped by 风速、风向、舱内温度 ")
  165. # 计算每个分组的偏航误差平均值
  166. grouped = data.groupby(['风向分组', '风速分组', '舱内温度分组'])
  167. # 将分组对象转换回 DataFrame
  168. grouped_df = grouped.apply(lambda x: x)
  169. # grouped_df=grouped.reset_index(drop=True)
  170. grouped_df.to_csv("./output/yaw_miss_grouped.csv",
  171. index=False, encoding="ansi")
  172. print(" max power rows ")
  173. # print(grouped_power_max)
  174. grouped_power_max.to_csv("./output/yaw_miss_max_power_rows.csv",
  175. index=False, encoding="ansi")
  176. print("number pairs of yaw miss avg : " )
  177. # 计算正数的平均值
  178. positive_mean = data[data['偏航误差'] > 0]['偏航误差'].mean()
  179. # 计算负数的平均值
  180. negative_mean = data[data['偏航误差'] < 0]['偏航误差'].mean()
  181. # 创建数对
  182. limits = (negative_mean, positive_mean)
  183. print("下限和上限的数对:", limits)
  184. if __name__ == "__main__":
  185. main()