Explorar o código

master分支整合

chenhongyan1989 hai 2 semanas
pai
achega
4f9292828e

+ 0 - 0
dataContract/algorithmContract/__init__.py


+ 169 - 0
dataContract/algorithmContract/confBusiness.py

@@ -0,0 +1,169 @@
+from enum import Enum
+
+# 全局变量
+charset_unify = 'utf-8'
+CSVSuffix = '.csv'
+Const_Output_Total='total'
+Const_TimeGranularity_Second="second"
+Const_TimeGranularity_Minute="minute"
+
+### SCADA ###
+Field_DeviceCode="wind_turbine_number" #风机编号
+Field_ActiverPower="active_power"       #有功功率
+Field_GeneratorTorque = "actual_torque" #实际扭矩
+Field_GeneratorSpeed = "generator_speed" #发电机转速
+Field_RotorSpeed = "rotor_speed"       #风轮转速
+Field_WindSpeed = "wind_velocity"     #风速
+Field_WindDirection="true_wind_direction"  # 绝对风向
+Field_AngleIncluded = "yaw_error1"  # 对风角度
+Field_PitchAngel1="pitch_angle_blade_1"  # 桨距角1
+Field_PitchAngel2="pitch_angle_blade_2"  # 桨距角2
+Field_PitchAngel3="pitch_angle_blade_3"  # 桨距角3
+Field_Time="time_stamp"  # .strftime('%Y-%m-%d %H:%M:%S')
+Field_EnvTemp="outside_cabin_temperature"  # 环境温度
+Field_NacTemp="cabin_temperature"  # 机舱内温度
+Field_NacPos="cabin_position"  # 机舱位置
+Field_GeneratorDE="generatordrive_end_bearing_temperature"  # 发电机驱动端轴承温度/发电机低速轴温度
+Field_GeneratorNDE="generatornon_drive_end_bearing_temperature"  # 发电机非驱动端轴承温度/发电机高速轴温度
+Field_MainBearTemp="main_bearing_temperature"  # 主轴承轴承温度
+Field_GbHsBearTemp="gearbox_high_speed_shaft_bearing_temperature"  # 齿轮箱高速轴轴承温度
+Field_GbMsBearTemp="gearboxmedium_speed_shaftbearing_temperature"  # 齿轮箱中速轴轴承温度
+Field_GbLsBearTemp="gearbox_low_speed_shaft_bearing_temperature"  # 齿轮箱低速轴轴承温度
+Field_GenWiTemp1="generator_winding1_temperature"  # 发电机绕组1温度
+Field_GenWiTemp2="generator_winding2_temperature"  # 发电机绕组2温度
+Field_GenWiTemp3="generator_winding3_temperature"  # 发电机绕组3温度
+Field_GbOilTemp="gearbox_oil_temperature"  # 齿轮箱油温
+Field_PCA="power_curve_available"  # 功率曲线可用
+Field_APSet="set_value_of_active_power"  # 有功功率设定值
+Field_NacFbVib="front_back_vibration_of_the_cabin"  # 机舱前后振动
+Field_NacLrVib="side_to_side_vibration_of_the_cabin"  # 机舱左右振动
+Field_StatusOfTurbine="wind_turbine_status"  # 风机状态1
+
+# 故障/告警数据
+Field_DeviceCode="wind_turbine_number" #风机编号
+Field_DeviceName="wind_turbine_name"#风机名称
+Field_FaultTime="time_diff"#故障时长
+Field_FaultDetail="fault_detail"#故障类型
+Field_BeginTime="begin_time"#故障开始时间
+Field_EndTime="end_time"#故障开始时间
+
+
+### 二次计算 ###
+Field_Cp = "cp"
+Field_CpMedian = "cp_median"
+Field_CpMax = "cp_max"
+Field_CpMin = "cp_min"
+Field_TSR = "tsr"
+Field_TSRModified = "tsr_modified"
+Field_TSRMax = "tsr_max"
+Field_TSRMin = "tsr_min"
+Field_TSRMedian = "tsr_median"
+Field_Year="year"
+Field_Month="month"
+Field_UnixYearMonth="monthIntTime"
+Field_YearMonth = "year-month"
+Field_YearMonthDay = "year-month-day"
+Field_PowerFloor= "power_floor"
+Field_Power="power"
+Field_WindSpeedFloor= "wind_speed_floor"
+Field_YawError="yaw_error1"
+Field_LableFlag="lab"
+
+### 风场信息表 	wind_field ###
+Field_PowerFarmCode="field_code"
+Field_PowerFarmName="field_name"
+Field_ProvinceID="province_id"
+Field_ProvinceName="province_name"
+Field_CityID="city_id"
+Field_CityName="city_name"
+Field_CompanyCode="company_code"  # 企业编号
+Field_CreateBy="create_by"  # 创建人
+Field_CreateTime="create_time"  # 创建时间
+Field_AirDensity="density"  # 空气密度-合同功率曲线
+Field_NumberOfTurbine="engine_number"  # 风机数量
+Field_PowerContractURL="power_contract_url"  # 合同功率曲线地址
+Field_RatedPowerSUM="rated_capacity_number"  # 总额定容量-sum机组
+
+### 风机机组信息表 	wind_engine_group ###
+Field_NameOfTurbine="engine_name"
+Field_CodeOfTurbine="engine_code"
+Field_RatedPower="rated_capacity"  # 额定功率
+Field_RatedWindSpeed="rated_wind_speed" # 额定风速
+Field_Elevation="elevation_height"
+Field_HubHeight="hub_height"  # 轮毂高度
+Field_Latitude="latitude"  # wind_engine_mill 也有
+Field_Longitude="longitude"  # wind_engine_mill 也有
+Field_Sightcing="sightcing"  # 是否标杆风机
+
+### 风机机型信息表	wind_engine_mill ###
+Field_RotorDiameter="rotor_diameter" # 叶轮直径
+Field_Brand="brand"  # 品牌名称(风机)
+Field_Combination="combination"  # 组合字段
+Field_MotionType="curved_motion_type"  # 驱动方式
+Field_DelState="del_state"  # 删除方式
+Field_MachineTypeCode="machine_type_code"  # 机型型号
+Field_MillTypeCode="mill_type_code"  # 编号
+Field_ManufacturerCode="manufacturer_code"  # 厂商编号
+Field_ManufacturerName="manufacturer_name"  # 厂商名称
+Field_PowerCriterionURL="power_criterion_url"  # 标准功率曲线地址
+Field_TowerHeight="tower_height"
+Field_VaneLong="vane_long"  # 叶片长度
+Field_RSR="rotational_speed_ratio"  # 传动比-转速比
+Field_CutInWS="rated_cut_in_windspeed"  # 切入风速
+Field_CutOutWS="rated_cut_out_windspeed" # 切出风速
+
+### 测风塔信息 	anemometer_tower -> anemometer_tower_relation  ###
+Field_AnemometerCode="anemometer_code"
+Field_AnemometerName="anemometer_name"
+
+### 数据转换
+Field_TransferType="transfer_type"  # 转换类型 (枚举值:second、minute)
+Field_TimeGranularity="time_granularity"  # 时间粒度(秒)
+
+Field_State="state"
+Field_UpdateTime="update_time"
+Field_UpdateBy="update_by"
+
+Field_Return_TypeAnalyst="typeAnalyst"
+Field_Return_BatchCode="batch_code"
+Field_Return_FilePath="localFilePath"
+Field_Return_IsSaveDatabase:bool=True
+
+class ErrorState(Enum):
+    NotErr=0
+    Err=1     # 异常
+
+class AnalysisState(Enum):
+    NotAnalyzed=-1 # 未分析
+    RequstQueue=10 # 请求队列中
+    Analyzing=20    # 分析中
+    Analyzed=30     # 已分析
+
+class CustomError(Exception):
+    ERROR_CODES = {
+        -1:"未知异常,请联系技术人员排查问题",
+        100: "未获得业务基础数据,或基础数据缺失",
+        101: "未获得业务数据,或业务数据与基础数据不匹配",
+        102: "缺少风电机组运行数据",
+        103: "算法模型未输出结果",
+        104: "缺失场站基础信息",
+        105: "缺失机组基础信息",
+        106: "缺失场站的数据批次信息",
+        107: "场站存在未配置机型信息(额定风速、切入风速、切出风速)的机组",
+        108: "缺失机组的合同功率曲线信息",
+        109: "场站存在未配置额定功率的机组",
+        110: "场站未配置空气密度",
+        111: "场站所属风电机组存在未配置叶轮直径",
+        112: "SCADA数据不包含风速或其全无值",
+        113: "SCADA数据不包含有功功率或其全无值",
+        114: "机组未配置机型信息",
+        115: "机组未配置基础信息",
+    }
+
+    def __init__(self, code,msg=""):
+        self.code = code
+        self.message =f"{msg} {self.ERROR_CODES.get(code, CustomError.ERROR_CODES.get(-1))}"
+        super().__init__(self.message)
+
+    def __str__(self):
+        return f"[Error Code: {self.code}] {self.message}"

