Ver código fonte

提交6个算法,1、pitchGeneratorSpeedAnalyst;2、pitchPowerAnalyst;3、windSpeedFrequencyAnalyst;4、windSpeedAnalyst;5、ratedWindSpeedAnalyst;6、dataIntegrityOfSecondAnalyst

lcb 4 meses atrás
pai
commit
084c10d883

+ 44 - 4
dataAnalysisBusiness/algorithm/dataIntegrityOfSecondAnalyst.py

@@ -122,6 +122,22 @@ class DataIntegrityOfSecondAnalyst(AnalystNotFilter):
             y_labels = result.index.tolist()    # 风机名
             x_axis_title = "日期"
             y_axis_title = "机组"
+            # 构建最终的JSON对象
+            json_output = {
+                "analysisTypeCode": "数据完整度检测(%)",
+                "engineCode": "",
+                "engineTypeName": "",
+                "xaixs": "日期",
+                "yaixs": "机组",
+                "data": [{
+                    "engineName": "",
+                    "engineCode": "",
+                    "title": f' 数据完整度%',
+                    "xData": x_labels,
+                    "yData": y_labels,
+                    "ZData": result.values.tolist(),
+                }]
+            }
         else:
             result = groupedDataFrame.pivot(
                 values="数据完整度%", index=Field_YearMonth, columns=fieldTurbineName)
@@ -129,6 +145,22 @@ class DataIntegrityOfSecondAnalyst(AnalystNotFilter):
             y_labels = result.index.tolist()    # 月份
             x_axis_title = "机组"
             y_axis_title = "日期"
+            # 构建最终的JSON对象
+            json_output = {
+                "analysisTypeCode": "数据完整度检测(%)",
+                "engineCode": "",
+                "engineTypeName": "",
+                "xaixs": "机组",
+                "yaixs": "日期",
+                "data": [{
+                    "engineName": "",
+                    "engineCode": "",
+                    "title": f' 数据完整度%',
+                    "xData": x_labels,
+                    "yData": y_labels,
+                    "ZData": result.values.tolist(),
+                }]
+            }
 
         # # 创建热图
         # fig = go.Figure(data=go.Heatmap(
@@ -186,15 +218,22 @@ class DataIntegrityOfSecondAnalyst(AnalystNotFilter):
         )
 
         result_rows = []
+
+        # 将JSON对象保存到文件
+        output_json_path = os.path.join(outputAnalysisDir, f"Data_Integrity_Of_Second_Analyst.json")
+        with open(output_json_path, 'w', encoding='utf-8') as f:
+            import json
+            json.dump(json_output, f, ensure_ascii=False, indent=4)
+
         # 保存图像
         pngFileName = f'{farmName}数据完整度分析.png'
         pngFilePath = os.path.join(outputAnalysisDir, pngFileName)
         fig.write_image(pngFilePath, scale=3)
 
         # 保存HTML
-        htmlFileName = f'{farmName}数据完整度分析.html'
-        htmlFilePath = os.path.join(outputAnalysisDir, htmlFileName)
-        fig.write_html(htmlFilePath)
+        # htmlFileName = f'{farmName}数据完整度分析.html'
+        # htmlFilePath = os.path.join(outputAnalysisDir, htmlFileName)
+        # fig.write_html(htmlFilePath)
 
         result_rows.append({
             Field_Return_TypeAnalyst: self.typeAnalyst(),
@@ -210,7 +249,8 @@ class DataIntegrityOfSecondAnalyst(AnalystNotFilter):
             Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
             Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
             Field_CodeOfTurbine: Const_Output_Total,
-            Field_Return_FilePath: htmlFilePath,
+            Field_MillTypeCode: 'total',
+            Field_Return_FilePath: output_json_path,
             Field_Return_IsSaveDatabase: True
         })
 

+ 40 - 5
dataAnalysisBusiness/algorithm/pitchGeneratorSpeedAnalyst.py

