cpWindSpeedAnalyst.py 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. import os
  2. import pandas as pd
  3. import numpy as np
  4. import plotly.graph_objects as go
  5. from plotly.subplots import make_subplots
  6. import seaborn as sns
  7. import matplotlib.pyplot as plt
  8. from matplotlib.ticker import MultipleLocator
  9. from behavior.analystExcludeRatedPower import AnalystExcludeRatedPower
  10. from utils.directoryUtil import DirectoryUtil as dir
  11. from algorithmContract.confBusiness import *
  12. class CpWindSpeedAnalyst(AnalystExcludeRatedPower):
  13. """
  14. 风电机组风能利用系数分析
  15. """
  16. def typeAnalyst(self):
  17. return "cp_windspeed"
  18. def turbineAnalysis(self,
  19. dataFrame,
  20. outputAnalysisDir,
  21. outputFilePath,
  22. confData: ConfBusiness,
  23. turbineName):
  24. self.cp(dataFrame, outputFilePath,
  25. confData.field_wind_speed, confData.field_rotor_speed, confData.field_power, confData.field_pitch_angle1, confData.rotor_diameter, confData.density_air)
  26. def cp(self, dataFrame, output_path, wind_speed_col, field_rotor_speed, power_col, pitch_col, rotor_diameter, air_density):
  27. print('rotor_diameter={} air_density={}'.format(
  28. rotor_diameter, air_density))
  29. dataFrame = dataFrame.dropna(subset=[power_col])
  30. dataFrame['power'] = dataFrame[power_col] # Alias the power column
  31. # Floor division by 10 and then multiply by 10
  32. dataFrame['wind_speed_floor'] = (
  33. dataFrame[wind_speed_col] / 1).astype(int) + 0.5
  34. dataFrame['wind_speed'] = dataFrame[wind_speed_col].astype(float)
  35. dataFrame['rotor_speed'] = dataFrame[field_rotor_speed].astype(float)
  36. # Power coefficient calculation
  37. dataFrame['power'] = pd.to_numeric(dataFrame['power'], errors='coerce')
  38. dataFrame['wind_speed'] = pd.to_numeric(
  39. dataFrame['wind_speed'], errors='coerce')
  40. # rotor_diameter = pd.to_numeric(rotor_diameter, errors='coerce')
  41. # air_density = pd.to_numeric(air_density, errors='coerce')
  42. # # Calculate cp
  43. # dataFrame['cp'] = dataFrame['power'] * 1000 / \
  44. # (0.5 * np.pi * air_density *
  45. # (rotor_diameter ** 2) / 4 * dataFrame['wind_speed'] ** 3)
  46. # Group by wind_speed_floor and calculate mean, max, and min of the specified columns
  47. grouped = dataFrame.groupby('wind_speed_floor').agg(
  48. power=('power', 'mean'),
  49. rotor_speed=('rotor_speed', 'mean'),
  50. cp=('cp', 'mean'),
  51. cp_max=('cp', 'max'),
  52. cp_min=('cp', 'min'),
  53. ).reset_index()
  54. # Rename columns post aggregation for clarity
  55. grouped.columns = ['wind_speed_floor', 'power',
  56. 'rotor_speed', 'cp', 'cp_max', 'cp_min']
  57. # Sort by wind_speed_floor
  58. grouped = grouped.sort_values('wind_speed_floor')
  59. # Write the dataframe to a CSV file
  60. grouped.to_csv(output_path, index=False)
  61. def turbinesAnalysis(self, dataFrameMerge, outputAnalysisDir, confData: ConfBusiness):
  62. self.generate_cp_distribution(outputAnalysisDir, confData)
  63. def generate_cp_distribution(self, csvFileDirOfCp, confData: ConfBusiness, encoding='utf-8'):
  64. """
  65. Generates Cp distribution plots for turbines in a wind farm.
  66. Parameters:
  67. - csvFileDirOfCp: str, path to the directory containing input CSV files.
  68. - farm_name: str, name of the wind farm.
  69. - encoding: str, encoding of the input CSV files. Defaults to 'utf-8'.
  70. """
  71. output_path = csvFileDirOfCp
  72. value_step = 0.5
  73. field_Name_Turbine = "turbine_name"
  74. x_name = 'wind_speed_floor'
  75. y_name = 'cp'
  76. sns.set_palette('deep')
  77. res = pd.DataFrame()
  78. for root, dir_names, file_names in dir.list_directory(csvFileDirOfCp):
  79. for file_name in file_names:
  80. if not file_name.endswith(CSVSuffix):
  81. continue
  82. file_path = os.path.join(root, file_name)
  83. print(file_path)
  84. frame = pd.read_csv(file_path, encoding=encoding)
  85. turbine_name = file_name.split(CSVSuffix)[0]
  86. frame[field_Name_Turbine] = turbine_name
  87. res = pd.concat(
  88. [res, frame.loc[:, [field_Name_Turbine, x_name, y_name]]], axis=0)
  89. ress = res.reset_index()
  90. fig, ax = plt.subplots()
  91. ax = sns.lineplot(x=x_name, y=y_name, data=ress,
  92. hue=field_Name_Turbine)
  93. ax.xaxis.set_major_locator(MultipleLocator(1)) # 创建一个刻度 ,将定位器应用到y轴上
  94. ax.set_xlim(0, 26)
  95. ax.yaxis.set_major_locator(MultipleLocator(
  96. confData.graphSets["cp"]["step"] if not self.common.isNone(confData.graphSets["cp"]["step"]) else value_step)) # 创建一个刻度 ,将定位器应用到y轴上
  97. ax.set_ylim(confData.graphSets["cp"]["min"] if not self.common.isNone(confData.graphSets["cp"]["min"])
  98. else 0, confData.graphSets["cp"]["max"] if not self.common.isNone(confData.graphSets["cp"]["max"]) else 1)
  99. ax.set_title('Cp-Distribution')
  100. plt.xticks(rotation=45) # 旋转45度
  101. plt.legend(ncol=4)
  102. plt.savefig(os.path.join(
  103. output_path, "{}-Cp-Distribution.png".format(confData.farm_name)), bbox_inches='tight', dpi=300)
  104. plt.close()
  105. grouped = ress.groupby(field_Name_Turbine)
  106. for name, group in grouped:
  107. color = ["lightgrey"] * len(ress[field_Name_Turbine].unique())
  108. fig, ax = plt.subplots(figsize=(8, 8))
  109. ax = sns.lineplot(x=x_name, y=y_name, data=ress, hue=field_Name_Turbine,
  110. palette=sns.color_palette(color), legend=False)
  111. ax = sns.lineplot(x=x_name, y=y_name, data=group,
  112. color='darkblue', legend=False)
  113. ax.xaxis.set_major_locator(
  114. MultipleLocator(1)) # 创建一个刻度 ,将定位器应用到y轴上
  115. ax.set_xlim(0, 26)
  116. ax.yaxis.set_major_locator(MultipleLocator(
  117. confData.graphSets["cp"]["step"] if not self.common.isNone(confData.graphSets["cp"]["step"]) else value_step)) # 创建一个刻度 ,将定位器应用到y轴上
  118. ax.set_ylim(confData.graphSets["cp"]["min"] if not self.common.isNone(confData.graphSets["cp"]["min"])
  119. else 0, confData.graphSets["cp"]["max"] if not self.common.isNone(confData.graphSets["cp"]["max"]) else 1)
  120. ax.set_title('turbine name={}'.format(name))
  121. plt.xticks(rotation=45) # 旋转45度
  122. plt.savefig(os.path.join(output_path, "{}.png".format(
  123. name)), bbox_inches='tight', dpi=120)
  124. plt.close()
  125. def plot_cp_distribution(self, csvFileDir, farm_name):
  126. field_Name_Turbine = "设备名"
  127. x_name = 'wind_speed_floor'
  128. y_name = 'cp'
  129. # Create the output path based on the farm name
  130. output_path = csvFileDir # output_path_template.format(farm_name)
  131. # Ensure the output directory exists
  132. os.makedirs(output_path, exist_ok=True)
  133. print(csvFileDir)
  134. # Initialize a DataFrame to store results
  135. res = pd.DataFrame()
  136. # Walk through the input directory to process each file
  137. for root, _, file_names in dir.list_directory(csvFileDir):
  138. for file_name in file_names:
  139. full_path = os.path.join(root, file_name)
  140. frame = pd.read_csv(full_path, encoding='gbk')
  141. turbine_name = file_name.split(CSVSuffix)[0]
  142. print("turbine_name={}".format(turbine_name))
  143. frame[field_Name_Turbine] = turbine_name
  144. res = pd.concat(
  145. [res, frame.loc[:, [field_Name_Turbine, x_name, y_name]]], axis=0)
  146. # Reset index for plotting
  147. ress = res.reset_index(drop=True)
  148. # Plot combined Cp distribution for all turbines
  149. fig = make_subplots(rows=1, cols=1)
  150. for name, group in ress.groupby(field_Name_Turbine):
  151. fig.add_trace(go.Scatter(
  152. x=group[x_name], y=group[y_name], mode='lines', name=name))
  153. fig.update_layout(title_text='{} Cp分布'.format(
  154. farm_name), xaxis_title=x_name, yaxis_title=y_name)
  155. fig.write_image(os.path.join(
  156. output_path, "{}Cp分布.png".format(farm_name)), scale=3)
  157. # Plot individual Cp distributions
  158. unique_turbines = ress[field_Name_Turbine].unique()
  159. for name in unique_turbines:
  160. individual_fig = make_subplots(rows=1, cols=1)
  161. # Add all turbines in grey
  162. for turbine in unique_turbines:
  163. group = ress[ress[field_Name_Turbine] == turbine]
  164. individual_fig.add_trace(go.Scatter(
  165. x=group[x_name], y=group[y_name], mode='lines', name=turbine, line=dict(color='lightgrey')))
  166. # Highlight the current turbine in dark blue
  167. group = ress[ress[field_Name_Turbine] == name]
  168. individual_fig.add_trace(go.Scatter(
  169. x=group[x_name], y=group[y_name], mode='lines', name=name, line=dict(color='darkblue')))
  170. individual_fig.update_layout(title_text='设备名={}'.format(name))
  171. individual_fig.write_image(os.path.join(
  172. output_path, "all-{}.png".format(name)), scale=2)