|
@@ -1,756 +0,0 @@
|
|
|
-import numpy as np
|
|
|
-from pandas import DataFrame
|
|
|
-
|
|
|
-from service.plt_service import get_base_wind_and_power
|
|
|
-from utils.file.trans_methods import read_file_to_df
|
|
|
-
|
|
|
-
|
|
|
-class ClassIdentifier(object):
|
|
|
-
|
|
|
- def __init__(self, wind_turbine_number, file_path: str = None, origin_df: DataFrame = None, index='time_stamp',
|
|
|
- wind_velocity='wind_velocity',
|
|
|
- active_power='active_power'):
|
|
|
- """
|
|
|
- :param wind_turbine_number: The wind turbine number.
|
|
|
- :param file_path: The file path of the input data.
|
|
|
- :param origin_df: The pandas DataFrame containing the input data.
|
|
|
- :param index: 索引字段
|
|
|
- :param wind_velocity: 风速字段
|
|
|
- :param active_power: 有功功率字段
|
|
|
- """
|
|
|
- self.wind_turbine_number = wind_turbine_number
|
|
|
- self.index = index
|
|
|
- self.wind_velocity = wind_velocity
|
|
|
- self.active_power = active_power
|
|
|
-
|
|
|
- self.rated_wind_speed = 'rated_wind_speed'
|
|
|
- self.rated_capacity = 'rated_capacity'
|
|
|
-
|
|
|
- if file_path is None and origin_df is None:
|
|
|
- raise ValueError("Either file_path or origin_df should be provided.")
|
|
|
-
|
|
|
- if file_path:
|
|
|
- self.df = read_file_to_df(file_path)
|
|
|
- else:
|
|
|
- self.df = origin_df
|
|
|
-
|
|
|
- self.df = self.df.set_index(keys=self.index)
|
|
|
-
|
|
|
- def identifier(self):
|
|
|
- # 风速 和 有功功率 df
|
|
|
- wind_and_power_df = self.df[[self.wind_velocity, self.active_power]]
|
|
|
- wind_and_power_df.reset_index(inplace=True)
|
|
|
- wind_and_power_df_count = wind_and_power_df.shape[0]
|
|
|
- PowerMax = wind_and_power_df[self.active_power].max()
|
|
|
- PowerRated = np.ceil(PowerMax / 100) * 100
|
|
|
- PRated = 1500 # 额定功率1500kw,可改为2000kw
|
|
|
- VCutOut = 25
|
|
|
- VCutIn = 3
|
|
|
- VRated = 10
|
|
|
- # 网格法确定风速风向分区数量,功率方向分区数量,
|
|
|
- # PNum = (PRated+100)/25 #功率分区间隔25kW
|
|
|
- PNum = int(np.ceil(PowerRated / 25)) # 功率分区间隔25kW
|
|
|
- VNum = int(np.ceil(VCutOut / 0.25)) # 风速分区间隔0.25m/s
|
|
|
-
|
|
|
- # 实发电量
|
|
|
- EPActualTotal = 0 # 实发电量
|
|
|
- for i in range(wind_and_power_df_count):
|
|
|
- if wind_and_power_df.loc[i, self.active_power] >= 0:
|
|
|
- EPActualTotal = EPActualTotal + wind_and_power_df.loc[i, self.active_power] / 6
|
|
|
-
|
|
|
- print("EPActualTotal", EPActualTotal)
|
|
|
- # 平均风速
|
|
|
- WindSpeedAvr = 0
|
|
|
- WindSum = 0
|
|
|
- for i in range(wind_and_power_df_count):
|
|
|
- if wind_and_power_df.loc[i, self.wind_velocity] >= 0:
|
|
|
- WindSum = WindSum + wind_and_power_df.loc[i, self.wind_velocity]
|
|
|
- WindSpeedAvr = WindSum / wind_and_power_df_count
|
|
|
- print("windSpeedAvr", WindSpeedAvr)
|
|
|
- # 用于计算损失电量的标杆功率曲线,可更换为风机设计功率曲线
|
|
|
- # base_wind_and_power_df = get_base_wind_and_power(self.wind_turbine_number)
|
|
|
- base_wind_and_power_df = read_file_to_df(r"D:\中能智能\matlib计算相关\好点坏点matlib计算\A型风机设计功率曲线.csv", header=None)
|
|
|
- base_wind_and_power_df.columns = [self.rated_wind_speed, self.rated_capacity]
|
|
|
- if base_wind_and_power_df.empty:
|
|
|
- raise ValueError("风场编号:" + self.wind_turbine_number + "未查询到风速功率信息")
|
|
|
- base_wind_and_power_count = base_wind_and_power_df.shape[0]
|
|
|
-
|
|
|
- # 风机可利用率,计算方法:大于切入风速但发电功率小于0
|
|
|
- TurbineRunRate = 0
|
|
|
- nShouldGP = 0
|
|
|
- nRealGP = 0
|
|
|
- for i in range(wind_and_power_df_count):
|
|
|
- if wind_and_power_df.loc[i, self.wind_velocity] >= VCutIn:
|
|
|
- nShouldGP = nShouldGP + 1
|
|
|
- if wind_and_power_df.loc[i, self.active_power] > 0:
|
|
|
- nRealGP = nRealGP + 1
|
|
|
- if nShouldGP > 0:
|
|
|
- TurbineRunRate = nRealGP / nShouldGP * 100
|
|
|
-
|
|
|
- print("disp(TurbineRunRate)", TurbineRunRate)
|
|
|
- # 理论电量-
|
|
|
- EPIdealTotalAAA = 0 # 理论电量-
|
|
|
- nWhichBin = 0
|
|
|
- IdealPower = 0
|
|
|
- for i in range(wind_and_power_df_count):
|
|
|
- # 应发电量-理论
|
|
|
- nWhichBin = 0
|
|
|
- for m in range(base_wind_and_power_count - 1):
|
|
|
- if base_wind_and_power_df.loc[m, self.rated_wind_speed] < wind_and_power_df.loc[
|
|
|
- i, self.wind_velocity] <= \
|
|
|
- base_wind_and_power_df.loc[m + 1, self.rated_wind_speed]:
|
|
|
- nWhichBin = m
|
|
|
- break
|
|
|
-
|
|
|
- # 插值计算对应设计功率
|
|
|
- if nWhichBin > base_wind_and_power_count - 1 or nWhichBin == 0:
|
|
|
- continue
|
|
|
-
|
|
|
- IdealPower = (wind_and_power_df.loc[i, self.wind_velocity] - base_wind_and_power_df.loc[nWhichBin,
|
|
|
- self.rated_wind_speed]) / (
|
|
|
- base_wind_and_power_df.loc[nWhichBin + 1, self.rated_wind_speed] -
|
|
|
- base_wind_and_power_df.loc[nWhichBin, self.rated_wind_speed]) * (
|
|
|
- base_wind_and_power_df.loc[nWhichBin + 1, self.rated_capacity] -
|
|
|
- base_wind_and_power_df.loc[nWhichBin, self.rated_capacity]) \
|
|
|
- + base_wind_and_power_df.loc[nWhichBin, self.rated_capacity]
|
|
|
- EPIdealTotalAAA = EPIdealTotalAAA + IdealPower / 6
|
|
|
-
|
|
|
- print('EPIdealTotalAAA', EPIdealTotalAAA)
|
|
|
- #
|
|
|
- # 存储功率大于零的运行数据
|
|
|
- DzMarch809 = np.zeros([wind_and_power_df_count, 2], dtype=float)
|
|
|
- nCounter1 = 0
|
|
|
- for i in range(wind_and_power_df_count):
|
|
|
- if wind_and_power_df.loc[i, self.active_power] > 0:
|
|
|
- DzMarch809[nCounter1, 0] = wind_and_power_df.loc[i, self.wind_velocity]
|
|
|
- DzMarch809[nCounter1, 1] = wind_and_power_df.loc[i, self.active_power]
|
|
|
-
|
|
|
- nCounter1 = nCounter1 + 1
|
|
|
-
|
|
|
- print('nCounter1', nCounter1)
|
|
|
-
|
|
|
- # 统计各网格落入的散点个数
|
|
|
- XBoxNumber = np.ones([PNum, VNum], dtype=int)
|
|
|
- nWhichP = -1
|
|
|
- nWhichV = -1
|
|
|
- for i in range(nCounter1):
|
|
|
- for m in range(PNum):
|
|
|
- if m * 25 < DzMarch809[i, 1] <= (m + 1) * 25:
|
|
|
- nWhichP = m
|
|
|
- break
|
|
|
- for n in range(VNum):
|
|
|
- if ((n + 1) * 0.25 - 0.125) < DzMarch809[i, 0] <= ((n + 1) * 0.25 + 0.125):
|
|
|
- nWhichV = n
|
|
|
- break
|
|
|
-
|
|
|
- if nWhichP > -1 and nWhichV > -1:
|
|
|
- XBoxNumber[nWhichP, nWhichV] = XBoxNumber[nWhichP, nWhichV] + 1
|
|
|
-
|
|
|
- for m in range(PNum):
|
|
|
- for n in range(VNum):
|
|
|
- XBoxNumber[m, n] = XBoxNumber[m, n] - 1
|
|
|
-
|
|
|
- print('XBoxNumber', XBoxNumber)
|
|
|
- # 在功率方向将网格内散点绝对个数转换为相对百分比,备用
|
|
|
- PBoxPercent = np.zeros([PNum, VNum], dtype=float)
|
|
|
- PBinSum = np.zeros(PNum, dtype=int)
|
|
|
-
|
|
|
- for i in range(PNum):
|
|
|
- for m in range(VNum):
|
|
|
- PBinSum[i] = PBinSum[i] + XBoxNumber[i, m]
|
|
|
-
|
|
|
- for m in range(VNum):
|
|
|
- if PBinSum[i] > 0:
|
|
|
- PBoxPercent[i, m] = XBoxNumber[i, m] / PBinSum[i] * 100
|
|
|
-
|
|
|
- # 在风速方向将网格内散点绝对个数转换为相对百分比,备用
|
|
|
- VBoxPercent = np.zeros([PNum, VNum], dtype=float)
|
|
|
- VBinSum = np.zeros(VNum, dtype=int)
|
|
|
-
|
|
|
- for i in range(VNum):
|
|
|
- for m in range(PNum):
|
|
|
- VBinSum[i] = VBinSum[i] + XBoxNumber[m, i]
|
|
|
-
|
|
|
- for m in range(PNum):
|
|
|
- if VBinSum[i] > 0:
|
|
|
- VBoxPercent[m, i] = XBoxNumber[m, i] / VBinSum[i] * 100
|
|
|
-
|
|
|
- # 以水平功率带方向为准,分析每个水平功率带中,功率主带中心,即找百分比最大的网格位置。
|
|
|
- PBoxMaxIndex = np.zeros(PNum, dtype=int) # 水平功率带最大网格位置索引
|
|
|
- PBoxMaxP = np.zeros(PNum, dtype=int) # 水平功率带最大网格百分比
|
|
|
-
|
|
|
- for m in range(PNum):
|
|
|
- # 确定每一水平功率带的最大网格位置索引即百分比值
|
|
|
- PBoxMaxP[m], PBoxMaxIndex[m] = PBoxPercent[m, :].max(), PBoxPercent[m, :].argmax()
|
|
|
-
|
|
|
- # 以垂直风速方向为准,分析每个垂直风速带中,功率主带中心,即找百分比最大的网格位置。
|
|
|
- VBoxMaxIndex = np.zeros(VNum, dtype=int)
|
|
|
- VBoxMaxV = np.zeros(VNum, dtype=int)
|
|
|
-
|
|
|
- for m in range(VNum):
|
|
|
- [VBoxMaxV[m], VBoxMaxIndex[m]] = VBoxPercent[:, m].max(), VBoxPercent[:, m].argmax()
|
|
|
-
|
|
|
- # 切入风速特殊处理,如果切入风速过于偏右,向左拉回
|
|
|
- if PBoxMaxIndex[0] > 14:
|
|
|
- PBoxMaxIndex[0] = 9
|
|
|
-
|
|
|
- # 以水平功率带方向为基准,进行分析
|
|
|
- DotDense = np.zeros(PNum, dtype=int) # 每一水平功率带的功率主带包含的网格数
|
|
|
- DotDenseLeftRight = np.zeros([PNum, 2], dtype=int) # 存储每一水平功率带的功率主带以最大网格为中心,向向左,向右扩展的网格数
|
|
|
- DotValve = 90 # 从中心向左右对称扩展网格的散点百分比和的阈值。
|
|
|
- PDotDenseSum = 0
|
|
|
-
|
|
|
- iSpreadLeft = 1 # 向左扩展网格计数,初值为1
|
|
|
- iSpreadRight = 1 # 向右扩展网格技术,初值为1
|
|
|
- for i in range(PNum - 6): # 从最下层水平功率带1开始,向上到第PNum-6个水平功率带(额定功率一下水平功率带),逐一分析
|
|
|
- PDotDenseSum = PBoxMaxP[i] # 以中心最大水平功率带为基准,向左向右对称扩展网格,累加各网格散点百分比
|
|
|
- iSpreadRight = 1
|
|
|
- iSpreadLeft = 1
|
|
|
- while PDotDenseSum < DotValve:
|
|
|
-
|
|
|
- if (PBoxMaxIndex[i] + iSpreadRight) < VNum - 1:
|
|
|
- PDotDenseSum = PDotDenseSum + PBoxPercent[i, PBoxMaxIndex[i] + iSpreadRight] # 向右侧扩展
|
|
|
- iSpreadRight = iSpreadRight + 1
|
|
|
-
|
|
|
- if (PBoxMaxIndex[i] + iSpreadRight) > VNum - 1:
|
|
|
- break
|
|
|
-
|
|
|
- if (PBoxMaxIndex[i] - iSpreadLeft) > 0:
|
|
|
- PDotDenseSum = PDotDenseSum + PBoxPercent[i, PBoxMaxIndex[i] - iSpreadLeft] # 向左侧扩展
|
|
|
- iSpreadLeft = iSpreadLeft + 1
|
|
|
-
|
|
|
- if (PBoxMaxIndex[i] - iSpreadLeft) <= 0:
|
|
|
- break
|
|
|
-
|
|
|
- iSpreadRight = iSpreadRight - 1
|
|
|
-
|
|
|
- iSpreadLeft = iSpreadLeft - 1
|
|
|
- # 向左右对称扩展完毕
|
|
|
-
|
|
|
- DotDenseLeftRight[i, 0] = iSpreadLeft
|
|
|
- DotDenseLeftRight[i, 1] = iSpreadRight
|
|
|
- DotDense[i] = iSpreadLeft + iSpreadRight + 1
|
|
|
-
|
|
|
- # 各行功率主带右侧宽度的中位数最具有代表性
|
|
|
- DotDenseWidthLeft = np.zeros([PNum - 6, 1], dtype=int)
|
|
|
- for i in range(PNum - 6):
|
|
|
- DotDenseWidthLeft[i] = DotDenseLeftRight[i, 1]
|
|
|
-
|
|
|
- MainBandRight = np.median(DotDenseWidthLeft)
|
|
|
-
|
|
|
- # 散点向右显著延展分布的水平功率带为限功率水平带
|
|
|
- PowerLimit = np.zeros([PNum, 1], dtype=int) # 各水平功率带是否为限功率标识,==1:是;==0:不是
|
|
|
- WidthAverage = 0 # 功率主带平均宽度
|
|
|
- WidthVar = 0 # 功率主带方差
|
|
|
- # PowerLimitValve = 6 #限功率主带判别阈值
|
|
|
- PowerLimitValve = np.ceil(MainBandRight) + 3 # 限功率主带判别阈值
|
|
|
-
|
|
|
- nCounterLimit = 0
|
|
|
- nCounter = 0
|
|
|
-
|
|
|
- for i in range(PNum - 6):
|
|
|
- if DotDenseLeftRight[i, 1] > PowerLimitValve and PBinSum[i] > 20: # 如果向右扩展网格数大于阈值,且该水平功率带点总数>20,是
|
|
|
- PowerLimit[i] = 1
|
|
|
- nCounterLimit = nCounterLimit + 1
|
|
|
-
|
|
|
- if DotDenseLeftRight[i, 1] <= PowerLimitValve:
|
|
|
- WidthAverage = WidthAverage + DotDenseLeftRight[i, 1] # 统计正常水平功率带右侧宽度
|
|
|
- nCounter = nCounter + 1
|
|
|
-
|
|
|
- WidthAverage = WidthAverage / nCounter # 功率主带平均宽度
|
|
|
-
|
|
|
- print("WidthAverage", WidthAverage)
|
|
|
-
|
|
|
- # 各水平功率带的功率主带宽度的方差,反映从下到上宽度是否一致,或是否下宽上窄等异常情况
|
|
|
- for i in range(PNum - 6):
|
|
|
- if DotDenseLeftRight[i, 1] <= PowerLimitValve:
|
|
|
- WidthVar = WidthVar + (DotDenseLeftRight[i, 1] - WidthAverage) * (
|
|
|
- DotDenseLeftRight[i, 1] - WidthAverage)
|
|
|
-
|
|
|
- WidthVar = np.sqrt(WidthVar / nCounter)
|
|
|
-
|
|
|
- # 各水平功率带,功率主带的风速范围,右侧扩展网格数*2*0.25
|
|
|
- PowerBandWidth = WidthAverage * 2 * 0.25
|
|
|
-
|
|
|
- # 对限负荷水平功率带的最大网格较下面相邻层显著偏右,拉回
|
|
|
- for i in range(1, PNum - 6):
|
|
|
- if PowerLimit[i] == 1 and abs(PBoxMaxIndex[i] - PBoxMaxIndex[i - 1]) > 5:
|
|
|
- PBoxMaxIndex[i] = PBoxMaxIndex[i - 1] + 1
|
|
|
-
|
|
|
- # 输出各层功率主带的左右边界网格索引
|
|
|
- DotDenseInverse = np.zeros([PNum, 2], dtype=int)
|
|
|
-
|
|
|
- for i in range(PNum):
|
|
|
- DotDenseInverse[i, :] = DotDenseLeftRight[PNum - i - 1, :]
|
|
|
-
|
|
|
- # print('DotDenseInverse', DotDenseInverse)
|
|
|
-
|
|
|
- # 功率主带的右边界
|
|
|
- CurveWidthR = int(np.ceil(WidthAverage) + 2)
|
|
|
-
|
|
|
- # CurveWidthL = 6 #功率主带的左边界
|
|
|
- CurveWidthL = CurveWidthR
|
|
|
-
|
|
|
- BBoxLimit = np.zeros([PNum, VNum], dtype=int) # 网格是否为限功率网格的标识,如果为限功率水平功率带,从功率主带右侧边缘向右的网格为限功率网格
|
|
|
- for i in range(2, PNum - 6):
|
|
|
- if PowerLimit[i] == 1:
|
|
|
- for j in range(PBoxMaxIndex[i] + CurveWidthR, VNum):
|
|
|
- BBoxLimit[i, j] = 1
|
|
|
-
|
|
|
- BBoxRemove = np.zeros([PNum, VNum], dtype=int) # 数据异常需要剔除的网格标识,标识==1:功率主带右侧的欠发网格;==2:功率主带左侧的超发网格
|
|
|
- for m in range(PNum - 6):
|
|
|
- for n in range(PBoxMaxIndex[m] + CurveWidthR - 1, VNum):
|
|
|
- BBoxRemove[m, n] = 1
|
|
|
-
|
|
|
- for n in range(PBoxMaxIndex[m] - CurveWidthL - 1, 0, -1):
|
|
|
- BBoxRemove[m, n] = 2
|
|
|
-
|
|
|
- # 确定功率主带的左上拐点,即额定风速位置的网格索引
|
|
|
- CurveTop = np.zeros(2, dtype=int)
|
|
|
- CurveTopValve = 3 # 网格的百分比阈值
|
|
|
- BTopFind = 0
|
|
|
- for m in range(PNum - 4 - 1, 0, -1):
|
|
|
- for n in range(VNum):
|
|
|
- if VBoxPercent[m, n] > CurveTopValve and XBoxNumber[m, n] >= 10: # 如左上角网格的百分比和散点个数大于阈值。
|
|
|
- CurveTop[0] = m
|
|
|
- CurveTop[1] = n
|
|
|
- BTopFind = 1
|
|
|
- break
|
|
|
-
|
|
|
- if BTopFind == 1:
|
|
|
- break
|
|
|
-
|
|
|
- IsolateValve = 3
|
|
|
- for m in range(PNum - 6):
|
|
|
- for n in range(PBoxMaxIndex[m] + CurveWidthR - 1, VNum):
|
|
|
- if PBoxPercent[m, n] < IsolateValve:
|
|
|
- BBoxRemove[m, n] = 1
|
|
|
-
|
|
|
- # 功率主带顶部宽度
|
|
|
- CurveWidthT = 2
|
|
|
- for m in range(PNum - CurveWidthT - 1, PNum):
|
|
|
- for n in range(VNum):
|
|
|
- BBoxRemove[m, n] = 3 # 网格为额定功率以上的超发点
|
|
|
-
|
|
|
- # 功率主带拐点左侧的欠发网格标识
|
|
|
- for m in range(PNum - 5 - 1, PNum):
|
|
|
- for n in range(CurveTop[1] - 2 - 1):
|
|
|
- BBoxRemove[m, n] = 2
|
|
|
-
|
|
|
- # 以网格的标识,决定该网格内数据的标识。Dzwind_and_power_dfSel功率非零数据的标识位。散点在哪个网格,此网格的标识即为该点的标识
|
|
|
- Dzwind_and_power_dfSel = np.zeros(nCounter1, dtype=int) # is ==1,欠发功率点;==2,超发功率点;==3,额定风速以上的超发功率点 ==4, 限电
|
|
|
- nWhichP = 0
|
|
|
- nWhichV = 0
|
|
|
- nBadA = 0
|
|
|
-
|
|
|
- for i in range(nCounter1):
|
|
|
- for m in range(PNum):
|
|
|
- if DzMarch809[i, 1] > (m - 1) * 25 and DzMarch809[i, 1] <= m * 25:
|
|
|
- nWhichP = m
|
|
|
- break
|
|
|
-
|
|
|
- for n in range(VNum):
|
|
|
- if DzMarch809[i, 0] > (n * 0.25 - 0.125) and DzMarch809[i, 0] <= (n * 0.25 + 0.125):
|
|
|
- nWhichV = n
|
|
|
- break
|
|
|
-
|
|
|
- if nWhichP > 0 and nWhichV > 0:
|
|
|
-
|
|
|
- if BBoxRemove[nWhichP, nWhichV] == 1:
|
|
|
- Dzwind_and_power_dfSel[i] = 1
|
|
|
- nBadA = nBadA + 1
|
|
|
-
|
|
|
- if BBoxRemove[nWhichP, nWhichV] == 2:
|
|
|
- Dzwind_and_power_dfSel[i] = 2
|
|
|
-
|
|
|
- if BBoxRemove[nWhichP, nWhichV] == 3:
|
|
|
- Dzwind_and_power_dfSel[i] = 0 # 3 # 额定风速以上的超发功率点认为是正常点,不再标识。
|
|
|
-
|
|
|
- if BBoxLimit[nWhichP, nWhichV] == 1 and nWhichP>16:
|
|
|
- Dzwind_and_power_dfSel[i] = 4
|
|
|
-
|
|
|
- print("nWhichP", nWhichP)
|
|
|
- print("nWhichV", nWhichV)
|
|
|
- print("nBadA", nBadA)
|
|
|
-
|
|
|
- # 限负荷数据标识方法2:把数据切割为若干个窗口。对每一窗口,以第一个点为基准,连续nWindowLength个数据的功率在方差范围内,呈现显著水平分布的点
|
|
|
- PVLimit = np.zeros([nCounter1, 2], dtype=int) # 存储限负荷数据
|
|
|
- nLimitTotal = 0
|
|
|
- nWindowLength = 3
|
|
|
- LimitWindow = np.zeros(nWindowLength, dtype=int)
|
|
|
- UpLimit = 0 # 上限
|
|
|
- LowLimit = 0 # 下限
|
|
|
- PowerStd = 15 # 功率波动方差
|
|
|
- bAllInUpLow = 1 # ==1:窗口内所有数据均在方差上下限之内,限负荷==0,不满足条件
|
|
|
- bAllInAreas = 1 # ==1:窗口所有数据均在200~PRated-300kW范围内;==0:不满足此条件
|
|
|
- nWindowNum = int(np.floor(nCounter1 / nWindowLength))
|
|
|
- PowerLimitUp = PRated - 300
|
|
|
- PowerLimitLow = 200
|
|
|
- for i in range(nWindowNum):
|
|
|
- for j in range(nWindowLength):
|
|
|
- LimitWindow[j] = DzMarch809[i * nWindowLength + j, 1]
|
|
|
-
|
|
|
- bAllInAreas = 1
|
|
|
- for j in range(nWindowLength):
|
|
|
- if LimitWindow[j] < PowerLimitLow or LimitWindow[j] > PowerLimitUp:
|
|
|
- bAllInAreas = 0
|
|
|
-
|
|
|
- if bAllInAreas == 0:
|
|
|
- continue
|
|
|
-
|
|
|
- UpLimit = LimitWindow[0] + PowerStd
|
|
|
- LowLimit = LimitWindow[0] - PowerStd
|
|
|
- bAllInUpLow = 1
|
|
|
- for j in range(1, nWindowLength):
|
|
|
- if LimitWindow[j] < LowLimit or LimitWindow[j] > UpLimit:
|
|
|
- bAllInUpLow = 0
|
|
|
-
|
|
|
- if bAllInUpLow == 1:
|
|
|
- for j in range(nWindowLength):
|
|
|
- Dzwind_and_power_dfSel[i * nWindowLength + j] = 4 # 标识窗口内的数据为限负荷数据
|
|
|
-
|
|
|
- for j in range(nWindowLength):
|
|
|
- PVLimit[nLimitTotal, :] = DzMarch809[i * nWindowLength + j, :]
|
|
|
- nLimitTotal = nLimitTotal + 1
|
|
|
-
|
|
|
- print("nLimitTotal", nLimitTotal)
|
|
|
-
|
|
|
- # 相邻水平功率主带的锯齿平滑
|
|
|
- PVLeftDown = np.zeros(2, dtype=int)
|
|
|
- PVRightUp = np.zeros(2, dtype=int)
|
|
|
- nSmooth = 0
|
|
|
- for i in range(PNum - 6 - 1):
|
|
|
- PVLeftDown = np.zeros(2, dtype=int)
|
|
|
- PVRightUp = np.zeros(2, dtype=int)
|
|
|
-
|
|
|
- if (PBoxMaxIndex[i + 1] - PBoxMaxIndex[i]) >= 1:
|
|
|
- PVLeftDown[0] = (PBoxMaxIndex[i] + CurveWidthR) * 0.25 - 0.125
|
|
|
- PVLeftDown[1] = (i - 1) * 25
|
|
|
-
|
|
|
- PVRightUp[0] = (PBoxMaxIndex[i + 1] + CurveWidthR) * 0.25 - 0.125
|
|
|
- PVRightUp[1] = (i + 1 - 1) * 25
|
|
|
-
|
|
|
- for m in range(nCounter1):
|
|
|
- if DzMarch809[m, 0] > PVLeftDown[0] and DzMarch809[m, 0] < PVRightUp[0] and PVLeftDown[1] < \
|
|
|
- DzMarch809[m, 1] < PVRightUp[1]: # 在该锯齿中
|
|
|
- if (DzMarch809[m, 1] - PVLeftDown[1]) / (DzMarch809[m, 0] - PVLeftDown[0]) > (
|
|
|
- PVRightUp[1] - PVLeftDown[1]) / (
|
|
|
- PVRightUp[0] - PVLeftDown[0]): # 斜率大于对角连线,则在锯齿左上三角形中,选中
|
|
|
- Dzwind_and_power_dfSel[m] = 0
|
|
|
- nSmooth = nSmooth + 1
|
|
|
-
|
|
|
- print("nSmooth", nSmooth)
|
|
|
-
|
|
|
- # 存储好点
|
|
|
- nCounterPV = 0
|
|
|
- PVDot = np.zeros([nCounter1, 2], dtype=int)
|
|
|
- for i in range(nCounter1):
|
|
|
- if Dzwind_and_power_dfSel[i] == 0:
|
|
|
- PVDot[nCounterPV, :] = DzMarch809[i, :]
|
|
|
- nCounterPV = nCounterPV + 1
|
|
|
-
|
|
|
- nCounterVP = nCounterPV
|
|
|
- print("nCounterVP", nCounterVP)
|
|
|
-
|
|
|
- # 存储坏点
|
|
|
- nCounterBad = 0
|
|
|
- PVBad = np.zeros([nCounter1, 2], dtype=int)
|
|
|
- for i in range(nCounter1):
|
|
|
- if Dzwind_and_power_dfSel[i] == 1 or Dzwind_and_power_dfSel[i] == 2 or Dzwind_and_power_dfSel[i] == 3:
|
|
|
- PVBad[nCounterBad, :] = DzMarch809[i, :]
|
|
|
- nCounterBad = nCounterBad + 1
|
|
|
-
|
|
|
- print("nCounterBad", nCounterBad)
|
|
|
-
|
|
|
- # 用功率主带中的好点绘制实测功率曲
|
|
|
- XBinNumber = np.ones(50, dtype=int)
|
|
|
- PCurve = np.zeros([50, 2], dtype=int)
|
|
|
- PCurve[:, 0] = [i / 2 for i in range(1, 51)]
|
|
|
- XBinSum = np.zeros([50, 2], dtype=int)
|
|
|
- nWhichBin = 0
|
|
|
-
|
|
|
- for i in range(nCounterVP):
|
|
|
- nWhichBin = 0
|
|
|
-
|
|
|
- for b in range(50):
|
|
|
- if PVDot[i, 0] > (b * 0.5 - 0.25) and PVDot[i, 0] <= (b * 0.5 + 0.25):
|
|
|
- nWhichBin = b
|
|
|
- break
|
|
|
-
|
|
|
- if nWhichBin > 0:
|
|
|
- XBinSum[nWhichBin, 0] = XBinSum[nWhichBin, 0] + PVDot[i, 0] # wind speed
|
|
|
- XBinSum[nWhichBin, 1] = XBinSum[nWhichBin, 1] + PVDot[i, 1] # Power
|
|
|
- XBinNumber[nWhichBin] = XBinNumber[nWhichBin] + 1
|
|
|
-
|
|
|
- for b in range(50):
|
|
|
- XBinNumber[b] = XBinNumber[b] - 1
|
|
|
-
|
|
|
- for b in range(50):
|
|
|
- if XBinNumber[b] > 0:
|
|
|
- PCurve[b, 0] = XBinSum[b, 0] / XBinNumber[b]
|
|
|
- PCurve[b, 1] = XBinSum[b, 1] / XBinNumber[b]
|
|
|
-
|
|
|
- # 对额定风速以上的功率直接赋额定功率
|
|
|
- VRatedNum = int(VRated / 0.5)
|
|
|
- for m in range(VRatedNum, 50):
|
|
|
- if PCurve[m, 1] == 0:
|
|
|
- PCurve[m, 1] = PRated
|
|
|
-
|
|
|
- # print("PCurve", PCurve)
|
|
|
-
|
|
|
- # 绘制标准正则功率曲线,以0.5m/s标准为间隔
|
|
|
- # 15m/s以上为额定功率,15m/s以下为计算得到
|
|
|
- PCurveNorm = np.zeros([50, 2], dtype=int)
|
|
|
- for i in range(30, 50):
|
|
|
- PCurveNorm[i, 0] = i * 0.5
|
|
|
- PCurveNorm[i, 1] = PRated
|
|
|
-
|
|
|
- # 15m/s一下正则功率曲线
|
|
|
- CurveData = np.zeros([30, 2], dtype=int)
|
|
|
- for i in range(30):
|
|
|
- CurveData[i, :] = PCurve[i, :]
|
|
|
-
|
|
|
- CurveNorm = np.zeros([30, 2], dtype=int)
|
|
|
- VSpeed = [i / 2 for i in range(1, 31)]
|
|
|
-
|
|
|
- WhichBin = 0
|
|
|
-
|
|
|
- K = 0
|
|
|
- a = 0
|
|
|
- for m in range(30):
|
|
|
- K = 0
|
|
|
- a = 0
|
|
|
-
|
|
|
- for n in range(30):
|
|
|
- if abs(CurveData[n, 0] - VSpeed[m]) < 0.1:
|
|
|
- WhichBin = n
|
|
|
- break
|
|
|
-
|
|
|
- if WhichBin > 1:
|
|
|
- if CurveData[WhichBin, 0] - CurveData[WhichBin - 1, 0] > 0:
|
|
|
- K = (CurveData[WhichBin, 1] - CurveData[WhichBin - 1, 1]) / (
|
|
|
- CurveData[WhichBin, 0] - CurveData[WhichBin - 1, 0])
|
|
|
- a = CurveData[WhichBin, 1] - K * CurveData[WhichBin, 0]
|
|
|
-
|
|
|
- CurveNorm[m, 0] = VSpeed[m]
|
|
|
- CurveNorm[m, 1] = a + K * VSpeed[m]
|
|
|
-
|
|
|
- for i in range(30):
|
|
|
- PCurveNorm[i, :] = CurveNorm[i, :]
|
|
|
-
|
|
|
- # 子模块3:损失电量计算及发电性能评价
|
|
|
- CC = len(PCurve[:, 0])
|
|
|
- EPIdealTotal = 0
|
|
|
- # 计算停机损失
|
|
|
- EPLostStopTotal = 0
|
|
|
- EPLost = 0
|
|
|
-
|
|
|
- nWhichBin = 0
|
|
|
- IdealPower = 0
|
|
|
- nStopTotal = 0
|
|
|
- for i in range(wind_and_power_df_count):
|
|
|
- if wind_and_power_df.loc[i, self.active_power] <= 0:
|
|
|
- nWhichBin = 0
|
|
|
- for m in range(base_wind_and_power_count - 1):
|
|
|
- if wind_and_power_df.loc[i, self.wind_velocity] > base_wind_and_power_df.loc[
|
|
|
- m, self.rated_wind_speed] and wind_and_power_df.loc[i, self.wind_velocity] <= \
|
|
|
- base_wind_and_power_df.loc[
|
|
|
- m + 1, self.rated_wind_speed]:
|
|
|
- nWhichBin = m
|
|
|
- break
|
|
|
-
|
|
|
- if nWhichBin > base_wind_and_power_count - 1 or nWhichBin == 0:
|
|
|
- continue
|
|
|
-
|
|
|
- IdealPower = (wind_and_power_df.loc[i, self.wind_velocity] - base_wind_and_power_df.loc[
|
|
|
- nWhichBin, self.rated_wind_speed]) / (
|
|
|
- base_wind_and_power_df.loc[nWhichBin + 1, self.rated_wind_speed] -
|
|
|
- base_wind_and_power_df.loc[
|
|
|
- nWhichBin, self.rated_wind_speed]) * (
|
|
|
- base_wind_and_power_df.loc[nWhichBin + 1, self.rated_capacity]
|
|
|
- - base_wind_and_power_df.loc[nWhichBin, self.rated_capacity]) \
|
|
|
- + base_wind_and_power_df.loc[nWhichBin, self.rated_capacity]
|
|
|
-
|
|
|
- EPLost = IdealPower / 6
|
|
|
- EPLostStopTotal = EPLostStopTotal + EPLost
|
|
|
- nStopTotal = nStopTotal + 1
|
|
|
-
|
|
|
- print("EPLost", EPLost)
|
|
|
- print("nStopTotal", nStopTotal)
|
|
|
- print("EPLostStopTotal", EPLostStopTotal)
|
|
|
-
|
|
|
- nWhichP = 0
|
|
|
- nWhichV = 0
|
|
|
- nWhichBin = 0
|
|
|
- IdealPower = 0
|
|
|
-
|
|
|
- # 计算欠发损失,此欠发损失已不包括限电损失,限电点在前面已经从欠发点中去除。
|
|
|
- EPLostBadTotal = 0
|
|
|
- EPLost = 0
|
|
|
-
|
|
|
- nBadTotal = 0
|
|
|
-
|
|
|
- LostBadPercent = 0
|
|
|
-
|
|
|
- EPOverTotal = 0
|
|
|
- EPOver = 0
|
|
|
- nOverTotal = 0
|
|
|
-
|
|
|
- for i in range(nCounter1):
|
|
|
- if Dzwind_and_power_dfSel[i] == 1:
|
|
|
- nWhichBin = 0
|
|
|
- for m in range(base_wind_and_power_count - 1):
|
|
|
- if DzMarch809[i, 0] > base_wind_and_power_df.loc[m, self.rated_wind_speed] \
|
|
|
- and DzMarch809[i, 0] <= base_wind_and_power_df.loc[m + 1, self.rated_wind_speed]:
|
|
|
- nWhichBin = m
|
|
|
- break
|
|
|
-
|
|
|
- if nWhichBin > base_wind_and_power_count - 1 or nWhichBin == 0:
|
|
|
- continue
|
|
|
-
|
|
|
- IdealPower = (DzMarch809[i, 0] - base_wind_and_power_df.loc[nWhichBin, self.rated_wind_speed]) / (
|
|
|
- base_wind_and_power_df.loc[nWhichBin + 1, self.rated_wind_speed] - base_wind_and_power_df.loc[
|
|
|
- nWhichBin, self.rated_wind_speed]) * (
|
|
|
- base_wind_and_power_df.loc[nWhichBin + 1, self.rated_capacity] -
|
|
|
- base_wind_and_power_df.loc[nWhichBin, self.rated_capacity]) + \
|
|
|
- base_wind_and_power_df.loc[nWhichBin, self.rated_capacity]
|
|
|
- EPLost = abs(IdealPower - DzMarch809[i, 1]) / 6
|
|
|
- EPLostBadTotal = EPLostBadTotal + EPLost
|
|
|
- nBadTotal = nBadTotal + 1
|
|
|
-
|
|
|
- # 额定风速以上超发电量
|
|
|
- if Dzwind_and_power_dfSel[i] == 3:
|
|
|
- EPOver = (DzMarch809[i, 1] - PRated) / 6
|
|
|
- EPOverTotal = EPOverTotal + EPOver
|
|
|
- nOverTotal = nOverTotal + 1
|
|
|
-
|
|
|
- print("EPLost", EPLost)
|
|
|
- print("nBadTotal", nBadTotal)
|
|
|
- print("EPLostBadTotal", EPLostBadTotal)
|
|
|
- print("EPOverTotal", EPOverTotal)
|
|
|
- print("nOverTotal", nOverTotal)
|
|
|
-
|
|
|
- # 功率曲线未达标损失
|
|
|
- EPLostPerformTotal = 0
|
|
|
- nWhichBinI = 0
|
|
|
- IdealPower = 0
|
|
|
-
|
|
|
- for i in range(nCounterVP):
|
|
|
-
|
|
|
- for m in range(base_wind_and_power_count - 1):
|
|
|
- if PVDot[i, 0] > base_wind_and_power_df.loc[m, self.rated_wind_speed] and PVDot[i, 0] <= \
|
|
|
- base_wind_and_power_df.loc[m + 1, self.rated_wind_speed]:
|
|
|
- nWhichBinI = m
|
|
|
- break
|
|
|
-
|
|
|
- if nWhichBinI > base_wind_and_power_count - 1 or nWhichBinI == 0:
|
|
|
- continue
|
|
|
-
|
|
|
- IdealPower = (PVDot[i, 0] - base_wind_and_power_df.loc[nWhichBinI, self.rated_wind_speed]) / (
|
|
|
- base_wind_and_power_df.loc[nWhichBinI + 1, self.rated_wind_speed] - base_wind_and_power_df.loc[
|
|
|
- nWhichBinI, self.rated_wind_speed]) * \
|
|
|
- (base_wind_and_power_df.loc[nWhichBinI + 1, self.rated_capacity] -
|
|
|
- base_wind_and_power_df.loc[nWhichBinI, self.rated_capacity]) + \
|
|
|
- base_wind_and_power_df.loc[nWhichBinI, self.rated_capacity]
|
|
|
-
|
|
|
- EPLostPerformTotal = EPLostPerformTotal + (IdealPower - PVDot[i, 1]) / 6
|
|
|
-
|
|
|
- print("EPLostPerformTotal", EPLostPerformTotal)
|
|
|
-
|
|
|
- # 限电损失
|
|
|
- EPLostLimitTotal = 0
|
|
|
- EPLost = 0
|
|
|
- nLimitTotal = 0
|
|
|
-
|
|
|
- PVLimit = np.zeros([nCounter1, 2])
|
|
|
-
|
|
|
- for i in range(nCounter1):
|
|
|
- if Dzwind_and_power_dfSel[i] == 4:
|
|
|
- nWhichBin = 0
|
|
|
- for m in range(base_wind_and_power_count - 1):
|
|
|
- if DzMarch809[i, 0] > base_wind_and_power_df.loc[m, self.rated_wind_speed] and DzMarch809[i, 0] <= \
|
|
|
- base_wind_and_power_df.loc[m + 1, self.rated_wind_speed]:
|
|
|
- nWhichBin = m
|
|
|
- break
|
|
|
-
|
|
|
- # 插值计算对应设计功率
|
|
|
- if nWhichBin > base_wind_and_power_count - 1 or nWhichBin == 0:
|
|
|
- continue
|
|
|
-
|
|
|
- IdealPower = (DzMarch809[i, 0] - base_wind_and_power_df.loc[nWhichBin, self.rated_wind_speed]) / (
|
|
|
- base_wind_and_power_df.loc[nWhichBin + 1, self.rated_wind_speed] -
|
|
|
- base_wind_and_power_df.loc[nWhichBin, self.rated_wind_speed]) * (
|
|
|
- base_wind_and_power_df.loc[nWhichBin + 1, self.rated_capacity] -
|
|
|
- base_wind_and_power_df.loc[nWhichBin, self.rated_capacity]) + \
|
|
|
- base_wind_and_power_df.loc[nWhichBin, self.rated_capacity]
|
|
|
- EPLost = np.abs(IdealPower - DzMarch809[i, 1]) / 6
|
|
|
- EPLostLimitTotal = EPLostLimitTotal + EPLost
|
|
|
-
|
|
|
- PVLimit[nLimitTotal, :] = DzMarch809[i, :]
|
|
|
- nLimitTotal = nLimitTotal + 1
|
|
|
-
|
|
|
- nLimitTotal = nLimitTotal - 1
|
|
|
-
|
|
|
- print("nLimitTotal", nLimitTotal)
|
|
|
-
|
|
|
- # 欠发和限点损失总和
|
|
|
- EPLostBadLimitTotal = EPLostBadTotal + EPLostLimitTotal
|
|
|
-
|
|
|
- # 如果功率曲线未达标损失为正
|
|
|
- if EPLostPerformTotal >= 0:
|
|
|
- EPIdealTotal = EPActualTotal + EPLostStopTotal + EPLostLimitTotal + EPLostBadTotal + EPLostPerformTotal
|
|
|
-
|
|
|
- # 如果功率曲线未达标损失为负
|
|
|
- if EPLostPerformTotal < 0:
|
|
|
- EPIdealTotal = EPActualTotal + EPLostStopTotal + EPLostLimitTotal + EPLostBadTotal
|
|
|
-
|
|
|
- print("EPIdealTotal", EPIdealTotal)
|
|
|
- # 可以比较求和得到的应发功率EPIdealTotal与理论计算得到的应发功率EPIdealTotalAAA的差别
|
|
|
- # 需要去除的超发功率:(1)功率主带左侧的超发点;(2)额定风速以上的超发点。
|
|
|
- RemoveOverEP = 0
|
|
|
- nType2 = 0
|
|
|
- for i in range(nCounter1):
|
|
|
- if Dzwind_and_power_dfSel[i] == 2: # 功率主带左侧的超发坏点
|
|
|
- nWhichBin = 0
|
|
|
- for m in range(base_wind_and_power_count - 1):
|
|
|
- if DzMarch809[i, 0] > base_wind_and_power_df.loc[m, self.rated_wind_speed] and DzMarch809[i, 0] <= \
|
|
|
- base_wind_and_power_df.loc[m + 1, self.rated_wind_speed]:
|
|
|
- nWhichBin = m
|
|
|
- break
|
|
|
-
|
|
|
- if nWhichBin > base_wind_and_power_count - 1 or nWhichBin == 0:
|
|
|
- continue
|
|
|
-
|
|
|
- IdealPower = (DzMarch809[i, 0] - base_wind_and_power_df.loc[nWhichBin, self.rated_wind_speed]) / (
|
|
|
- base_wind_and_power_df.loc[nWhichBin + 1, self.rated_wind_speed] - base_wind_and_power_df.loc[
|
|
|
- nWhichBin, self.rated_wind_speed]) * (
|
|
|
- base_wind_and_power_df.loc[nWhichBin + 1, self.rated_capacity] -
|
|
|
- base_wind_and_power_df.loc[nWhichBin, self.rated_capacity]) + \
|
|
|
- base_wind_and_power_df.loc[nWhichBin, self.rated_capacity]
|
|
|
-
|
|
|
- RemoveOverEP = RemoveOverEP + (DzMarch809[i, 1] - IdealPower) / 6
|
|
|
- nType2 = nType2 + 1
|
|
|
-
|
|
|
- print("RemoveOverEP", RemoveOverEP)
|
|
|
- print("nType2", nType2)
|
|
|
- # 额定功率以上的超发点
|
|
|
- nTypeOver = 0
|
|
|
- for i in range(nCounter1):
|
|
|
- if DzMarch809[i, 1] > PRated:
|
|
|
- RemoveOverEP = RemoveOverEP + (DzMarch809[i, 1] - PRated) / 6
|
|
|
- nTypeOver = nTypeOver + 1
|
|
|
-
|
|
|
- print("RemoveOverEP", RemoveOverEP)
|
|
|
- print("nTypeOver", nTypeOver)
|
|
|
-
|
|
|
- def run(self):
|
|
|
- # Implement your class identification logic here
|
|
|
- self.identifier()
|
|
|
-
|
|
|
-
|
|
|
-if __name__ == '__main__':
|
|
|
- test = ClassIdentifier('test', r"D:\中能智能\matlib计算相关\好点坏点matlib计算\A01.csv", index='时间',
|
|
|
- wind_velocity='风速',
|
|
|
- active_power='功率')
|
|
|
-
|
|
|
- test.run()
|