@@ -25,10 +25,12 @@ class PitchGeneratorSpeedAnalyst(AnalystWithGoodBadPoint):
 
     def turbinesAnalysis(self, outputAnalysisDir, conf: Contract, turbineCodes):
         dictionary = self.processTurbineData(turbineCodes, conf,self.selectColumns())
+        turbineInfos = self.common.getTurbineInfos(conf.dataContract.dataFilter.powerFarmID, turbineCodes,
+                                                   self.turbineInfo)
         dataFrame = self.userDataFrame(dictionary,conf.dataContract.configAnalysis,self)
-        return self.plot_speed_pitch_angle(dataFrame,outputAnalysisDir, conf, )
+        return self.plot_speed_pitch_angle(dataFrame, turbineInfos, outputAnalysisDir, conf, )
 
-    def plot_speed_pitch_angle(self, dataFrameMerge, outputAnalysisDir, conf: Contract):
+    def plot_speed_pitch_angle(self, dataFrameMerge, turbineModelInfo: pd.Series, outputAnalysisDir, conf: Contract):
         # 按设备名分组数据
         dataFrameMerge = dataFrameMerge[(dataFrameMerge[Field_ActiverPower] > 0)].sort_values(by=Field_YearMonth)
         grouped = dataFrameMerge.groupby([Field_NameOfTurbine, Field_CodeOfTurbine])
@@ -100,12 +102,44 @@ class PitchGeneratorSpeedAnalyst(AnalystWithGoodBadPoint):
                     )
                 )
             )
+            # 确保从 Series 中提取的是具体的值
+            engineTypeCode = turbineModelInfo.get(Field_MillTypeCode, "")
+            if isinstance(engineTypeCode, pd.Series):
+                engineTypeCode = engineTypeCode.iloc[0]
+
+            engineTypeName = turbineModelInfo.get(Field_MachineTypeCode, "")
+            if isinstance(engineTypeName, pd.Series):
+                engineTypeName = engineTypeName.iloc[0]
+            # 构建最终的JSON对象
+            group[Field_UnixYearMonth] = pd.to_datetime(group[Field_UnixYearMonth])
+            json_output = {
+                "analysisTypeCode": "变桨和发电机转速协调性分析",
+                "engineCode": engineTypeCode,
+                "engineTypeName": engineTypeName,
+                "xaixs": "发电机转速(r/min)",
+                "yaixs": "桨距角(°)",
+                "data": [{
+                    "engineName": name[0],
+                    "engineCode": name[1],
+                    "title": f' 机组: {name[0]}',
+                    "xData": groupNew[Field_GeneratorSpeed].tolist(),
+                    "yData": groupNew[Field_PitchAngel1].tolist(),
+                    "colorbar": dataFrameMerge[Field_YearMonth].unique().tolist(),
+
+                }]
+            }
 
             # Save plot
             filePathOfImage = os.path.join(outputAnalysisDir, f"{name[0]}.png")
             fig.write_image(filePathOfImage, scale=3)
-            filePathOfHtml = os.path.join(outputAnalysisDir, f"{name[0]}.html")
-            fig.write_html(filePathOfHtml)
+            # filePathOfHtml = os.path.join(outputAnalysisDir, f"{name[0]}.html")
+            # fig.write_html(filePathOfHtml)
+
+            # 将JSON对象保存到文件
+            output_json_path = os.path.join(outputAnalysisDir, f"pitch_GeneratorSpeed_Analyst{name[0]}.json")
+            with open(output_json_path, 'w', encoding='utf-8') as f:
+                import json
+                json.dump(json_output, f, ensure_ascii=False, indent=4)
 
             result_rows.append({
                 Field_Return_TypeAnalyst: self.typeAnalyst(),
@@ -121,7 +155,8 @@ class PitchGeneratorSpeedAnalyst(AnalystWithGoodBadPoint):
                 Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
                 Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
                 Field_CodeOfTurbine: name[1],
-                Field_Return_FilePath: filePathOfHtml,
+                Field_MillTypeCode: 'total',
+                Field_Return_FilePath: output_json_path,
                 Field_Return_IsSaveDatabase: True
             })
 

