cpWindSpeedAnalyst.py 7.9 KB

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