tsrCpPowerScatterAnalyst.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. import os
  2. import pandas as pd
  3. import math
  4. import numpy as np
  5. from plotly.subplots import make_subplots
  6. import plotly.express as px
  7. import pandas as pd
  8. import plotly.graph_objects as go
  9. import seaborn as sns
  10. from matplotlib.ticker import MultipleLocator
  11. from behavior.analystWithGoodPoint import AnalystWithGoodPoint
  12. from utils.directoryUtil import DirectoryUtil as dir
  13. from algorithmContract.confBusiness import *
  14. from algorithmContract.contract import Contract
  15. class TSRCpPowerScatterAnalyst(AnalystWithGoodPoint):
  16. """
  17. 风电机组叶尖速比-Cp-功率散点分析
  18. """
  19. def typeAnalyst(self):
  20. return "tsr_cp_power_scatter"
  21. def turbinesAnalysis(self, outputAnalysisDir, conf: Contract, turbineCodes):
  22. dictionary = self.processTurbineData(turbineCodes,conf,[Field_DeviceCode,Field_Time,Field_WindSpeed,Field_ActiverPower,Field_RotorSpeed,Field_GeneratorSpeed])
  23. turbineInfos = self.common.getTurbineInfos(conf.dataContract.dataFilter.powerFarmID, turbineCodes,
  24. self.turbineInfo)
  25. dataFrameMerge = self.userDataFrame(dictionary,conf.dataContract.configAnalysis,self)
  26. # return self.plot_tsr_distribution(self.tsr(dataFrameMerge), outputAnalysisDir, conf)
  27. dataFrameMerge[Field_PowerFarmName] = self.currPowerFarmInfo.loc[Field_PowerFarmName]
  28. # Ensure the necessary columns are of float type
  29. dataFrameMerge[Field_WindSpeed] = dataFrameMerge[Field_WindSpeed].astype(float)
  30. dataFrameMerge[Field_RotorSpeed] = dataFrameMerge[Field_RotorSpeed].astype(float)
  31. dataFrameMerge[Field_Cp] = dataFrameMerge[Field_Cp].astype(float)
  32. dataFrameMerge[Field_ActiverPower] = dataFrameMerge[Field_ActiverPower].astype(float)
  33. dataFrameMerge[Field_GeneratorSpeed] = dataFrameMerge[Field_GeneratorSpeed].astype(float)
  34. max_cutin = self.turbineModelInfo[Field_CutInWS].max()
  35. min_rated = self.turbineModelInfo[Field_RatedWindSpeed].min()
  36. dataFrameMerge = dataFrameMerge[(dataFrameMerge[Field_WindSpeed] > max_cutin) & (dataFrameMerge[Field_WindSpeed] < min_rated)]
  37. # Group by 'power_floor' and calculate median, max, and min of TSR
  38. dataFrameMerge[Field_TSRModified] = dataFrameMerge[Field_TSR] / (dataFrameMerge[Field_Cp] ** (1/3))
  39. return self.plot_tsrcp_distribution(dataFrameMerge, turbineInfos, outputAnalysisDir, conf)
  40. def plot_tsrcp_distribution(self, dataFrameMerge: pd.DataFrame, turbineModelInfo: pd.Series, outputAnalysisDir, conf: Contract, encoding=charset_unify):
  41. """
  42. Generates tsr distribution plots for turbines in a wind farm.
  43. Parameters:
  44. - outputAnalysisDir: str, path to the directory containing input CSV files.
  45. - farm_name: str, name of the wind farm.
  46. - encoding: str, encoding of the input CSV files. Defaults to 'utf-8'.
  47. """
  48. x_name = Field_ActiverPower
  49. y_name = Field_TSRModified
  50. upLimitOfTSR = 20
  51. result_rows = []
  52. # 绘制每个设备的TSR分布图
  53. for name, group in dataFrameMerge.groupby([Field_NameOfTurbine, Field_CodeOfTurbine]):
  54. fig = px.scatter(group,x=x_name, y=y_name)
  55. fig.update_layout(
  56. title={"text": '机组: {}'.format(name[0])},
  57. xaxis=dict(
  58. title='功率',
  59. dtick=200,
  60. tickangle=-45,
  61. range=[0, 1800]),
  62. yaxis=dict(
  63. title= '叶尖速比/风能利用系数分析^(1/3)', # r"$\frac{TSR}{Cp^{1/3}}$" # 仅在.png格式下正确显示
  64. dtick=self.axisStepTSR,
  65. range=[self.axisLowerLimitTSR,
  66. self.axisUpperLimitTSR]
  67. )
  68. )
  69. fig.update_traces(marker=dict(size=3))
  70. fig.update_xaxes(tickangle=-45)
  71. # 确保从 Series 中提取的是具体的值
  72. engineTypeCode = turbineModelInfo.get(Field_MillTypeCode, "")
  73. if isinstance(engineTypeCode, pd.Series):
  74. engineTypeCode = engineTypeCode.iloc[0]
  75. engineTypeName = turbineModelInfo.get(Field_MachineTypeCode, "")
  76. if isinstance(engineTypeName, pd.Series):
  77. engineTypeName = engineTypeName.iloc[0]
  78. # 构建最终的JSON对象
  79. json_output = {
  80. "analysisTypeCode": "机组叶尖速比-Cp-功率散点分析",
  81. "engineCode": engineTypeCode,
  82. "engineTypeName": engineTypeName,
  83. "xaixs": "功率(kW)",
  84. "yaixs": "叶尖速比/风能利用系数分析^(1/3)",
  85. "data": [{
  86. "engineName": name[0], # Field_NameOfTurbine
  87. "engineCode": name[1], # Field_CodeOfTurbine
  88. "title": f' 机组: {format(name[0])}',
  89. "xData": group[x_name].tolist(),
  90. "yData": group[y_name].tolist(),
  91. }]
  92. }
  93. # 保存图像
  94. pngFileName = f"{name[0]}.png"
  95. pngFilePath = os.path.join(outputAnalysisDir, pngFileName)
  96. fig.write_image(pngFilePath, scale=3)
  97. # 将JSON对象保存到文件
  98. output_json_path = os.path.join(outputAnalysisDir, f"{name[0]}.json")
  99. with open(output_json_path, 'w', encoding='utf-8') as f:
  100. import json
  101. json.dump(json_output, f, ensure_ascii=False, indent=4)
  102. # 保存HTML
  103. # htmlFileName = f"{name[0]}.html"
  104. # htmlFilePath = os.path.join(outputAnalysisDir, htmlFileName)
  105. # fig.write_html(htmlFilePath)
  106. # 如果需要返回DataFrame,可以包含文件路径
  107. result_rows.append({
  108. Field_Return_TypeAnalyst: self.typeAnalyst(),
  109. Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
  110. Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
  111. Field_CodeOfTurbine: name[1],
  112. Field_Return_FilePath: output_json_path,
  113. Field_Return_IsSaveDatabase: True
  114. })
  115. result_rows.append({
  116. Field_Return_TypeAnalyst: self.typeAnalyst(),
  117. Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
  118. Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
  119. Field_CodeOfTurbine: name[1],
  120. Field_Return_FilePath: pngFilePath,
  121. Field_Return_IsSaveDatabase: False
  122. })
  123. # result_rows.append({
  124. # Field_Return_TypeAnalyst: self.typeAnalyst(),
  125. # Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
  126. # Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
  127. # Field_CodeOfTurbine: name[1],
  128. # Field_Return_FilePath: htmlFilePath,
  129. # Field_Return_IsSaveDatabase: True
  130. # })
  131. result_df = pd.DataFrame(result_rows)
  132. return result_df