+ 86 - 12
dataAnalysisBusiness/algorithm/pitchPowerAnalyst.py

@@ -24,13 +24,15 @@ class PitchPowerAnalyst(AnalystWithGoodBadPoint):
     def turbinesAnalysis(self, outputAnalysisDir, conf: Contract, turbineCodes):
         dictionary = self.processTurbineData(turbineCodes, conf,self.selectColumns())
         dataFrame = self.userDataFrame(dictionary,conf.dataContract.configAnalysis,self)
-        result_df1 = self.plot_power_pitch_angle(dataFrame, outputAnalysisDir, conf)
-        result_df2 = self.drawScatterGraph(dataFrame, outputAnalysisDir, conf)
+        turbineInfos = self.common.getTurbineInfos(conf.dataContract.dataFilter.powerFarmID, turbineCodes,
+                                                   self.turbineInfo)
+        result_df1 = self.plot_power_pitch_angle(dataFrame, turbineInfos, outputAnalysisDir, conf)
+        result_df2 = self.drawScatterGraph(dataFrame, turbineInfos, outputAnalysisDir, conf)
         result_df = pd.concat([result_df1, result_df2], ignore_index=True)
 
         return result_df
 
-    def plot_power_pitch_angle(self, dataFrame:pd.DataFrame, outputAnalysisDir:str, conf: Contract):
+    def plot_power_pitch_angle(self, dataFrame:pd.DataFrame, turbineModelInfo: pd.Series, outputAnalysisDir:str, conf: Contract):
         # 按设备名分组数据
 
         dataFrameMerge = dataFrame[(dataFrame[Field_ActiverPower] > 0)].sort_values(by=Field_YearMonth)
@@ -127,11 +129,42 @@ class PitchPowerAnalyst(AnalystWithGoodBadPoint):
                 )
             )
 
+            # 确保从 Series 中提取的是具体的值
+            engineTypeCode = turbineModelInfo.get(Field_MillTypeCode, "")
+            if isinstance(engineTypeCode, pd.Series):
+                engineTypeCode = engineTypeCode.iloc[0]
+
+            engineTypeName = turbineModelInfo.get(Field_MachineTypeCode, "")
+            if isinstance(engineTypeName, pd.Series):
+                engineTypeName = engineTypeName.iloc[0]
+            # 构建最终的JSON对象
+            json_output = {
+                "analysisTypeCode": "变桨和有功功率协调性分析",
+                "engineCode": engineTypeCode,
+                "engineTypeName": engineTypeName,
+                "xaixs": "功率(kW)",
+                "yaixs": "桨距角(°)",
+                "data": [{
+                    "engineName": name[0],
+                    "engineCode": name[1],
+                    "title": f' 机组: {name[0]}',
+                    "xData": group[Field_ActiverPower].tolist(),
+                    "yData": group[Field_PitchAngel1].tolist(),
+                    "colorbar": dataFrameMerge[Field_YearMonth].unique().tolist(),
+                }]
+            }
+
             # 保存图像
             filePathOfImage = os.path.join(outputAnalysisDir, f"{name[0]}.png")
             fig.write_image(filePathOfImage, width=800, height=600, scale=3)
