import os import pandas as pd import numpy as np import matplotlib.pyplot as plt from matplotlib.pyplot import MultipleLocator import math import pdb # pdb.set_trace() # 设置断点 intervalPower = 25 # For example intervalWindspeed = 0.25 # For example fieldRatedPower="额定功率" fieldRatedWindSpeed="额定风速" fieldWindSpeedCutIn="切入风速" fieldWindSpeedCutOut="切出风速" fieldTime="时间" fieldWindSpeed="风速" fieldActivePower="变频器电网侧有功功率" fieldLabel="lab" # 1. 数据加载和预处理函数 def loadData(filePathSCADA:str, filePathTurbineInfo:str): dataFrameSCADA = pd.read_csv(filePathSCADA, encoding="utf-8") dataFrameTurbineInfo = pd.read_csv(filePathTurbineInfo) return dataFrameSCADA, dataFrameTurbineInfo def extractTurbineParameters(turbineInfo:pd.DataFrame): """ 解析风电机组参数 参数: turbineInfo 风电机组信息DataFrame 返回: PRated 额定功率(kw) VCutOut 切出风速(m/s) VCutIn 切入风速(m/s) VRated 额定风速(m/s) """ ratedPower = turbineInfo.loc[:, [fieldRatedPower]].values windSpeedCutIn = turbineInfo.loc[:, [fieldWindSpeedCutIn]].values windSpeedCutOut = turbineInfo.loc[:, [fieldWindSpeedCutOut]].values ratedWindSpeed = turbineInfo.loc[:, [fieldRatedWindSpeed]].values return ratedPower, windSpeedCutOut, windSpeedCutIn, ratedWindSpeed def preprocessData(dataFrameOfSCADA:pd.DataFrame): """ 获取机组SCADA数据的 时间、有功功率、风速,构建新的DataFrame变量 参数: dataFrameOfSCADA 机组SCADA数据 返回: 由机组SCADA数据的 时间、有功功率、风速,构建新的DataFrame变量 """ timeStamp = dataFrameOfSCADA.loc[:, ['时间']] activePower = dataFrameOfSCADA.loc[:, ['变频器电网侧有功功率']] windSpeed = dataFrameOfSCADA.loc[:, ['风速']] dataFramePartOfSCADA = pd.concat([timeStamp,activePower,windSpeed], axis=1) # dataFramePartOfSCADA[fieldLabel]=0 # dataFramePartOfSCADA[fieldLabel]=dataFramePartOfSCADA[fieldLabel].astype(int) return dataFramePartOfSCADA # 2. 数据标签分配和分箱计算 def calculateIntervals(activePowerMax, ratedPower, windSpeedCutOut): """ 按有功功率(以25kw为间隔)、风速(以0.25m/s为间隔)分仓 参数: max_power 当前机组的有功功率最大值 PRated 机组额定功率 wind_speed_cutout 切出风速 返回: interval_power 有功功率分仓间隔 interval_windspeed 风速分仓间隔 PNum 有功功率分仓数量 VNum 风速分仓数量 """ binNumOfPower = math.floor(activePowerMax / intervalPower) + 1 if activePowerMax >= ratedPower else math.floor(ratedPower / intervalPower) binNumOfWindSpeed = math.ceil(windSpeedCutOut / intervalWindspeed) return binNumOfPower, binNumOfWindSpeed def calculateTopP(activePowerMax,ratedPower): """ 计算额定功率以上功率仓的个数 参数: max_power 当前机组的有功功率最大值 PRated 机组额定功率 返回: TopP 额定功率以上功率仓的个数 """ TopP = 0 if activePowerMax >= ratedPower: TopP = math.floor((activePowerMax - ratedPower) / intervalPower) + 1 else: TopP = 0 return TopP def chooseData(dataFramePartOfSCADA:pd.DataFrame, dataFrameOfSCADA): """ 根据特定条件对数据进行标签分配,例如功率和风速阈值。 参数: dataFramePartOfSCADA (DataFrame): 包含时间和功率和风速数据的DataFrame。 dataFrameOfSCADA: 原始数据 返回: DzMarch809: array:V P lab: 38181。 nCounter1: 个数 dataFramePartOfSCADA: """ # 初始化标签列 SM1 = dataFramePartOfSCADA.shape #(52561,3) AA1 = SM1[0] lab = [[0] for _ in range(AA1)] lab = pd.DataFrame(lab,columns=['lab']) dataFramePartOfSCADA = pd.concat([dataFramePartOfSCADA,lab],axis=1) #在tpv后加一列标签列 dataFramePartOfSCADA = dataFramePartOfSCADA.values SM = dataFramePartOfSCADA.shape #(52561,4) AA = SM[0] nCounter1 = 0 DzMarch809_0 = np.zeros((AA, 3)) Point_line = np.zeros(AA, dtype=int) APower = dataFrameOfSCADA[fieldActivePower] WSpeed = dataFrameOfSCADA[fieldWindSpeed] for i in range(AA): if (APower[i] > 10) & (WSpeed[i] > 0): nCounter1 += 1 DzMarch809_0[nCounter1-1, 0] = WSpeed[i] DzMarch809_0[nCounter1-1, 1] = APower[i] Point_line[nCounter1-1] = i+1 if APower[i] <= 10: dataFramePartOfSCADA[i,SM[1]-1] = -1 DzMarch809 = DzMarch809_0[:nCounter1, :] return DzMarch809,nCounter1,dataFramePartOfSCADA,Point_line,SM def gridCount(binNumOfWindSpeed,binNumOfPower,nCounter1,DzMarch809): """ 统计各网格中落入label!=-1的数据点个数 参数: binNumOfWindSpeed: 风速分仓个数。 binNumOfPower: 功率分仓个数。 DataFrame: 带有新的'label'列的原始DataFrame。 nCounter1: 数据个数 DzMarch809 返回: XBoxNumber: 各网格中落入label!=-1的数据点个数的array。 """ # 遍历有效数据 XBoxNumber = np.ones((binNumOfPower, binNumOfWindSpeed),dtype=int) for i in range(nCounter1): for m in range(1, binNumOfPower + 1): if (DzMarch809[i,1] > (m - 1) * intervalPower) and (DzMarch809[i,1] <= m * intervalPower): nWhichP = m break for n in range(1, binNumOfWindSpeed + 1): if (DzMarch809[i, 0] > (n - 1) * intervalWindspeed) and (DzMarch809[i, 0] <= n * intervalWindspeed): nWhichV = n break if (nWhichP > 0) and (nWhichV > 0): XBoxNumber[nWhichP - 1][nWhichV - 1] += 1 for m in range(1,binNumOfPower+1): for n in range(1,binNumOfWindSpeed+1): XBoxNumber[m-1,n-1] = XBoxNumber[m-1,n-1] - 1 return XBoxNumber def percentageDots(XBoxNumber, binNumOfPower, binNumOfWindSpeed,axis): """ 计算分仓(水平/竖直)后每个网格占百分比 参数: XBoxNumber: 各网格中落入label!=-1的数据点个数的array。 binNumOfPower: 功率分仓个数。 binNumOfWindSpeed: 风速分仓个数。 axis: "power"or"speed"分仓 返回: BoxPercent: 占比情况array。 """ BoxPercent = np.zeros((binNumOfPower, binNumOfWindSpeed), dtype=float) BinSum = np.zeros((binNumOfPower if axis == 'power' else binNumOfWindSpeed, 1), dtype=int) for i in range(1,1+(binNumOfPower if axis == 'power' else binNumOfWindSpeed)): for m in range(1,(binNumOfWindSpeed if axis == 'power' else binNumOfPower)+1): BinSum[i-1] = BinSum[i-1] + (XBoxNumber[i-1,m-1] if axis == 'power' else XBoxNumber[m-1,i-1]) for m in range(1,(binNumOfWindSpeed if axis == 'power' else binNumOfPower)+1): if BinSum[i-1]>0: if axis == 'power': BoxPercent[i-1,m-1] = (XBoxNumber[i-1,m-1] / BinSum[i-1])*100 else: BoxPercent[m-1,i-1] = (XBoxNumber[m-1,i-1] / BinSum[i-1])*100 return BoxPercent,BinSum def maxBoxPercentage(BoxPercent, binNumOfPower, binNumOfWindSpeed, axis): """ 计算分仓(水平/竖直)后占百分比最大的网格索引及值 参数: BoxPercent: 占比情况array。 binNumOfPower: 功率分仓个数。 binNumOfWindSpeed: 风速分仓个数。 axis: "power"or"speed"分仓 返回: BoxMaxIndex: 占百分比最大的网格索引。 BoxMax: 占百分比最大的网格值 """ BoxMaxIndex = np.zeros((binNumOfPower if axis == 'power' else binNumOfWindSpeed,1),dtype = int) BoxMax = np.zeros((binNumOfPower if axis == 'power' else binNumOfWindSpeed,1),dtype = float) for m in range(1,(binNumOfPower if axis == 'power' else binNumOfWindSpeed)+1): BoxMaxIndex[m-1] = (np.argmax(BoxPercent[m-1, :])) if axis == 'power' else (np.argmax(BoxPercent[:, m-1])) BoxMax[m-1] = (np.max(BoxPercent[m-1, :]))if axis == 'power' else (np.max(BoxPercent[:, m-1])) return BoxMaxIndex, BoxMax def extendBoxPercent(m, BoxMax,TopP,BoxMaxIndex,BoxPercent,binNumOfPower,binNumOfWindSpeed): """ 以中心最大水平功率带为基准,向两侧对称扩展网格,使网格散点百分比总值达到阈值m 参数: m: 设定总和百分比阈值。 BoxMax: 占百分比最大的网格值。 TopP: 额定功率以上功率仓个数。 BoxMaxIndex: 占百分比最大的网格索引。 BoxPercent: 占比情况array。 binNumOfPower: 功率分仓个数。 binNumOfWindSpeed: 风速分仓个数。 返回: DotDense: 每个功率仓内网格的个数。 DotDenseLeftRight: 向左向右拓展的网格个数 """ DotDense = np.zeros(binNumOfPower) DotDenseLeftRight = np.zeros((binNumOfPower,2)) DotValve = m PDotDenseSum = 0 for i in range(binNumOfPower - TopP): PDotDenseSum = BoxMax[i] iSpreadRight = 1 iSpreadLeft = 1 while PDotDenseSum < DotValve: if (BoxMaxIndex[i] + iSpreadRight) < binNumOfWindSpeed-1-1: PDotDenseSum += BoxPercent[i, BoxMaxIndex[i] + iSpreadRight] iSpreadRight += 1 else: break if (BoxMaxIndex[i] - iSpreadLeft) > 0: PDotDenseSum += BoxPercent[i, BoxMaxIndex[i] - iSpreadLeft] iSpreadLeft += 1 else: break iSpreadRight = iSpreadRight-1 iSpreadLeft = iSpreadLeft-1 DotDenseLeftRight[i, 0] = iSpreadLeft DotDenseLeftRight[i, 1] = iSpreadRight DotDense[i] = iSpreadLeft + iSpreadRight + 1 return DotDenseLeftRight def calculatePWidth(binNumOfPower,TopP,DotDenseLeftRight,PBinSum): """ 计算功率主带的平均宽度 参数: binNumOfPower: 功率分仓个数。 TopP: 额定功率以上功率仓个数。 DotDenseLeftRight: 向左向右拓展的网格个数 PBinSum: 功率仓内数据点总和 返回: DotDense: 每个功率仓内网格的个数。 DotDenseLeftRight: 向左向右拓展的网格个数 PowerLimit: 各水平功率带是否为限功率标识,1:是;0:不是 """ PowerLimit = np.zeros(binNumOfPower, dtype=int) WidthAverage = 0 WidthAverage_L = 0 nCounter = 0 PowerLimitValve = 6 N_Pcount = 20 for i in range(binNumOfPower - TopP): if (DotDenseLeftRight[i, 1] > PowerLimitValve) and (PBinSum[i] > N_Pcount): PowerLimit[i] = 1 if DotDenseLeftRight[i, 1] <= PowerLimitValve: WidthAverage += DotDenseLeftRight[i, 1] WidthAverage_L += DotDenseLeftRight[i,1] nCounter += 1 WidthAverage /= nCounter if nCounter > 0 else 1 WidthAverage_L /= nCounter if nCounter > 0 else 1 return WidthAverage, WidthAverage_L,PowerLimit def amendMaxBox(binNumOfPower,TopP,PowerLimit,BoxMaxIndex): """ 对限负荷水平功率带的最大网格进行修正 参数: binNumOfPower: 功率分仓个数。 TopP: 额定功率以上功率仓个数。 PowerLimit:标识限功率水平功率带,1:是;0:不是 BoxMaxIndex: 占百分比最大的网格索引 返回: BoxMaxIndex: 修正后的最大占比网格索引 """ for i in range(1, binNumOfPower - TopP+1): if (PowerLimit[i] == 1) and (abs(BoxMaxIndex[i] - BoxMaxIndex[i - 1]) > 5): BoxMaxIndex[i] = BoxMaxIndex[i - 1] + 1 return BoxMaxIndex def markBoxLimit(binNumOfPower,binNumOfWindSpeed,TopP,CurveWidthR,CurveWidthL,BoxMaxIndex): ''' 标记需剔除的网格 参数: binNumOfPower: 功率分仓个数。 binNumOfWindSpeed:风速分仓个数 TopP: 额定功率以上功率仓个数。 CurveWidthR:功率主带轮廓 CurveWidthL BoxMaxIndex: 修正后的最大占比网格索引 返回: BBoxRemove: 标识需剔除的网格 ''' BBoxRemove = np.zeros((binNumOfPower, binNumOfWindSpeed), dtype=int) for m in range(binNumOfPower - TopP): for n in range(int(BoxMaxIndex[m]) + int(CurveWidthR), binNumOfWindSpeed): BBoxRemove[m, n] = 1 for n in range(int(BoxMaxIndex[m]) - int(CurveWidthL)+1, 0, -1): BBoxRemove[m, n-1] = 2 return BBoxRemove def markBoxPLimit(binNumOfPower,binNumOfWindSpeed,TopP,CurveWidthR,PowerLimit,BoxPercent,BoxMaxIndex,mm,BBoxRemove,nn): ''' 标记限功率网格 1:右侧欠发 2:左侧超发 3:额定功率以上超发 参数: binNumOfPower: 功率分仓个数。 binNumOfWindSpeed:风速分仓个数 TopP: 额定功率以上功率仓个数。 CurveWidthR:功率主带轮廓 PowerLimit: 标识限功率水平功率带,1:是;0:不是 BoxMaxIndex: 修正后的最大占比网格索引 mm: 拐点所在功率仓 BBoxRemove:需剔除的网格 CurveTop1:拐点对应列 返回: BBoxLimit:标识限功率网格 ''' BBoxLimit = np.zeros((binNumOfPower, binNumOfWindSpeed), dtype=int) for i in range(2, binNumOfPower - TopP): if PowerLimit[i] == 1: BBoxLimit[i, int(BoxMaxIndex[i] + CurveWidthR + 1):binNumOfWindSpeed] = 1 IsolateValve = 3 for m in range(binNumOfPower - TopP): for n in range(int(BoxMaxIndex[m]) + int(CurveWidthR), binNumOfWindSpeed): if BoxPercent[m, n] < IsolateValve: BBoxRemove[m, n] = 1 for m in range(binNumOfPower - TopP, binNumOfPower): for n in range(binNumOfWindSpeed): BBoxRemove[m, n] = 3 # 标记功率主带拐点左侧的欠发网格 for m in range(mm-1, binNumOfPower - TopP): for n in range(int(nn) - 2): BBoxRemove[m, n] = 2 return BBoxLimit def markData(binNumOfPower, binNumOfWindSpeed,DzMarch809,BBoxRemove,nCounter1): ''' 根据网格标识来标记数据点 参数: nCounter1 binNumOfPower: 功率分仓个数。 binNumOfWindSpeed:风速分仓个数 DzMarch809: array V P lab: 38181。 BBoxRemove:需剔除的网格 返回: DzMarch809Sel:数组现在包含了每个数据点的标识 ''' DzMarch809Sel = np.zeros(nCounter1, dtype=int) nWhichP = 0 nWhichV = 0 for i in range(nCounter1): for m in range( binNumOfPower ): if ((DzMarch809[i,1])> m * intervalPower) and ((DzMarch809[i,1]) <= (m+1) * intervalPower): nWhichP = m #m记录的是index break for n in range( binNumOfWindSpeed ): if DzMarch809[i,0] > ((n+1) * intervalWindspeed - intervalWindspeed/2) and DzMarch809[i,0] <= ((n+1) * intervalWindspeed + intervalWindspeed / 2): nWhichV = n break if nWhichP >= 0 and nWhichV >= 0: if BBoxRemove[nWhichP, nWhichV] == 1: DzMarch809Sel[i] = 1 elif BBoxRemove[nWhichP, nWhichV] == 2: DzMarch809Sel[i] = 2 elif BBoxRemove[nWhichP , nWhichV] == 3: DzMarch809Sel[i] = 0 return DzMarch809Sel def windowFilter(nCounter1,ratedPower,DzMarch809,DzMarch809Sel,Point_line): ''' 滑动窗口方法,进一步标记数据坏点 参数: nCounter1: ratedPower: Point_line: 返回: PVLimit: 限负荷数据 nLimitTotal: 是限负荷数据的总数 ''' PVLimit = np.zeros((nCounter1, 3)) nLimitTotal = 0 nWindowLength = 6 LimitWindow = np.zeros(nWindowLength) UpLimit = 0 LowLimit = 0 PowerStd = 30 nWindowNum = np.floor(nCounter1/nWindowLength) PowerLimitUp = ratedPower - 100 PowerLimitLow = 100 # 循环遍历每个窗口 for i in range(int(nWindowNum)): start_idx = i * nWindowLength end_idx = start_idx + nWindowLength LimitWindow = DzMarch809[start_idx:end_idx, 1] bAllInAreas = np.all(LimitWindow >= PowerLimitLow) and np.all(LimitWindow <= PowerLimitUp) if not bAllInAreas: continue UpLimit = LimitWindow[0] + PowerStd LowLimit = LimitWindow[0] - PowerStd bAllInUpLow = np.all(LimitWindow >= LowLimit) and np.all(LimitWindow <= UpLimit) if bAllInUpLow: DzMarch809Sel[start_idx:end_idx] = 4 for j in range(nWindowLength): PVLimit[nLimitTotal, :2] = DzMarch809[start_idx + j, :2] PVLimit[nLimitTotal, 2] = Point_line[start_idx + j] # 对数据进行标识 nLimitTotal += 1 return PVLimit,nLimitTotal def store_points(DzMarch809, DzMarch809Sel,Point_line, nCounter1): """ 存储好点,并返回存储好的点的数组和计数。 参数: DzMarch809: array:V P lab: 38181。 DzMarch809Sel: 数组现在包含了每个数据点的标识 Point_line: nCounter1: axis: 'good' or 'bad' 返回: PVDot: 数据 nCounterPV: 数据个数 """ PVDot = np.zeros((nCounter1, 3)) PVBad = np.zeros((nCounter1, 3)) nCounterPV = 0 nCounterBad = 0 for i in range(nCounter1): if DzMarch809Sel[i] == 0: nCounterPV += 1 PVDot[nCounterPV-1, :2] = DzMarch809[i, :2] PVDot[nCounterPV-1, 2] = Point_line[i] elif DzMarch809Sel[i] in [1, 2, 3]: nCounterBad += 1 PVBad[nCounterBad-1, :2] = DzMarch809[i, :2] PVBad[nCounterBad-1, 2] = Point_line[i] return PVDot, nCounterPV,PVBad,nCounterBad def markAllData(nCounterPV,nCounterBad,dataFramePartOfSCADA,PVDot,PVBad,SM,nLimitTotal,PVLimit): """ 标记好点、坏点、限电点。 参数: nCounterPV nCounterBad dataFramePartOfSCADA PVDot PVBad SM nLimitTotal PVLimit 返回: dataFramePartOfSCADA """ for i in range(nCounterPV): dataFramePartOfSCADA[int(PVDot[i, 2] - 1), (SM[1]-1)] = 1 #坏点 for i in range(nCounterBad): dataFramePartOfSCADA[int(PVBad[i, 2] - 1),(SM[1]-1)] = 5 # 坏点标识 # 对所有数据中的限电点进行标注 for i in range(nLimitTotal): dataFramePartOfSCADA[int(PVLimit[i, 2] - 1),(SM[1]-1)] = 4 # 限电点标识 return dataFramePartOfSCADA # 4. 数据可视化 def plot_data(ws:list, ap:list): fig = plt.figure() plt.scatter(ws, ap, s=1, c='black', marker='.') ax = plt.gca() ax.xaxis.set_major_locator(MultipleLocator(5)) ax.yaxis.set_major_locator(MultipleLocator(500)) plt.xlim((0, 30)) plt.ylim((0, 2200)) plt.tick_params(labelsize=8) plt.xlabel("V/(m$·$s$^{-1}$)", fontsize=8) plt.ylabel("P/kW", fontsize=8) plt.show() # 5. Main Execution def main(): turbine=85 basePath=r'E:\BaiduNetdiskDownload\test\min_scada_LuoTuoGou\72' filePathSCADA = r'{}\{}.csv'.format(basePath,turbine) filePathTurbineInfo = r'{}\info.csv'.format(basePath) outputFilePathOfSCADA=r"{}\labeled\labeled_{}.csv".format(basePath,turbine) dataFrameOfSCADA, turbineInfo = loadData(filePathSCADA, filePathTurbineInfo) ratedPower, windSpeedCutOut, windSpeedCutIn, ratedWindSpeed = extractTurbineParameters(turbineInfo) dataFramePartOfSCADA = preprocessData(dataFrameOfSCADA) powerMax=dataFramePartOfSCADA[fieldActivePower].max() binNumOfPower, binNumOfWindSpeed = calculateIntervals(powerMax,ratedPower,windSpeedCutOut) TopP = calculateTopP(powerMax,ratedPower) # 根据功率阈值对数据进行标签分配 DzMarch809,nCounter1,dataFramePartOfSCADA,Point_line,SM = chooseData(dataFramePartOfSCADA, dataFrameOfSCADA) XBoxNumber = gridCount(binNumOfWindSpeed,binNumOfPower,nCounter1,DzMarch809) PBoxPercent,PBinSum = percentageDots(XBoxNumber, binNumOfPower, binNumOfWindSpeed, 'power') VBoxPercent,VBinSum = percentageDots(XBoxNumber, binNumOfPower, binNumOfWindSpeed, 'speed') PBoxMaxIndex, PBoxMaxP = maxBoxPercentage(PBoxPercent, binNumOfPower, binNumOfWindSpeed, 'power') VBoxMaxIndex, VBoxMaxV = maxBoxPercentage(VBoxPercent, binNumOfPower, binNumOfWindSpeed, 'speed') if PBoxMaxIndex[0] > 14: PBoxMaxIndex[0] = 9 DotDenseLeftRight = extendBoxPercent(90, PBoxMaxP,TopP,PBoxMaxIndex,PBoxPercent,binNumOfPower,binNumOfWindSpeed) # pdb.set_trace() # 设置断点 WidthAverage, WidthAverage_L,PowerLimit = calculatePWidth(binNumOfPower,TopP,DotDenseLeftRight,PBinSum) PBoxMaxIndex = amendMaxBox(binNumOfPower,TopP,PowerLimit,PBoxMaxIndex) # 计算功率主带的左右边界 CurveWidthR = np.ceil(WidthAverage) + 2 CurveWidthL = np.ceil(WidthAverage_L) + 2 #确定功率主带的左上拐点,即额定风速位置的网格索引 CurveTop = np.zeros((2, 1), dtype=int) BTopFind = 0 for m in range(binNumOfPower - TopP, 0, -1): for n in range(int(np.floor(int(windSpeedCutIn) / intervalWindspeed)), binNumOfWindSpeed - 1): if (VBoxPercent[m, n - 1] < VBoxPercent[m, n]) and (VBoxPercent[m, n] <= VBoxPercent[m, n + 1]) and (XBoxNumber[m, n] >= 3): CurveTop[0] = m CurveTop[1] = n #[第80个,第40个] BTopFind = 1 mm = m nn = n break if BTopFind == 1: break #标记网格 BBoxRemove = markBoxLimit(binNumOfPower,binNumOfWindSpeed,TopP,CurveWidthR,CurveWidthL,PBoxMaxIndex) BBoxLimit = markBoxPLimit(binNumOfPower,binNumOfWindSpeed,TopP,CurveWidthR,PowerLimit,PBoxPercent,PBoxMaxIndex,mm,BBoxRemove,nn) DzMarch809Sel = markData(binNumOfPower, binNumOfWindSpeed,DzMarch809,BBoxRemove,nCounter1) PVLimit,nLimitTotal = windowFilter(nCounter1,ratedPower,DzMarch809,DzMarch809Sel,Point_line) #将功率滑动窗口主带平滑化 nSmooth = 0 for i in range(binNumOfPower - TopP - 1): PVLeftDown = np.zeros(2) PVRightUp = np.zeros(2) if PBoxMaxIndex[i + 1] - PBoxMaxIndex[i] >= 1: # 计算左下和右上顶点的坐标 PVLeftDown[0] = (PBoxMaxIndex[i]+1 + CurveWidthR) * 0.25 - 0.125 PVLeftDown[1] = (i) * 25 PVRightUp[0] = (PBoxMaxIndex[i+1]+1 + CurveWidthR) * 0.25 - 0.125 PVRightUp[1] = (i+1) * 25 for m in range(nCounter1): # 检查当前点是否在锯齿区域内 if (DzMarch809[m, 0] > PVLeftDown[0]) and (DzMarch809[m, 0] < PVRightUp[0]) and (DzMarch809[m, 1] > PVLeftDown[1]) and (DzMarch809[m, 1] < PVRightUp[1]): # 检查斜率是否大于对角连线 if (DzMarch809[m, 1] - PVLeftDown[1]) / (DzMarch809[m, 0] - PVLeftDown[0]) > (PVRightUp[1] - PVLeftDown[1]) / (PVRightUp[0] - PVLeftDown[0]): # 如果在锯齿左上三角形中,则选中并增加锯齿平滑计数器 DzMarch809Sel[m] = 0 nSmooth += 1 # DzMarch809Sel 数组现在包含了锯齿平滑的选择结果,nSmooth 是选中的点数 PVDot, nCounterPV,PVBad,nCounterBad = store_points(DzMarch809, DzMarch809Sel,Point_line, nCounter1) #标注 dataFramePartOfSCADA = markAllData(nCounterPV,nCounterBad,dataFramePartOfSCADA,PVDot,PVBad,SM,nLimitTotal,PVLimit) A = dataFramePartOfSCADA[:,3] A=pd.DataFrame(A,columns=['lab']) labeledData = pd.concat([dataFrameOfSCADA,A],axis=1) D = labeledData[labeledData['lab'].isin([-1,0,1,2,3,4,5])]#选择为1的行 labeledData.to_csv(outputFilePathOfSCADA,encoding='utf-8') plot_data(D[fieldWindSpeed], D[fieldActivePower]) if __name__ == '__main__': main()