windSpeedFrequencyAnalyst.py 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. import os
  2. import pandas as pd
  3. import numpy as np
  4. import plotly.graph_objects as go
  5. import plotly.express as px
  6. from plotly.subplots import make_subplots
  7. from behavior.analystNotFilter import AnalystNotFilter
  8. from utils.directoryUtil import DirectoryUtil as dir
  9. import matplotlib.pyplot as plt
  10. from algorithmContract.confBusiness import *
  11. from algorithmContract.contract import Contract
  12. class WindSpeedFrequencyAnalyst(AnalystNotFilter):
  13. def typeAnalyst(self):
  14. return "wind_speed_frequency"
  15. # def filterCommon(self,dataFrame:pd.DataFrame, conf: Contract):
  16. # return dataFrame
  17. def turbinesAnalysis(self, outputAnalysisDir, conf: Contract, turbineCodes):
  18. dictionary=self.processTurbineData(turbineCodes,conf,[Field_DeviceCode,Field_Time,Field_WindSpeed,Field_ActiverPower])
  19. turbineInfos = self.common.getTurbineInfos(conf.dataContract.dataFilter.powerFarmID, turbineCodes,
  20. self.turbineInfo)
  21. dataFrameMerge=self.userDataFrame(dictionary,conf.dataContract.configAnalysis,self)
  22. return self.windRoseAnalysis(dataFrameMerge, turbineInfos, outputAnalysisDir, conf)
  23. def windRoseAnalysis(self, dataFrameMerge: pd.DataFrame, turbineModelInfo: pd.Series, outputAnalysisDir, conf: Contract):
  24. # 检查所需列是否存在
  25. required_columns = {Field_NameOfTurbine, Field_WindSpeed}
  26. if not required_columns.issubset(dataFrameMerge.columns):
  27. raise ValueError(f"DataFrame缺少必要的列。需要的列有: {required_columns}")
  28. wind_speed_bins = np.arange(0, 26, 0.5) # x轴风速范围 ,间隔0.5
  29. # 按设备名分组数据
  30. grouped = dataFrameMerge.groupby([Field_NameOfTurbine, Field_CodeOfTurbine])
  31. turbine_data_list = []
  32. result_rows = []
  33. for name, group in grouped:
  34. # 2. 计算风速频率
  35. # 首先,我们需要确定风速的范围并计算每个风速的频数
  36. # wind_speeds = group[Field_WindSpeed].unique()
  37. # 计算风速频率,确保频率没有零值(用很小的数代替零)
  38. wind_speed_freq = np.histogram(group[Field_WindSpeed], bins=wind_speed_bins)[0]
  39. wind_speed_freq = np.maximum(wind_speed_freq, 0.01) / len(group[Field_WindSpeed]) * 100
  40. # 3. & 4. 确定y轴风速频率的范围和间隔(这里直接计算了频率,所以不需要手动设置间隔)
  41. # 我们已经计算了风速频率,因此不需要再手动设置y轴的间隔和范围
  42. # 5. 使用plotly绘制风速频率分布柱状图
  43. # 为了使用plotly绘制柱状图,我们需要将风速范围的中点作为x轴的值
  44. x_values = (wind_speed_bins[:-1] + wind_speed_bins[1:]) / 2
  45. # 创建柱状图
  46. fig = px.bar(x=x_values, y=wind_speed_freq)
  47. # 更新图形的布局
  48. fig.update_layout(
  49. title={
  50. 'text': f'风速频率: {name[0]}',
  51. # 'y': 0.95,
  52. 'x': 0.5,
  53. 'xanchor': 'center',
  54. 'yanchor': 'top'
  55. },
  56. xaxis=dict(
  57. title='风速 (m/s)',
  58. showgrid=True,
  59. range=[0, 26],
  60. dtick=1,
  61. tickangle=-45
  62. ),
  63. yaxis=dict(
  64. title='频率 (%)',
  65. showgrid=True,
  66. # range=[0, 1],
  67. ),
  68. margin=dict(t=50, b=10) # t为顶部(top)间距,b为底部(bottom)间距
  69. )
  70. # # 更新x轴和y轴的范围和标签
  71. # fig.update_yaxes(range=[0, max(wind_speed_freq) * 1.1 if max(wind_speed_freq) > 0 else 0.2], title='Frequency')
  72. # 确保从 Series 中提取的是具体的值
  73. engineTypeCode = turbineModelInfo.get(Field_MillTypeCode, "")
  74. if isinstance(engineTypeCode, pd.Series):
  75. engineTypeCode = engineTypeCode.iloc[0]
  76. engineTypeName = turbineModelInfo.get(Field_MachineTypeCode, "")
  77. if isinstance(engineTypeName, pd.Series):
  78. engineTypeName = engineTypeName.iloc[0]
  79. # 构建最终的JSON对象
  80. json_output = {
  81. "analysisTypeCode": "风速频率分析",
  82. "engineCode": engineTypeCode,
  83. "engineTypeName": engineTypeName,
  84. "xaixs": "风速(m/s)",
  85. "yaixs": "频率(%)",
  86. "data": [{
  87. "engineName": name[0],
  88. "engineCode": name[1],
  89. "title": f' 风速频率:{name[0]}',
  90. "xData": x_values.tolist(),
  91. "yData": wind_speed_freq.tolist(),
  92. }]
  93. }
  94. # Save plot
  95. filePathOfImage = os.path.join(outputAnalysisDir, f"{name[0]}.png")
  96. fig.write_image(filePathOfImage, scale=3)
  97. # filePathOfHtml = os.path.join(outputAnalysisDir, f"{name[0]}.html")
  98. # fig.write_html(filePathOfHtml)
  99. # 将JSON对象保存到文件
  100. output_json_path = os.path.join(outputAnalysisDir, f"wind_Speed_Frequency{name[0]}.json")
  101. with open(output_json_path, 'w', encoding='utf-8') as f:
  102. import json
  103. json.dump(json_output, f, ensure_ascii=False, indent=4)
  104. result_rows.append({
  105. Field_Return_TypeAnalyst: self.typeAnalyst(),
  106. Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
  107. Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
  108. Field_CodeOfTurbine: name[1],
  109. Field_Return_FilePath: filePathOfImage,
  110. Field_Return_IsSaveDatabase: False
  111. })
  112. result_rows.append({
  113. Field_Return_TypeAnalyst: self.typeAnalyst(),
  114. Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
  115. Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
  116. Field_CodeOfTurbine: name[1],
  117. Field_MillTypeCode: 'total',
  118. Field_Return_FilePath: output_json_path,
  119. Field_Return_IsSaveDatabase: True
  120. })
  121. result_df = pd.DataFrame(result_rows)
  122. return result_df