+ 14 - 0
dataContract/algorithmContract/configAnalysis.py

@@ -0,0 +1,14 @@
+class ConfigAnalysis:
+    def __init__(self, package: str, className: str, methodName: str,scada:str):
+        self.package = package
+        self.className = className
+        self.methodName = methodName
+        self.scada=scada
+
+    def to_dict(self):
+        return {
+            "package": self.package,
+            "className": self.className,
+            "methodName": self.methodName,
+            "scada":self.scada
+        }

+ 3 - 0
dataContract/algorithmContract/const.py

@@ -0,0 +1,3 @@
+
+DATABASE_BusinessFoundationDb="businessFoundationDb"
+DATABASE_businessDb="businessDb"

+ 199 - 0
dataContract/algorithmContract/contract.py

@@ -0,0 +1,199 @@
+import traceback
+import json
+from algorithmContract.dataContractType import DataContractType
+from algorithmContract.customDataContract import DataContract
+from algorithmContract.dataSource import DataSource
+from algorithmContract.dataFilter import DataFilter
+from algorithmContract.customFilter import CustomFilter
+from algorithmContract.configAnalysis import ConfigAnalysis
+from algorithmContract.graphSet import GraphSet
+
+
+class Contract:
+    def __init__(self, contractType: DataContractType, dataContract: DataContract):
+        self.contractType = contractType
+        self.dataContract = dataContract
+
+    def to_dict(self):
+        return {
+            "dataContractType": self.contractType.to_dict(),
+            "dataContract": self.dataContract.to_dict()
+        }
+
+
+def LoadAnalysisInput(jsonString: str):
+    # Load the JSON string into a Python dictionary
+    try:
+        jsonData = json.loads(jsonString)
+
+        jsonDataType = jsonData["dataContractType"]
+        contractType = DataContractType(
+            jsonDataType["type"], jsonDataType["version"])
+
+        jsonDataContract = jsonData["dataContract"]
+
+        autoOrManual = jsonDataContract["autoOrManual"]
+        # Initialize the entity classes using the JSON data
+        # data_source = DataSource(jsonDataContract["dataSource"]["scada"])
+
+        custom_filters = {}
+        for key, value in jsonDataContract["dataFilter"]["customFilter"].items():
+            custom_filter = CustomFilter(value.get("min"), value.get("max"))
+            custom_filters[key] = custom_filter
+            
+        if (not jsonDataContract["dataFilter"]["turbines"] is None) and (not isinstance(jsonDataContract["dataFilter"]["turbines"],list)):
+              raise Exception("输入参数中机组数据类型不合法.")  
+
+        data_filter = DataFilter(
+            jsonDataContract["dataFilter"]["powerFarmID"],
+            jsonDataContract["dataFilter"]["turbines"],
+            jsonDataContract["dataFilter"]["dataBatchNum"],
+            jsonDataContract["dataFilter"]["beginTime"],
+            jsonDataContract["dataFilter"]["endTime"],
+            jsonDataContract["dataFilter"]["excludingMonths"],
+            custom_filters
+        )
+
+        config_analysis = []
+        for item in jsonDataContract["configAnalysis"]:
+            analysis = ConfigAnalysis(
+                item["package"], item["className"], item["methodName"], item["scada"])
+            config_analysis.append(analysis)
+
+        graph_sets = {}
+        for key, value in jsonDataContract["graphSets"].items():
+            graph_set = GraphSet(value["step"], value["min"], value["max"])
+            graph_sets[key] = graph_set
+
+        data_contract = DataContract(autoOrManual,
+                                     data_filter, config_analysis, graph_sets)
+
+        contract = Contract(contractType, data_contract)
+    except Exception as e:
+        print("exception: {}".format(e))
+        traceback.print_exc()  # 打印异常的堆栈跟踪
+        raise e
+
+    return contract
+
+
+# JSON string representing the data contract
+jsonString = '''
+{
+	"dataContractType": {
+		"type": "analysisExecuteOrder",
+		"version": "1.2.0"
+	},
+	"dataContract": {
+		"autoOrManual":"automatic",
+		"dataSource": {
+			"scada": "second"
+		},
+		"dataFilter": {
+			"powerFarmID": "010-00001",
+			"turbines": [
+				"010-00001-0001",
+				"010-00001-0002"
+			],
+			"dataBatchNum": "B2024042211-0",
+			"beginTime": "2023-01-01 00:00:00",
+			"endTime": "2023-12-31 23:59:59",
+			"excludingMonths": [
+				"2023-12",
+				"2023-09"
+			],
+			"customFilter": {
+				"valueWindSpeed": {
+					"min": 3.0,
+					"max": 25.0
+				},
+				"valuePitchAngle": {
+					"min": 2,
+					"max": null
+				},
+				"valueActivePower": {
+					"min": 10,
+					"max": 2500
+				},
+				"valueGeneratorSpeed": {
+					"min": 10,
+					"max": 2500
+				}
+			}
+		},
+		"configAnalysis": [
+			{
+				"package": "algorithm.powerCurveAnalyst",
+				"className": "PowerCurveAnalyst",
+				"methodName": "executeAnalysis"
+			},
+			{
+				"package": "algorithm.powerScatter2DAnalyst",
+				"className": "PowerScatter2DAnayst",
+				"methodName": "executeAnalysis"
+			},
+			{
+				"package": "algorithm.powerScatterAnalyst",
+				"className": "PowerScatterAnalyst",
+				"methodName": "executeAnalysis"
+			},
+			{
+				"package": "algorithm.windSpeedFrequencyAnalyst",
+				"className": "WindSpeedFrequencyAnalyst",
+				"methodName": "executeAnalysis"
+			},
+			{
+				"package": "algorithm.generatorSpeedPowerAnalyst",
+				"className": "GeneratorSpeedPowerAnalyst",
+				"methodName": "executeAnalysis"
+			}
+		],
+		"graphSets": {
+			"generatorSpeed": {
+				"step": 200,
+				"min": 1000,
+				"max": 2000
+			},
+			"generatorTorque": {
+				"step": 2000,
+				"min": 0,
+				"max": 12000
+			},
+			"cp": {
+				"step": 0.5,
+				"min": 0,
+				"max": 2
+			},
+			"tsr": {
+				"step": 5,
+				"min": 0,
+				"max": 30
+			},
+			"pitchAngle": {
+				"step": 1,
+				"min": -1,
+				"max": 20
+			},
+			"activePower": {
+				"step": 250,
+				"min": 0,
+				"max": 2000
+			}
+		}
+	}
+}
+'''
+
+
+def load():
+    return LoadAnalysisInput(jsonString)
+
+
+def Analysis(contract: Contract):
+    jsonString = ""
+    try:
+        contractDict = contract.to_dict()  # 先转换为字典
+        jsonString = json.dumps(contractDict)
+    except:
+        traceback.print_exc()
+    return jsonString

