SCADA_10min_category_0.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. # -*- coding: utf-8 -*-
  2. """
  3. Created on Mon Apr 8 15:01:43 2024
  4. @author: LDDN
  5. """
  6. import math
  7. import pandas as pd
  8. import numpy as np
  9. import matplotlib.pyplot as plt
  10. from matplotlib.pyplot import MultipleLocator#设定固定刻度
  11. scada_10min = pd.read_csv(r'E:\BaiduNetdiskDownload\test\min_scada_LuoTuoGou\72\82.csv',encoding="utf-8") #.value是将单元格
  12. turbine_info = pd.read_csv(r'E:\BaiduNetdiskDownload\test\min_scada_LuoTuoGou\72\info.csv') #.value是将单元格
  13. PRated = turbine_info.loc[:,["额定功率"]] #2000
  14. PRated = PRated.values
  15. VCutOut = turbine_info.loc[:,["切出风速"]] #25
  16. VCutOut = VCutOut.values
  17. VCutIn = turbine_info.loc[:,["切入风速"]] #3
  18. VCutIn = VCutIn.values
  19. VRated = turbine_info.loc[:,["额定风速"]] #10
  20. VRated = VRated.values
  21. time_stamp = scada_10min.loc[:,['时间']] #dataframe
  22. active_power = scada_10min.loc[:,['变频器电网侧有功功率']]
  23. wind_speed = scada_10min.loc[:,['风速']]
  24. LM = pd.concat([time_stamp,active_power,wind_speed],axis=1) #dataframe
  25. Labeled_March809 = LM
  26. APower = Labeled_March809["变频器电网侧有功功率"] #series读入有功功率
  27. WSpeed = Labeled_March809["风速"] #读入风速
  28. maxP=np.max(APower)
  29. intervalP=25 #ceil(PRated*0.01)#功率分区间隔为额定功率的1%
  30. intervalwindspeed=0.25 #风速分区间隔0.25m/s
  31. #初始化
  32. PNum = 0
  33. TopP = 0
  34. # 根据条件计算PNum和TopP
  35. if maxP >= PRated:
  36. PNum = math.floor(maxP / intervalP) + 1
  37. TopP = math.floor((maxP - PRated) / intervalP) + 1
  38. else:
  39. PNum = math.floor(PRated / intervalP)
  40. TopP = 0
  41. VNum = math.ceil(VCutOut / intervalwindspeed)
  42. SM1 = Labeled_March809.shape
  43. AA1 = SM1[0]
  44. lab = [[0] for _ in range(AA1)]
  45. lab = pd.DataFrame(lab,columns=['lab'])
  46. Labeled_March809 = pd.concat([Labeled_March809,lab],axis=1) #在tpv后加一列标签列
  47. Labeled_March809 = Labeled_March809.values
  48. SM = Labeled_March809.shape #(52561,4)
  49. AA = SM[0]
  50. #存储功率大于0的运行数据
  51. #标识功率为0的点,标识-1
  52. DzMarch809_0 = np.zeros((AA, 3)) # 初始化数组来存储功率大于零的运行数据
  53. nCounter1 = 0
  54. Point_line = np.zeros(AA, dtype=int)
  55. #考虑到很多功率小于10的数据存在,将<10的功率视为0
  56. for i in range(AA):
  57. if (APower[i] > 10) & (WSpeed[i] > 0):
  58. nCounter1 += 1 #共有nCounter1个功率大于0的正常数据
  59. DzMarch809_0[nCounter1-1, 0] = WSpeed[i]
  60. DzMarch809_0[nCounter1-1, 1] = APower[i]
  61. Point_line[nCounter1-1] = i+1 # 记录nCounter1记下的数据在原始数据中的位置
  62. if APower[i] <= 10:
  63. Labeled_March809[i,SM[1]-1] = -1 # 功率为0标识为-1 array类型
  64. # 截取DzMarch809_0中实际存储的数据 其他全为0
  65. DzMarch809 = DzMarch809_0[:nCounter1, :]
  66. #统计各网格落入的散点个数
  67. XBoxNumber = np.ones((PNum, VNum),dtype=int) #(86 100)
  68. nWhichP = 0
  69. nWhichV = 0
  70. # 循环遍历DzMarch809中的有效数据
  71. for i in range(nCounter1):
  72. # 查找功率所在的区间
  73. for m in range(1, PNum + 1): # 注意Python的range是左闭右开的,所以需要+1
  74. if (DzMarch809[i,1] > (m - 1) * intervalP) and (DzMarch809[i,1] <= m * intervalP):
  75. nWhichP = m
  76. break
  77. # 查找风速所在的区间
  78. for n in range(1, VNum + 1): # 同样需要+1
  79. if (DzMarch809[i, 0] > (n - 1)*intervalwindspeed) and (DzMarch809[i, 0] <= n*intervalwindspeed):
  80. nWhichV = n
  81. break
  82. # 如果功率和风速都在有效区间内,增加对应网格的计数
  83. if (nWhichP > 0) and (nWhichV > 0):
  84. XBoxNumber[nWhichP - 1, nWhichV - 1] += 1 # 注意Python的索引是从0开始的,所以需要减1
  85. # XBoxNumber现在包含了每个网格的计数[PNum行, VNum列]
  86. for m in range(1,PNum+1):
  87. for n in range(1,VNum+1):
  88. XBoxNumber[m-1,n-1] = XBoxNumber[m-1,n-1] - 1
  89. #在功率方向将网格内散点绝对个数转换为相对百分比,备用
  90. PBoxPercent = np.zeros((PNum, VNum),dtype = float) #(86 100) #计算后会出现浮点型,所以不能定义int类型
  91. PBinSum = np.zeros((PNum,1),dtype=int)
  92. for i in range(1,PNum+1):
  93. for m in range(1,VNum+1):
  94. PBinSum[i-1] = PBinSum[i-1] + XBoxNumber[i-1,m-1]
  95. for m in range(1,VNum+1):
  96. if PBinSum[i-1]>0:
  97. PBoxPercent[i-1,m-1] = (XBoxNumber[i-1,m-1] / PBinSum[i-1])*100
  98. #在风速方向将网格内散点绝对个数转换为相对百分比,备用
  99. VBoxPercent = np.zeros((PNum, VNum)) #(86 100) #计算后会出现浮点型,所以不能定义int类型
  100. VBinSum = np.zeros((VNum,1),dtype=int)
  101. for i in range(1,VNum+1):
  102. for m in range(1,PNum+1):
  103. VBinSum[i-1] = VBinSum[i-1] + XBoxNumber[m-1,i-1]
  104. for m in range(1,PNum+1):
  105. if VBinSum[i-1]>0:
  106. VBoxPercent[m-1,i-1] = (XBoxNumber[m-1,i-1] / VBinSum[i-1])*100
  107. # VBoxPercent PBoxPercent 左上-右下
  108. # 将数据颠倒一下 左下-右上 第一行换为倒数第一行 方便可视化
  109. InvXBoxNumber = np.zeros((PNum,VNum),dtype = int)
  110. InvPBoxPercent = np.zeros((PNum,VNum),dtype = float)
  111. InvVBoxPercent = np.zeros((PNum,VNum),dtype = float)
  112. for m in range(1,PNum+1):
  113. for n in range(1,VNum+1):
  114. InvXBoxNumber[m-1,n-1] = XBoxNumber[PNum-(m-1)-1,n-1]
  115. InvPBoxPercent[m-1,n-1] = PBoxPercent[PNum-(m-1)-1,n-1]
  116. InvVBoxPercent[m-1,n-1] = VBoxPercent[PNum-(m-1)-1,n-1]
  117. #以水平功率带方向为准,分析每个水平功率带中,功率主带中心,即找百分比最大的网格位置。
  118. PBoxMaxIndex = np.zeros((PNum,1),dtype = int) #水平功率带最大网格位置索引
  119. PBoxMaxP = np.zeros((PNum,1),dtype = float) #水平功率带最大网格百分比
  120. for m in range(1,PNum+1):
  121. PBoxMaxIndex[m-1] = np.argmax(PBoxPercent[m-1, :]) #argmax返回最大值的索引
  122. PBoxMaxP[m-1] = np.max(PBoxPercent[m-1, :])
  123. #以垂直风速方向为准,分析每个垂直风速带中,功率主带中心,即找百分比最大的网格位置。
  124. VBoxMaxIndex = np.zeros((VNum,1),dtype = int)
  125. VBoxMaxV = np.zeros((VNum,1),dtype = float)
  126. for m in range(1,VNum+1):
  127. VBoxMaxIndex[m-1] = np.argmax(VBoxPercent[:, m-1])
  128. VBoxMaxV[m-1] = np.max(VBoxPercent[:, m-1])
  129. #切入风速特殊处理,如果切入风速过于偏右,向左拉回
  130. if PBoxMaxIndex[0]>14: #第一个值对应的是风速最小处 即切入风速
  131. PBoxMaxIndex[0] = 9
  132. #以水平功率带方向为基准,进行分析
  133. DotDense = np.zeros(PNum) #每一水平功率带的功率主带包含的网格数
  134. DotDenseLeftRight = np.zeros((PNum,2)) #存储每一水平功率带的功率主带以最大网格为中心,向左,向右扩展的网格数
  135. DotValve = 90 #从中心向左右对称扩展网格的散点百分比和的阈值。
  136. PDotDenseSum = 0
  137. for i in range(PNum - TopP): # 从最下层水平功率带开始,向上分析到特定的功率带
  138. PDotDenseSum = PBoxMaxP[i] # 以中心最大水平功率带为基准,向左向右对称扩展网格,累加各网格散点百分比
  139. iSpreadRight = 1
  140. iSpreadLeft = 1
  141. while PDotDenseSum < DotValve:
  142. if (PBoxMaxIndex[i] + iSpreadRight) < VNum-1-1:
  143. PDotDenseSum += PBoxPercent[i, PBoxMaxIndex[i] + iSpreadRight] # 向右侧扩展
  144. iSpreadRight += 1
  145. else:
  146. break
  147. if (PBoxMaxIndex[i] - iSpreadLeft) > 0:
  148. PDotDenseSum += PBoxPercent[i, PBoxMaxIndex[i] - iSpreadLeft] # 向左侧扩展
  149. iSpreadLeft += 1
  150. else:
  151. break
  152. iSpreadRight = iSpreadRight-1
  153. iSpreadLeft = iSpreadLeft-1
  154. #向左右扩展完毕
  155. DotDenseLeftRight[i, 0] = iSpreadLeft # 左
  156. DotDenseLeftRight[i, 1] = iSpreadRight # 右
  157. DotDense[i] = iSpreadLeft + iSpreadRight + 1 # 记录向左向右扩展的个数及每个功率仓内网格的个数
  158. # 此时DotDense和DotDenseLeftRight数组已经包含了所需信息
  159. #各行功率主带右侧宽度的中位数最具有代表性(因为先右后左)
  160. DotDenseWidthLeft = np.zeros((PNum-TopP))
  161. for i in range(PNum-TopP):
  162. DotDenseWidthLeft[i] = DotDenseLeftRight[i,1] #DotDenseLeftRight[i,1]:向右延伸个数
  163. MainBandRight = np.median(DotDenseWidthLeft) #计算中位数
  164. # 初始化变量
  165. PowerLimit = np.zeros(PNum, dtype=int) # 各水平功率带是否为限功率标识,1:是;0:不是
  166. WidthAverage = 0 # 功率主带右侧平均宽度
  167. WidthAverage_L = 0 # 功率主带左侧平均宽度
  168. WidthVar = 0 # 功率主带方差(此变量在提供的代码中并未使用)
  169. PowerLimitValve = 6 # 限功率主带判别阈值
  170. N_Pcount = 20 # 阈值
  171. nCounterLimit = 0 # 限功率的个数
  172. nCounter = 0 # 正常水平功率带的个数
  173. # 循环遍历水平功率带,从第1个到第PNum-TopP个
  174. for i in range(PNum - TopP):
  175. # 如果向右扩展网格数大于阈值,且该水平功率带点总数大于20,则标记为限功率带
  176. if (DotDenseLeftRight[i, 1] > PowerLimitValve) and (PBinSum[i] > N_Pcount):
  177. PowerLimit[i] = 1
  178. nCounterLimit += 1 #限功率的个数
  179. # 如果向右扩展网格数小于等于阈值,则累加右侧宽度(左侧宽度在代码中似乎有误)
  180. if DotDenseLeftRight[i, 1] <= PowerLimitValve:
  181. WidthAverage += DotDenseLeftRight[i, 1] # 统计正常水平功率带右侧宽度
  182. WidthAverage_L += DotDenseLeftRight[i,1] #统计正常水平功率带左侧宽度
  183. nCounter += 1
  184. # 计算平均宽度
  185. WidthAverage /= nCounter if nCounter > 0 else 1 # 避免除以0的情况
  186. WidthAverage_L /= nCounter if nCounter > 0 else 1
  187. #计算正常(即非限功率)水平功率带的功率主带宽度的方差,以此来反映从下到上宽度是否一致
  188. WidthVar = 0 # 功率主带宽度的方差
  189. for i in range(PNum - TopP):
  190. # 如果向右扩展网格数小于等于阈值,则计算当前宽度与平均宽度的差值平方
  191. if DotDenseLeftRight[i, 1] <= PowerLimitValve:
  192. WidthVar += (DotDenseLeftRight[i, 1] - WidthAverage) ** 2
  193. # 计算方差(注意:除以nCounter-1是为了得到样本方差)
  194. WidthVar = np.sqrt(WidthVar / (nCounter - 1) if nCounter > 1 else 0) # 避免除以0的情况
  195. #各水平功率带,功率主带的风速范围,右侧扩展网格数*2*0.25
  196. PowerBandWidth = WidthAverage*intervalwindspeed+WidthAverage_L*intervalwindspeed
  197. # 对限负荷水平功率带的最大网格进行修正
  198. for i in range(1, PNum - TopP+1):
  199. if (PowerLimit[i] == 1) and (abs(PBoxMaxIndex[i] - PBoxMaxIndex[i - 1]) > 5):
  200. PBoxMaxIndex[i] = PBoxMaxIndex[i - 1] + 1
  201. # 输出各层功率主带的左右边界网格索引
  202. DotDenseInverse = np.flipud(DotDenseLeftRight) # 上下翻转数组以得到反向顺序
  203. # 计算功率主带的左右边界
  204. CurveWidthR = np.ceil(WidthAverage) + 2 # 功率主带的右边界 + 2
  205. CurveWidthL = np.ceil(WidthAverage_L) + 2 # 功率主带的左边界 + 2
  206. # 网格是否为限功率网格的标识数组
  207. BBoxLimit = np.zeros((PNum, VNum), dtype=int)
  208. # 标记限功率网格
  209. for i in range(2, PNum - TopP):
  210. if PowerLimit[i] == 1:
  211. BBoxLimit[i, int(PBoxMaxIndex[i] + CurveWidthR + 1):VNum] = 1
  212. # 初始化数据异常需要剔除的网格标识数组
  213. BBoxRemove = np.zeros((PNum, VNum), dtype=int)
  214. # 标记需要剔除的网格
  215. for m in range(PNum - TopP):
  216. for n in range(int(PBoxMaxIndex[m]) + int(CurveWidthR), VNum): # 注意Python中的索引从0开始,因此需要减去1
  217. BBoxRemove[m, n] = 1
  218. # 功率主带左侧的超发网格,从最大索引向左直到第一个网格
  219. for n in range(int(PBoxMaxIndex[m]) - int(CurveWidthL)+1, 0, -1): # 使用range的步长参数来实现从右向左的迭代
  220. BBoxRemove[m, n-1] = 2 # 注意Python中的索引从0开始,因此需要减去1
  221. # 初始化变量
  222. CurveTop = np.zeros((2, 1), dtype=int)
  223. CurveTopValve = 1 # 网格的百分比阈值
  224. BTopFind = 0
  225. mm = 0
  226. #确定功率主带的左上拐点,即额定风速位置的网格索引
  227. CurveTop = np.zeros((2, 1), dtype=int)
  228. CurveTopValve = 1 # 网格的百分比阈值
  229. BTopFind = 0
  230. mm = 0
  231. for m in range(PNum - TopP, 0, -1): # 注意Python的range是左闭右开区间,所以这里从PNum-TopP开始到1(不包括0)
  232. for n in range(int(np.floor(int(VCutIn) / intervalwindspeed)), VNum - 1): # 使用floor函数来向下取整
  233. if (VBoxPercent[m, n - 1] < VBoxPercent[m, n]) and (VBoxPercent[m, n] <= VBoxPercent[m, n + 1]) and (XBoxNumber[m, n] >= 3):
  234. CurveTop[0] = m
  235. CurveTop[1] = n #[第80个,第40个]
  236. BTopFind = 1
  237. mm = m # mm是拐点所在功率仓,对应其index
  238. break # 找到后退出内层循环
  239. if BTopFind == 1:
  240. break # 找到后退出外层循环
  241. IsolateValve = 3 #功率主带右侧孤立点占比功率仓阈值 3%
  242. # 遍历功率仓和网格
  243. for m in range(PNum - TopP):
  244. for n in range(int(PBoxMaxIndex[m]) + int(CurveWidthR), VNum):
  245. # 检查PBoxPercent是否小于阈值,如果是,则标记BBoxRemove为1
  246. if PBoxPercent[m, n] < IsolateValve:
  247. BBoxRemove[m, n] = 1
  248. #功率主带顶部宽度
  249. CurveWidthT = np.floor((maxP - PRated) / intervalP) + 1
  250. # 标记额定功率以上的超发点(PNum-PTop之间)
  251. for m in range(PNum - TopP, PNum):
  252. for n in range(VNum):
  253. BBoxRemove[m, n] = 3
  254. # 标记功率主带拐点左侧的欠发网格
  255. for m in range(mm-1, PNum - TopP):
  256. for n in range(int(CurveTop[1]) - 2):
  257. BBoxRemove[m, n] = 2 # BBoxRemove数组现在包含了根据条件标记的超发点和欠发网格的信息
  258. #以网格的标识,决定该网格内数据的标识。
  259. # DzMarch809Sel数组现在包含了每个数据点的标识
  260. DzMarch809Sel = np.zeros(nCounter1, dtype=int) # 初始化标识数组
  261. nWhichP = 0
  262. nWhichV = 0
  263. nBadA = 0
  264. for i in range(nCounter1):
  265. for m in range( PNum ):
  266. if (DzMarch809[i, 1] > m * intervalP) and (DzMarch809[i, 1] <= (m+1) * intervalP):
  267. nWhichP = m #m记录的是index
  268. break
  269. for n in range( VNum ): # 注意Python的range是左闭右开区间,所以这里到VNum+1
  270. if DzMarch809[i, 0] > ((n+1) * intervalwindspeed - intervalwindspeed/2) and DzMarch809[i, 0] <= ((n+1) * intervalwindspeed + intervalwindspeed / 2):
  271. nWhichV = n #index
  272. break
  273. if nWhichP >= 0 and nWhichV >= 0:
  274. if BBoxRemove[nWhichP, nWhichV] == 1:
  275. DzMarch809Sel[i] = 1
  276. nBadA += 1
  277. elif BBoxRemove[nWhichP, nWhichV] == 2:
  278. DzMarch809Sel[i] = 2
  279. elif BBoxRemove[nWhichP , nWhichV] == 3:
  280. DzMarch809Sel[i] = 0 # 额定风速以上的超发功率点认为是正常点,不再标识
  281. # DzMarch809Sel数组现在包含了每个数据点的标识
  282. ##############################滑动窗口方法
  283. # 存储限负荷数据
  284. PVLimit = np.zeros((nCounter1, 3)) #存储限负荷数据 %第3列用于存储限电的点所在的行数
  285. nLimitTotal = 0
  286. nWindowLength = 6 #滑动窗口长度设置为6
  287. LimitWindow = np.zeros(nWindowLength) #滑动窗口空列表
  288. UpLimit = 0 #上限
  289. LowLimit = 0 #下限
  290. PowerStd = 30 # 功率波动方差
  291. nWindowNum = np.floor(nCounter1/nWindowLength) #6587
  292. PowerLimitUp = PRated - 100
  293. PowerLimitLow = 100
  294. # 循环遍历每个窗口
  295. for i in range(int(nWindowNum)):
  296. start_idx = i * nWindowLength
  297. end_idx = start_idx + nWindowLength
  298. LimitWindow = DzMarch809[start_idx:end_idx, 1] # 提取当前窗口的数据
  299. # 检查窗口内所有数据是否在功率范围内
  300. bAllInAreas = np.all(LimitWindow >= PowerLimitLow) and np.all(LimitWindow <= PowerLimitUp)
  301. if not bAllInAreas:
  302. continue
  303. # 计算方差上下限
  304. UpLimit = LimitWindow[0] + PowerStd
  305. LowLimit = LimitWindow[0] - PowerStd
  306. # 检查窗口内数据是否在方差范围内
  307. bAllInUpLow = np.all(LimitWindow >= LowLimit) and np.all(LimitWindow <= UpLimit)
  308. if bAllInUpLow:
  309. # 标识窗口内的数据为限负荷数据
  310. DzMarch809Sel[start_idx:end_idx] = 4
  311. # 存储限负荷数据
  312. for j in range(nWindowLength):
  313. PVLimit[nLimitTotal, :2] = DzMarch809[start_idx + j, :2]
  314. PVLimit[nLimitTotal, 2] = Point_line[start_idx + j] # 对数据进行标识
  315. nLimitTotal += 1
  316. # PVLimit现在包含了限负荷数据,nLimitTotal是限负荷数据的总数
  317. #将功率滑动窗口主带平滑化
  318. # 初始化锯齿平滑的计数器
  319. nSmooth = 0
  320. # 遍历除了最后 TopP+1 个元素之外的所有 PBoxMaxIndex 元素
  321. for i in range(PNum - TopP - 1):
  322. PVLeftDown = np.zeros(2)
  323. PVRightUp = np.zeros(2)
  324. # 检查当前与下一个 PBoxMaxIndex 之间的距离是否大于等于1
  325. if PBoxMaxIndex[i + 1] - PBoxMaxIndex[i] >= 1:
  326. # 计算左下和右上顶点的坐标
  327. PVLeftDown[0] = (PBoxMaxIndex[i]+1 + CurveWidthR) * 0.25 - 0.125
  328. PVLeftDown[1] = (i) * 25
  329. PVRightUp[0] = (PBoxMaxIndex[i+1]+1 + CurveWidthR) * 0.25 - 0.125
  330. PVRightUp[1] = (i+1) * 25
  331. # 遍历 DzMarch809 数组
  332. for m in range(nCounter1):
  333. # 检查当前点是否在锯齿区域内
  334. if (DzMarch809[m, 0] > PVLeftDown[0]) and (DzMarch809[m, 0] < PVRightUp[0]) and (DzMarch809[m, 1] > PVLeftDown[1]) and (DzMarch809[m, 1] < PVRightUp[1]):
  335. # 检查斜率是否大于对角连线
  336. if (DzMarch809[m, 1] - PVLeftDown[1]) / (DzMarch809[m, 0] - PVLeftDown[0]) > (PVRightUp[1] - PVLeftDown[1]) / (PVRightUp[0] - PVLeftDown[0]):
  337. # 如果在锯齿左上三角形中,则选中并增加锯齿平滑计数器
  338. DzMarch809Sel[m] = 0
  339. nSmooth += 1
  340. # DzMarch809Sel 数组现在+包含了锯齿平滑的选择结果,nSmooth 是选中的点数
  341. ###################################存储数据
  342. # 存储好点
  343. nCounterPV = 0 # 初始化计数器
  344. PVDot = np.zeros((nCounter1, 3)) # 初始化存储好点的数组 nCounter1是p>0的数
  345. for i in range(nCounter1):
  346. if DzMarch809Sel[i] == 0:
  347. nCounterPV += 1
  348. PVDot[nCounterPV-1, :2] = DzMarch809[i, :2]
  349. PVDot[nCounterPV-1, 2] = Point_line[i] # 好点 Point_line记录nCounter1在原始数据中的位置
  350. nCounterVP = nCounterPV
  351. # 对所有数据中的好点进行标注
  352. for i in range(nCounterVP):
  353. Labeled_March809[int(PVDot[i, 2] - 1), (SM[1]-1)] = 1 # 注意Python的索引从0开始,并且需要转换为整数索引
  354. # 存储坏点
  355. nCounterBad = 0 # 初始化计数器
  356. PVBad = np.zeros((nCounter1, 3)) # 初始化存储坏点的数组
  357. for i in range(nCounter1):
  358. if DzMarch809Sel[i] in [1, 2, 3]:
  359. nCounterBad += 1
  360. PVBad[nCounterBad-1, :2] = DzMarch809[i, :2]
  361. PVBad[nCounterBad-1, 2] = Point_line[i]
  362. # 对所有数据中的坏点进行标注
  363. for i in range(nCounterBad):
  364. Labeled_March809[int(PVBad[i, 2] - 1),(SM[1]-1)] = 5 # 坏点标识
  365. # 对所有数据中的限电点进行标注
  366. for i in range(nLimitTotal):
  367. Labeled_March809[int(PVLimit[i, 2] - 1),(SM[1]-1)] = 4 # 限电点标识
  368. # 对所有的数据点进行标注
  369. # Labeled_March809是array,提取所第四列的值保存为dataframe
  370. A = Labeled_March809[:,3]
  371. A=pd.DataFrame(A,columns=['lab'])
  372. mergedTable = pd.concat([scada_10min,A],axis=1)#合并dataframe
  373. D = mergedTable[mergedTable['lab'] == 1]#选择为1的行
  374. ws = D["风速"].values #array
  375. ap = D["变频器电网侧有功功率"]
  376. # fig=plt.figure(figsize=(10,6),dpi=500) #figsize是图形大小,dpi像素
  377. fig=plt.figure() #figsize是图形大小,dpi像素
  378. plt.scatter(ws,ap,s=1,c='black',marker='.') #'.'比'o'要更小
  379. # plt.scatter(x2,y2,s=10,c='b',marker='.',label='5.8-6.5建模噪声点')
  380. x_major_locator=MultipleLocator(5)
  381. y_major_locator=MultipleLocator(500)
  382. ax=plt.gca()
  383. ax.xaxis.set_major_locator(x_major_locator)
  384. ax.yaxis.set_major_locator(y_major_locator)
  385. plt.xlim((0,30))
  386. plt.ylim((0,2200))
  387. plt.tick_params(labelsize=8)
  388. # plt.grid(c='dimgray',alpha=0.2)
  389. plt.xlabel("V/(m$·$s$^{-1}$)",fontsize=8)
  390. plt.ylabel("P/kW",fontsize=8)
  391. # plt.savefig(r'D:\赵雅丽\研究生学习资料\学习资料\劣化度健康度\spyder\大论文\图\风速-功率.jpg',bbox_inches='tight')
  392. plt.show()