faultAnalyst.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. import pandas as pd
  2. import os
  3. from algorithmContract.confBusiness import *
  4. from algorithmContract.contract import Contract
  5. from behavior.analystNotFilter import AnalystNotFilter
  6. class FaultAnalyst(AnalystNotFilter):
  7. """
  8. 风电机组故障分析
  9. 新逻辑:基于首发故障结束时间划分窗口, 以首发故障的结束时间为界,后续故障的开始时间如果 ≤ 这个结束时间,则视为连带故障;否则作为新的首发故障。
  10. 风场范围的故障分析
  11. 统计风场范围内 首发故障中各故障发生的次数和累计时长
  12. """
  13. def typeAnalyst(self):
  14. return "fault"
  15. def selectColumns(self):
  16. # 直接返回数据库表中的真实列名
  17. return ["wind_turbine_name", "begin_time", "end_time", "fault_detail"]
  18. #风机原始名称、故障开始时间、故障结束时间、故障描述
  19. def getTimeGranularitys(self, conf: Contract):
  20. return ["fault"]
  21. def turbinesAnalysis(self, outputAnalysisDir, conf: Contract, turbineCodes):
  22. dictionary = self.processTurbineData(turbineCodes, conf, self.selectColumns())
  23. dataFrameMerge = dictionary.get("fault", pd.DataFrame())
  24. if dataFrameMerge.empty:
  25. return pd.DataFrame()
  26. return self.get_result(dataFrameMerge, outputAnalysisDir, conf)
  27. def get_result(self, dataFrame: pd.DataFrame, outputAnalysisDir: str, conf: Contract):
  28. if dataFrame.empty:
  29. return pd.DataFrame()
  30. df = dataFrame.copy()
  31. # 转换时间列
  32. df["begin_time"] = pd.to_datetime(df["begin_time"])
  33. df["end_time"] = pd.to_datetime(df["end_time"])
  34. df = df.dropna(subset=["begin_time", "end_time"])
  35. if df.empty:
  36. return pd.DataFrame()
  37. # 存储中间结果
  38. turbine_events = []
  39. fault_events = []
  40. # 按风机分组处理
  41. for turbine, group in df.groupby("wind_turbine_name"):
  42. group = group.sort_values("begin_time").reset_index(drop=True)
  43. i = 0
  44. n = len(group)
  45. while i < n:
  46. primary = group.iloc[i]
  47. primary_start = primary["begin_time"]
  48. primary_end = primary["end_time"]
  49. duration_sec = (primary_end - primary_start).total_seconds()
  50. turbine_events.append({
  51. "turbine": turbine,
  52. "duration_sec": duration_sec
  53. })
  54. fault_events.append({
  55. "fault_detail": primary["fault_detail"],
  56. "duration_sec": duration_sec
  57. })
  58. # 跳过连带故障
  59. j = i + 1
  60. while j < n and group.iloc[j]["begin_time"] <= primary_end:
  61. j += 1
  62. i = j
  63. # 聚合风机维度
  64. if turbine_events:
  65. turbine_df = pd.DataFrame(turbine_events)
  66. turbine_summary = turbine_df.groupby("turbine").agg(
  67. count=("duration_sec", "size"),
  68. fault_time=("duration_sec", "sum")
  69. ).reset_index()
  70. turbine_summary = turbine_summary.rename(columns={"turbine": "wind_turbine_name"})
  71. turbine_file = os.path.join(outputAnalysisDir, f"turbine_fault_result{CSVSuffix}")
  72. turbine_summary.to_csv(turbine_file, index=False, encoding='utf-8-sig')
  73. else:
  74. turbine_summary = pd.DataFrame()
  75. # 聚合故障类型维度
  76. if fault_events:
  77. fault_df = pd.DataFrame(fault_events)
  78. fault_summary = fault_df.groupby("fault_detail").agg(
  79. count=("duration_sec", "size"),
  80. fault_time_sum=("duration_sec", "sum")
  81. ).reset_index()
  82. fault_file = os.path.join(outputAnalysisDir, f"total_fault_result{CSVSuffix}")
  83. fault_summary.to_csv(fault_file, index=False, encoding='utf-8-sig')
  84. else:
  85. fault_summary = pd.DataFrame()
  86. # 返回结果
  87. result_rows = []
  88. if not turbine_summary.empty:
  89. result_rows.append({
  90. Field_Return_TypeAnalyst: self.typeAnalyst(),
  91. Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
  92. Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
  93. Field_CodeOfTurbine: "total",
  94. Field_MillTypeCode: "turbine_fault_result",
  95. Field_Return_FilePath: turbine_file,
  96. Field_Return_IsSaveDatabase: True
  97. })
  98. if not fault_summary.empty:
  99. result_rows.append({
  100. Field_Return_TypeAnalyst: self.typeAnalyst(),
  101. Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
  102. Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
  103. Field_CodeOfTurbine: "total",
  104. Field_MillTypeCode: "total_fault_result",
  105. Field_Return_FilePath: fault_file,
  106. Field_Return_IsSaveDatabase: True
  107. })
  108. return pd.DataFrame(result_rows)