+ 35 - 0
dataContract/algorithmContract/customDataContract.py

@@ -0,0 +1,35 @@
+import types
+from algorithmContract.dataSource import DataSource
+from algorithmContract.dataFilter import DataFilter
+from algorithmContract.customFilter import CustomFilter
+from algorithmContract.configAnalysis import ConfigAnalysis
+from algorithmContract.graphSet import GraphSet
+
+
+class DataContract:
+    def __init__(self,autoOrManual:str , dataFilter: DataFilter, configAnalysis: list[ConfigAnalysis], graphSets: dict[str,GraphSet]):
+        self.autoOrManual=autoOrManual
+        # self.dataSource = dataSource
+        self.dataFilter = dataFilter
+        self.configAnalysis = configAnalysis
+        self.graphSets = graphSets
+
+    def _graph_sets_to_dict(self, graph_sets):
+        result = {}
+        for key, value in graph_sets.items():
+            if isinstance(value, GraphSet):
+                result[key] = value.to_dict()
+            elif isinstance(value, dict):
+                result[key] = self._graph_sets_to_dict(value)
+            else:
+                raise TypeError(f"Unsupported type for graph set value: {type(value)}")
+        return result
+
+    def to_dict(self):
+        return {
+            "autoOrManual":self.autoOrManual,
+            # "dataSource": self.dataSource.to_dict(),
+            "dataFilter": self.dataFilter.to_dict(),            
+            "configAnalysis": [analysis.to_dict() for analysis in self.configAnalysis],  # 修改这一行
+            "graphSets": {key: graph.to_dict() for key, graph in self.graphSets.items()}  # 假设 graphSets 是一个字典 # self._graph_sets_to_dict(self.graphSets) # 
+        }