-            filePathOfHtml = os.path.join(outputAnalysisDir, f"{name[0]}.html")
-            fig.write_html(filePathOfHtml)
+            # filePathOfHtml = os.path.join(outputAnalysisDir, f"{name[0]}.html")
+            # fig.write_html(filePathOfHtml)
+
+            # 将JSON对象保存到文件
+            output_json_path = os.path.join(outputAnalysisDir, f"pitch_Power_Analyst{name[0]}.json")
+            with open(output_json_path, 'w', encoding='utf-8') as f:
+                import json
+                json.dump(json_output, f, ensure_ascii=False, indent=4)
 
             result_rows1.append({
                 Field_Return_TypeAnalyst: self.typeAnalyst(),
@@ -147,7 +180,8 @@ class PitchPowerAnalyst(AnalystWithGoodBadPoint):
                 Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
                 Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
                 Field_CodeOfTurbine: name[1],
-                Field_Return_FilePath: filePathOfHtml,
+                Field_MillTypeCode: 'total',
+                Field_Return_FilePath: output_json_path,
                 Field_Return_IsSaveDatabase: True
             })
 
@@ -155,7 +189,7 @@ class PitchPowerAnalyst(AnalystWithGoodBadPoint):
 
         return result_df1
 
-    def drawScatterGraph(self, dataFrame: pd.DataFrame,  outputAnalysisDir: str, conf: Contract):
+    def drawScatterGraph(self, dataFrame: pd.DataFrame,  turbineModelInfo: pd.Series, outputAnalysisDir: str, conf: Contract):
 
         dataFrame = dataFrame[(dataFrame[Field_ActiverPower] > 0)].sort_values(
             by=Field_YearMonth)
@@ -292,18 +326,58 @@ class PitchPowerAnalyst(AnalystWithGoodBadPoint):
                         itemwidth=80  # Set the width of legend items to 50 pixels
                     )
                 )
-
+                # 确保从 Series 中提取的是具体的值
+                engineTypeCode = turbineModelInfo.get(Field_MillTypeCode, "")
+                if isinstance(engineTypeCode, pd.Series):
+                    engineTypeCode = engineTypeCode.iloc[0]
+
+                engineTypeName = turbineModelInfo.get(Field_MachineTypeCode, "")
+                if isinstance(engineTypeName, pd.Series):
+                    engineTypeName = engineTypeName.iloc[0]
+                # 构建最终的JSON对象
+                json_output = {
+                    "analysisTypeCode": "变桨和有功功率协调性分析",
+                    "engineCode": engineTypeCode,
+                    "engineTypeName": engineTypeName,
+                    "xaixs": "桨距角(°)",
+                    "yaixs": "时间",
+                    "zaixs": "有功功率(kW)",
+                    "data": [{
+                        "engineName": name[0],
+                        "engineCode": name[1],
+                        "title": f' 月度桨距角功率3D散点图: {name[0]}',
+                        "xData": group[Field_PitchAngel1].tolist(),
+                        "yData": group[Field_YearMonth].tolist(),
+                        "zData": group[Field_ActiverPower].tolist(),
+                    }]
+                }
                 # 保存图像
-                filePathOfHtml = os.path.join(
-                    outputAnalysisDir, f"{name[0]}_3D.html")
-                fig.write_html(filePathOfHtml)
+                filePathOfImage = os.path.join(outputAnalysisDir, f"{name[0]}_3D.png")
+                fig.write_image(filePathOfImage, width=800, height=600, scale=3)
+                # filePathOfHtml = os.path.join(outputAnalysisDir, f"{name[0]}_3D.html")
+                # fig.write_html(filePathOfHtml)
 
+                # 将JSON对象保存到文件
+                output_json_path = os.path.join(outputAnalysisDir, f"pitch_Power_Analyst{name[0]}_3D.json")
+                with open(output_json_path, 'w', encoding='utf-8') as f:
+                    import json
+                    json.dump(json_output, f, ensure_ascii=False, indent=4)
+
+                result_rows2.append({
+                    Field_Return_TypeAnalyst: self.typeAnalyst(),
+                    Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
+                    Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
+                    Field_CodeOfTurbine: name[1],
+                    Field_Return_FilePath: filePathOfImage,
+                    Field_Return_IsSaveDatabase: False
+                })
                 result_rows2.append({
                     Field_Return_TypeAnalyst: self.typeAnalyst(),
                     Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
                     Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
                     Field_CodeOfTurbine: name[1],
-                    Field_Return_FilePath: filePathOfHtml,
+                    Field_MillTypeCode: 'total',
+                    Field_Return_FilePath: output_json_path,
                     Field_Return_IsSaveDatabase: True
                 })
 

