pitchTSRCpAnalyst.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. import os
  2. import pandas as pd
  3. import plotly.graph_objects as go
  4. from algorithmContract.confBusiness import *
  5. from algorithmContract.contract import Contract
  6. from behavior.analystWithGoodPoint import AnalystWithGoodPoint
  7. from plotly.subplots import make_subplots
  8. class PitchTSRCpAnalyst(AnalystWithGoodPoint):
  9. def typeAnalyst(self):
  10. return "pitch_tsr_cp"
  11. def turbinesAnalysis(self, outputAnalysisDir, conf: Contract, turbineCodes):
  12. dictionary=self.processTurbineData(turbineCodes,conf,[Field_DeviceCode,Field_Time,Field_PitchAngel1,Field_WindSpeed,Field_ActiverPower,Field_RotorSpeed,Field_GeneratorSpeed])
  13. dataFrameMerge=self.userDataFrame(dictionary,conf.dataContract.configAnalysis,self)
  14. turbineInfos = self.common.getTurbineInfos(conf.dataContract.dataFilter.powerFarmID, turbineCodes, self.turbineInfo)
  15. return self.windRoseAnalysis(dataFrameMerge,turbineInfos, outputAnalysisDir, conf)
  16. def windRoseAnalysis(self, dataFrameMerge: pd.DataFrame, turbineModelInfo: pd.Series,outputAnalysisDir, conf: Contract):
  17. """
  18. 绘制3D曲面图。
  19. 参数:
  20. df: pandas.DataFrame, 必须包含Field_PitchAngel1, Field_TSR, 和 Field_Cp这三个字段。
  21. 返回:
  22. 一个Plotly图形对象。
  23. """
  24. # 检查所需列是否存在
  25. required_columns = {Field_PitchAngel1, Field_TSR, Field_Cp}
  26. if not required_columns.issubset(dataFrameMerge.columns):
  27. raise ValueError(f"DataFrame缺少必要的列。需要的列有: {required_columns},Available: {dataFrameMerge.columns}")
  28. # # 按设备名分组数据
  29. # grouped = dataFrameMerge.groupby([Field_NameOfTurbine, Field_CodeOfTurbine])
  30. result_rows = []
  31. ## 分图
  32. dataFrameMerge['PitchAngleBin'] = pd.cut(dataFrameMerge[Field_PitchAngel1], bins=[-1, 1, 3, 5, 7, 9], right=True, labels=['[-1,1]', '(1,3]', '(3,5]', '(5,7]', '(7,9]'])
  33. # turbines = dataFrameMerge[Field_NameOfTurbine].unique()
  34. turbines = dataFrameMerge.groupby([Field_NameOfTurbine, Field_CodeOfTurbine]).groups.keys()
  35. for turbine_name, turbine_code in turbines:
  36. fig = make_subplots(rows=1, cols=1)
  37. # 选择当前风力发电机的数据
  38. turbine_data = dataFrameMerge[dataFrameMerge[Field_NameOfTurbine] == turbine_name]
  39. # 按角区间分组
  40. grouped = turbine_data.groupby('PitchAngleBin')
  41. # 为每个区间添加一个数据迹
  42. for pitch_bin, group in grouped:
  43. fig.add_trace(go.Scatter(
  44. x=group[Field_TSR],
  45. y=group[Field_Cp],
  46. mode='markers',
  47. name=pitch_bin,
  48. marker=dict(
  49. size=3, # Smaller size, default is usually around 10
  50. opacity=0.8 # Reduced opacity, default is 1
  51. )
  52. # name=f'Pitch: {name}'
  53. ))
  54. # 更新布局
  55. fig.update_layout(
  56. title=f'风能利用系数 vs. 叶尖速比 : {turbine_name}',
  57. xaxis_title='叶尖速比',
  58. yaxis_title='风能利用系数',
  59. legend_title='桨距角',
  60. legend=dict(
  61. # orientation="h",
  62. itemsizing="constant", # Use constant size for legend items
  63. itemwidth=80 # Set the width of legend items to 50 pixels
  64. ),
  65. xaxis=dict(
  66. # dtick=2,
  67. range=[5,20]),
  68. yaxis=dict(
  69. dtick=self.axisStepCp,
  70. range=[self.axisLowerLimitCp,self.axisUpperLimitCp]
  71. )
  72. # legend=dict(
  73. # orientation="h",
  74. # xanchor="center",
  75. # x=0.5,
  76. # y=-0.2
  77. # )
  78. )
  79. # 确保从 Series 中提取的是具体的值
  80. engineTypeCode = turbineModelInfo.get(Field_MillTypeCode, "")
  81. if isinstance(engineTypeCode, pd.Series):
  82. engineTypeCode = engineTypeCode.iloc[0]
  83. engineTypeName = turbineModelInfo.get(Field_MachineTypeCode, "")
  84. if isinstance(engineTypeName, pd.Series):
  85. engineTypeName = engineTypeName.iloc[0]
  86. # 构建最终的JSON对象
  87. json_output = {
  88. "analysisTypeCode": "变桨和叶尖速比及风能利用系数分析",
  89. "engineCode": engineTypeCode,
  90. "engineTypeName": engineTypeName,
  91. "xaixs": "叶尖速比",
  92. "yaixs": "风能利用系数",
  93. "data": [{
  94. "engineName": turbine_name,
  95. "engineCode": turbine_code,
  96. "title":f' 风能利用系数 vs. 叶尖速比-{turbine_name}',
  97. "xData": group[Field_TSR].tolist(),
  98. "yData":group[Field_Cp].tolist(),
  99. "colorbar": pitch_bin,
  100. "colorbartitle": "桨距角"
  101. }]
  102. }
  103. # 保存html
  104. filePathOfPng = os.path.join(outputAnalysisDir, f"{turbine_name}.png")
  105. fig.write_image(filePathOfPng)
  106. filePathOfHtml = os.path.join(outputAnalysisDir, f"{turbine_name}.html")
  107. fig.write_html(filePathOfHtml)
  108. # 将JSON对象保存到文件
  109. output_json_path = os.path.join(outputAnalysisDir, f"pitch_TSR_cp{turbine_name}.json")
  110. with open(output_json_path, 'w', encoding='utf-8') as f:
  111. import json
  112. json.dump(json_output, f, ensure_ascii=False, indent=4)
  113. # 如果需要返回DataFrame,可以包含文件路径
  114. result_rows.append({
  115. Field_Return_TypeAnalyst: self.typeAnalyst(),
  116. Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
  117. Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
  118. Field_CodeOfTurbine: turbine_code,
  119. Field_Return_FilePath: output_json_path,
  120. Field_Return_IsSaveDatabase: True
  121. })
  122. result_rows.append({
  123. Field_Return_TypeAnalyst: self.typeAnalyst(),
  124. Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
  125. Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
  126. Field_CodeOfTurbine: turbine_code,
  127. Field_Return_FilePath: filePathOfPng,
  128. Field_Return_IsSaveDatabase: False
  129. })
  130. result_rows.append({
  131. Field_Return_TypeAnalyst: self.typeAnalyst(),
  132. Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
  133. Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
  134. Field_CodeOfTurbine: turbine_code,
  135. Field_Return_FilePath: filePathOfHtml,
  136. Field_Return_IsSaveDatabase: True
  137. })
  138. result_df = pd.DataFrame(result_rows)
  139. return result_df