+ 7 - 0
dataContract/algorithmContract/customFilter.py

@@ -0,0 +1,7 @@
+class CustomFilter:
+    def __init__(self, min_val:float, max_val:float):
+        self.min = min_val
+        self.max = max_val
+
+    def to_dict(self):
+        return {"min": self.min,"max":self.max}

+ 7 - 0
dataContract/algorithmContract/dataContractType.py

@@ -0,0 +1,7 @@
+class DataContractType:
+    def __init__(self, type:str, version:str):
+        self.type = type
+        self.version = version
+    
+    def to_dict(self):
+        return {"type": self.type,"version":self.version}

+ 23 - 0
dataContract/algorithmContract/dataFilter.py

@@ -0,0 +1,23 @@
+from algorithmContract.customFilter import CustomFilter
+
+
+class DataFilter:
+    def __init__(self, powerFarmID: str, turbines: list, dataBatchNum: str, beginTime: str, endTime: str, excludingMonths: list, customFilter: dict[str,CustomFilter]):
+        self.powerFarmID = powerFarmID
+        self.turbines = turbines
+        self.dataBatchNum = dataBatchNum
+        self.beginTime = beginTime
+        self.endTime = endTime
+        self.excludingMonths = excludingMonths
+        self.customFilter = customFilter
+
+    def to_dict(self):
+        return {
+            "powerFarmID": self.powerFarmID,
+            "turbines": self.turbines,
+            "dataBatchNum": self.dataBatchNum,
+            "beginTime": self.beginTime,
+            "endTime": self.endTime,
+            "excludingMonths": self.excludingMonths,
+            "customFilter": {key: filter.to_dict() for key, filter in self.customFilter.items()}
+        }