+ 44 - 27
dataAnalysisBusiness/algorithm/ratedWindSpeedAnalyst.py

@@ -17,31 +17,17 @@ class RatedWindSpeedAnalyst(AnalystWithGoodBadPoint):
         return "rated_windspeed"
 
     def turbinesAnalysis(self, outputAnalysisDir, conf: Contract, turbineCodes):
-        dictionary=self.processTurbineData(turbineCodes,conf,[Field_DeviceCode,Field_Time,Field_WindSpeed,Field_ActiverPower])
+        # dictionary=self.processTurbineData(turbineCodes,conf,[Field_DeviceCode,Field_Time,Field_WindSpeed,Field_ActiverPower])
         # dataFrameMerge=self.userDataFrame(dictionary,conf.dataContract.configAnalysis,self)
-        dataFrameOfTurbines = self.userDataFrame(
-            dictionary, conf.dataContract.configAnalysis, self)
+        dictionary = self.processTurbineData(turbineCodes, conf,
+                                             [Field_DeviceCode, Field_Time, Field_WindSpeed, Field_ActiverPower])
+        turbineInfos = self.common.getTurbineInfos(conf.dataContract.dataFilter.powerFarmID, turbineCodes,
+                                                   self.turbineInfo)
+        dataFrameMerge = self.userDataFrame(dictionary, conf.dataContract.configAnalysis, self)
+        return self.draw(dataFrameMerge, turbineInfos, outputAnalysisDir, conf)
 
-        turbrineInfos = self.common.getTurbineInfos(
-            conf.dataContract.dataFilter.powerFarmID, turbineCodes, self.turbineInfo)
 
-        groupedOfTurbineModel = turbrineInfos.groupby(Field_MillTypeCode)
-
-        returnDatas = []
-        for turbineModelCode, group in groupedOfTurbineModel:
-            currTurbineCodes = group[Field_CodeOfTurbine].unique().tolist()
-            currTurbineModeInfo = self.common.getTurbineModelByCode(
-                turbineModelCode, self.turbineModelInfo)
-            currDataFrameOfTurbines = dataFrameOfTurbines[dataFrameOfTurbines[Field_CodeOfTurbine].isin(
-                currTurbineCodes)]
-            returnData= self.draw(currDataFrameOfTurbines, outputAnalysisDir, conf,currTurbineModeInfo)
-            returnDatas.append(returnData)
-
-        returnResult = pd.concat(returnDatas, ignore_index=True) 
-        return returnResult
-
-
-    def draw(self, dataFrameMerge: pd.DataFrame, outputAnalysisDir, conf: Contract,turbineModelInfo: pd.Series):
+    def draw(self, dataFrameMerge: pd.DataFrame, turbineModelInfo: pd.Series, outputAnalysisDir, conf: Contract):
         """
         绘制并保存满发风速区间数据计数图。
 
@@ -75,7 +61,7 @@ class RatedWindSpeedAnalyst(AnalystWithGoodBadPoint):
 
         fig.update_layout(
             title={
-                "text": f'额定风速间隔数据计数-{turbineModelInfo[Field_MachineTypeCode]}',
+                "text": f'额定风速间隔数据计数',
                         'x': 0.5
             },
             xaxis=dict(
@@ -87,6 +73,31 @@ class RatedWindSpeedAnalyst(AnalystWithGoodBadPoint):
             )
         )
 
+        # 确保从 Series 中提取的是具体的值
+
+        engineTypeCode = turbineModelInfo.get(Field_MillTypeCode, "")
+        if isinstance(engineTypeCode, pd.Series):
+            engineTypeCode = engineTypeCode.iloc[0]
+
+        engineTypeName = turbineModelInfo.get(Field_MachineTypeCode, "")
+        if isinstance(engineTypeName, pd.Series):
+            engineTypeName = engineTypeName.iloc[0]
+        # 构建最终的JSON对象
+        json_output = {
+            "analysisTypeCode": "额定风速分析",
+            "engineCode": engineTypeCode,
+            "engineTypeName": engineTypeName,
+            "xaixs": "机组",
+            "yaixs": "总数",
+            "data": [{
+                "engineName": "",
+                "engineCode": "",
+                "title": f' 额定风速间隔数据计数',
+                "xData": data[Field_NameOfTurbine].tolist(),
+                "yData": data['count'].tolist(),
+            }]
+        }
+
         result_rows = []
         # 保存图像
         pngFileName = '风速区间数据计数.png'
@@ -94,9 +105,14 @@ class RatedWindSpeedAnalyst(AnalystWithGoodBadPoint):
         fig.write_image(pngFilePath, scale=3)
 
         # 保存HTML
-        htmlFileName = '风速区间数据计数.html'
-        htmlFilePath = os.path.join(outputAnalysisDir, htmlFileName)
-        fig.write_html(htmlFilePath)
+        # htmlFileName = '风速区间数据计数.html'
+        # htmlFilePath = os.path.join(outputAnalysisDir, htmlFileName)
+        # fig.write_html(htmlFilePath)
+        # 将JSON对象保存到文件
+        output_json_path = os.path.join(outputAnalysisDir, f"rated_WindSpeed.json")
+        with open(output_json_path, 'w', encoding='utf-8') as f:
+            import json
+            json.dump(json_output, f, ensure_ascii=False, indent=4)
 
         result_rows.append({
             Field_Return_TypeAnalyst: self.typeAnalyst(),
@@ -112,7 +128,8 @@ class RatedWindSpeedAnalyst(AnalystWithGoodBadPoint):
             Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
             Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
             Field_CodeOfTurbine: 'total',
-            Field_Return_FilePath: htmlFilePath,
+            Field_MillTypeCode: 'total',
+            Field_Return_FilePath: output_json_path,
             Field_Return_IsSaveDatabase: True
         })
 

+ 40 - 7
dataAnalysisBusiness/algorithm/windSpeedAnalyst.py

@@ -14,10 +14,12 @@ class WindSpeedAnalyst(AnalystNotFilter):
 
     def turbinesAnalysis(self, outputAnalysisDir, conf: Contract, turbineCodes):
         dictionary=self.processTurbineData(turbineCodes,conf,[Field_DeviceCode,Field_Time,Field_WindSpeed,Field_ActiverPower])
+        turbineInfos = self.common.getTurbineInfos(conf.dataContract.dataFilter.powerFarmID, turbineCodes,
+                                                   self.turbineInfo)
         dataFrameMerge=self.userDataFrame(dictionary,conf.dataContract.configAnalysis,self)
-        return self.drawWindSpeedAnalysis(dataFrameMerge, outputAnalysisDir, conf)
+        return self.drawWindSpeedAnalysis(dataFrameMerge, turbineInfos,outputAnalysisDir, conf)
 
-    def drawWindSpeedAnalysis(self, dataFrameMerge: pd.DataFrame, outputAnalysisDir, conf: Contract):
+    def drawWindSpeedAnalysis(self, dataFrameMerge: pd.DataFrame, turbineModelInfo: pd.Series, outputAnalysisDir, conf: Contract):
         # 检查所需列是否存在
         required_columns = {Field_NameOfTurbine, Field_WindSpeed}
         if not required_columns.issubset(dataFrameMerge.columns):
@@ -33,7 +35,7 @@ class WindSpeedAnalyst(AnalystNotFilter):
 
         # 使用plotly绘制柱状图
         fig = px.bar(average_wind_speed, x=Field_NameOfTurbine,
-                     y=Field_WindSpeed, title=f'机组平均风速-{self.turbineModelInfo[Field_MachineTypeCode].iloc[0]}')
+                     y=Field_WindSpeed, title=f'机组平均风速')
 
         # 更新x轴和y轴的标签
         fig.update_xaxes(title_text='机组', tickangle=-45)
@@ -42,13 +44,43 @@ class WindSpeedAnalyst(AnalystNotFilter):
         # 可以使用 update_layout 来设置标题的 x 坐标(xanchor)为 'center' 来确保居中
         fig.update_layout(title_x=0.5)  # 设置标题的x位置为图的中心
 
+        engineTypeCode = turbineModelInfo.get(Field_MillTypeCode, "")
+        if isinstance(engineTypeCode, pd.Series):
+            engineTypeCode = engineTypeCode.iloc[0]
+
+        engineTypeName = turbineModelInfo.get(Field_MachineTypeCode, "")
+        if isinstance(engineTypeName, pd.Series):
+            engineTypeName = engineTypeName.iloc[0]
+        # 构建最终的JSON对象
+        json_output = {
+            "analysisTypeCode": "风速均值分析",
+            "engineCode": engineTypeCode,
+            "engineTypeName": engineTypeName,
+            "xaixs": "机组",
+            "yaixs": "平均风速(m/s)",
+            "data": [{
+                "engineName":"",
+                "engineCode": "",
+                "title": f'机组平均风速',
+                "xData": average_wind_speed[Field_NameOfTurbine].tolist(),
+                "yData": average_wind_speed[Field_WindSpeed].tolist(),
+
+            }]
+        }
+
         # Save plot
         filePathOfImage = os.path.join(
             outputAnalysisDir, f"WindSpeedAvg_Turbines.png")
         fig.write_image(filePathOfImage, scale=3)
-        filePathOfHtml = os.path.join(
-            outputAnalysisDir, f"WindSpeedAvg_Turbines.html")
-        fig.write_html(filePathOfHtml)
+        # filePathOfHtml = os.path.join(
+            # outputAnalysisDir, f"WindSpeedAvg_Turbines.html")
+        # fig.write_html(filePathOfHtml)
+
+        # 将JSON对象保存到文件
+        output_json_path = os.path.join(outputAnalysisDir, f"WindSpeedAvg_Turbines.json")
+        with open(output_json_path, 'w', encoding='utf-8') as f:
+            import json
+            json.dump(json_output, f, ensure_ascii=False, indent=4)
 
         result_rows = []
         result_rows.append({
@@ -65,7 +97,8 @@ class WindSpeedAnalyst(AnalystNotFilter):
             Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID,
             Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
             Field_CodeOfTurbine: "total",
-            Field_Return_FilePath: filePathOfHtml,
+            Field_MillTypeCode: 'total',
+            Field_Return_FilePath: output_json_path,
             Field_Return_IsSaveDatabase: True
         })
 

+ 41 - 7
dataAnalysisBusiness/algorithm/windSpeedFrequencyAnalyst.py

@@ -20,10 +20,12 @@ class WindSpeedFrequencyAnalyst(AnalystNotFilter):
 
     def turbinesAnalysis(self, outputAnalysisDir, conf: Contract, turbineCodes):
         dictionary=self.processTurbineData(turbineCodes,conf,[Field_DeviceCode,Field_Time,Field_WindSpeed,Field_ActiverPower])
+        turbineInfos = self.common.getTurbineInfos(conf.dataContract.dataFilter.powerFarmID, turbineCodes,
+                                                   self.turbineInfo)
         dataFrameMerge=self.userDataFrame(dictionary,conf.dataContract.configAnalysis,self)
-        return self.windRoseAnalysis(dataFrameMerge, outputAnalysisDir, conf)
+        return self.windRoseAnalysis(dataFrameMerge, turbineInfos, outputAnalysisDir, conf)
 
-    def windRoseAnalysis(self, dataFrameMerge: pd.DataFrame, outputAnalysisDir, conf: Contract):
+    def windRoseAnalysis(self, dataFrameMerge: pd.DataFrame, turbineModelInfo: pd.Series, outputAnalysisDir, conf: Contract):
         # 检查所需列是否存在
         required_columns = {Field_NameOfTurbine, Field_WindSpeed}
         if not required_columns.issubset(dataFrameMerge.columns):
@@ -33,7 +35,7 @@ class WindSpeedFrequencyAnalyst(AnalystNotFilter):
 
         # 按设备名分组数据
         grouped = dataFrameMerge.groupby([Field_NameOfTurbine, Field_CodeOfTurbine])
-        
+        turbine_data_list = []
         result_rows = []
         for name, group in grouped:
             # 2. 计算风速频率
@@ -78,12 +80,43 @@ class WindSpeedFrequencyAnalyst(AnalystNotFilter):
             )
             # # 更新x轴和y轴的范围和标签
             # fig.update_yaxes(range=[0, max(wind_speed_freq) * 1.1 if max(wind_speed_freq) > 0 else 0.2], title='Frequency')
-            
+            # 确保从 Series 中提取的是具体的值
+            engineTypeCode = turbineModelInfo.get(Field_MillTypeCode, "")
+            if isinstance(engineTypeCode, pd.Series):
+                engineTypeCode = engineTypeCode.iloc[0]
+
+            engineTypeName = turbineModelInfo.get(Field_MachineTypeCode, "")
+            if isinstance(engineTypeName, pd.Series):
+                engineTypeName = engineTypeName.iloc[0]
+            # 构建最终的JSON对象
+            json_output = {
+                "analysisTypeCode": "风速频率分析",
+                "engineCode": engineTypeCode,
+                "engineTypeName": engineTypeName,
+                "xaixs": "风速(m/s)",
+                 "yaixs": "频率(%)",
+                 "data": [{
+                    "engineName": name[0],
+                    "engineCode": name[1],
+                    "title": f' 风速频率:{name[0]}',
+                    "xData": x_values.tolist(),
+                    "yData": wind_speed_freq.tolist(),
+
+
+                }]
+            }
+
             # Save plot
             filePathOfImage = os.path.join(outputAnalysisDir, f"{name[0]}.png")
             fig.write_image(filePathOfImage, scale=3)
-            filePathOfHtml = os.path.join(outputAnalysisDir, f"{name[0]}.html")
-            fig.write_html(filePathOfHtml)
+            # filePathOfHtml = os.path.join(outputAnalysisDir, f"{name[0]}.html")
+            # fig.write_html(filePathOfHtml)
+
+            # 将JSON对象保存到文件
+            output_json_path = os.path.join(outputAnalysisDir, f"wind_Speed_Frequency{name[0]}.json")
+            with open(output_json_path, 'w', encoding='utf-8') as f:
+                import json
+                json.dump(json_output, f, ensure_ascii=False, indent=4)
             
             result_rows.append({
                 Field_Return_TypeAnalyst: self.typeAnalyst(),
@@ -99,7 +132,8 @@ class WindSpeedFrequencyAnalyst(AnalystNotFilter):
                 Field_PowerFarmCode: conf.dataContract.dataFilter.powerFarmID, 
                 Field_Return_BatchCode: conf.dataContract.dataFilter.dataBatchNum,
                 Field_CodeOfTurbine: name[1],
-                Field_Return_FilePath: filePathOfHtml,
+                Field_MillTypeCode: 'total',
+                Field_Return_FilePath: output_json_path,
                 Field_Return_IsSaveDatabase: True
             })