+ 6 - 0
dataContract/algorithmContract/dataSource.py

@@ -0,0 +1,6 @@
+class DataSource:
+    def __init__(self, scada:str):
+        self.scada = scada
+        
+    def to_dict(self):
+        return {"scada": self.scada}

+ 8 - 0
dataContract/algorithmContract/graphSet.py

@@ -0,0 +1,8 @@
+class GraphSet:
+    def __init__(self, step:float, min_val:float, max_val:float):
+        self.step = step
+        self.min = min_val
+        self.max = max_val
+
+    def to_dict(self):
+        return {"step": self.step,"min":self.min,"max":self.max}

+ 107 - 0
dataContract/algorithmContract/testDataContract.py

@@ -0,0 +1,107 @@
+import json
+from algorithmContract.contract import LoadAnalysisInput,Analysis
+
+
+
+# JSON string representing the data contract
+jsonString = '''
+{
+	"dataContractType": {
+		"type": "analysisExecuteOrder",
+		"version": "1.2.0"
+	},
+	"dataContract": {
+		"autoOrManual": "automatic",
+		"dataFilter": {
+			"powerFarmID": "WOF01000002",
+			"turbines": null,
+			"dataBatchNum": "zhaoyuan_20240528",
+			"beginTime": "2023-01-01 00:00:00",
+			"endTime": "2024-12-31 23:59:59",
+			"excludingMonths": [
+				"2023-12",
+				"2023-09"
+			],
+			"customFilter": {
+				"valueWindSpeed": {
+					"min": 3.0,
+					"max": 25.0
+				},
+				"valuePitchAngle": {
+					"min": 2,
+					"max": null
+				},
+				"valueActivePower": {
+					"min": 10,
+					"max": 2500
+				},
+				"valueGeneratorSpeed": {
+					"min": 10,
+					"max": 2500
+				}
+			}
+		},
+		"configAnalysis": [
+			{
+				"package": "algorithm.temperatureLargeComponentsAnalyst",
+				"className": "TemperatureLargeComponentsAnalyst",
+				"methodName": "executeAnalysis",
+				"scada": "minute"
+			}
+		],
+		"graphSets": {
+			"directDrive": {
+				"generatorSpeed": {
+					"step": 5,
+					"min": 0,
+					"max": 30
+				},
+				"generatorTorque": {
+					"step": 10000,
+					"min": 0,
+					"max": 100000
+				}
+			},
+			"indirectDrive": {
+				"generatorSpeed": {
+					"step": 200,
+					"min": 1000,
+					"max": 2000
+				},
+				"generatorTorque": {
+					"step": 2000,
+					"min": 0,
+					"max": 12000
+				}
+			},
+			"tsr": {
+				"step": 5,
+				"min": 0,
+				"max": 30
+			},
+			"pitchAngle": {
+				"step": 1,
+				"min": -1,
+				"max": 20
+			},
+			"activePower": {
+				"step": 250,
+				"min": 0,
+				"max": 2000
+			}
+		}
+	}
+}
+'''
+
+
+data=LoadAnalysisInput(jsonString)
+
+print(data.dataContract.graphSets["directDrive"]["generatorSpeed"].step)
+print(data.dataContract.graphSets["directDrive"]["generatorTorque"].step)
+
+string=Analysis(data)
+print(string)
+
+
+