limited_power_wind.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. import copy
  2. import os
  3. import pandas as pd
  4. import numpy as np
  5. import matplotlib.pyplot as plt
  6. import pickle
  7. import argparse
  8. current_path = os.path.dirname(__file__)
  9. parent_path = os.path.dirname(current_path)
  10. class LimitPower(object):
  11. def __init__(self, logger, params, weather_power):
  12. self.logger = logger
  13. self.opt = argparse.Namespace(**params)
  14. self.weather_power = weather_power
  15. self.step = self.opt.usable_power_w['step']
  16. self.segs = np.array([x * self.step for x in range(1, 50)]) # 对风速以50为间隔进行分段
  17. self.xs = np.array([self.segs[i - 1] + x if i > 0 else self.step / 2 for i, x in
  18. enumerate([self.step / 2 for _ in self.segs])]) # 分段的中间点
  19. self.polynomial = None
  20. self.width = 0
  21. self.max_ws = 50
  22. def segment_statis(self):
  23. """
  24. 对机头风速-实际功率进行分段处理,获取分度的中位点,四分位间距和斜率
  25. :return: glob_rp 总辐射分段
  26. """
  27. glob_rp = {} # dict: key 辐照度分段中间点 value 分段内的实际功率
  28. for index, row in self.weather_power.iterrows():
  29. ws_ = row[self.opt.usable_power_w["env"]]
  30. rp = row[self.opt.target]
  31. for i, seg in enumerate(self.segs):
  32. if ws_ <= seg:
  33. glob_rp.setdefault(list(self.xs)[i], []).append(rp)
  34. break
  35. rms = []
  36. for i, x in enumerate(self.xs):
  37. rps = glob_rp.get(x)
  38. if rps is None:
  39. continue
  40. rps = np.array(rps)
  41. up = self.opt.usable_power_w['up_fractile']
  42. down = self.opt.usable_power_w['down_fractile']
  43. offset = 0
  44. while True:
  45. index = i-1 if i > 0 else 0
  46. while (self.xs[index] in rms or self.xs[index] not in glob_rp) and index >0:
  47. index -= 1
  48. x_l = self.xs[index] if index > 0 else 0
  49. q2_l = glob_rp[list(self.xs)[index]][0] if index > 0 else 0
  50. down = down + offset
  51. if down > up:
  52. rms.append(x)
  53. self.logger.info("删除的坐标点为:{}".format(x))
  54. break
  55. q1 = np.percentile(rps, down) # 下四分位点
  56. q2 = round(np.percentile(rps, down+(up-down)/2), 3) # 中位点
  57. q3 = np.percentile(rps, up) # 上四分为点
  58. # q2 = np.around(np.mean(rps[(rps >= q1) & (rps <= q3)]), 3)
  59. iqr = q3 - q1 # 四分位间距
  60. k2 = round((q2-q2_l)/(x-x_l), 3) # 趋势斜率
  61. # std = np.around(np.std(rps[(rps >= q1) & (rps <= q3)]), 3)
  62. # mean = np.around(np.mean(rps), 3) # 实际功率均值
  63. # std = np.around(np.std(rps), 3) # 实际功率标准差
  64. # print("看看q2={},mean={}".format(q2, mean))
  65. if k2 >= 0:
  66. glob_rp[x] = [q2, iqr] # 更新dict
  67. break
  68. else:
  69. offset += 1
  70. glob_rp = {k: glob_rp[k] for k in glob_rp.keys() if k not in rms}
  71. glob_rp = {k: glob_rp[k] for k in sorted(glob_rp.keys())}
  72. return glob_rp
  73. def mapping_relation(self, glob_rp):
  74. degree = self.opt.usable_power_w['degree']
  75. xs = list(glob_rp.keys())
  76. ys = [y[0] for y in glob_rp.values()]
  77. self.width = np.median(np.array([y[1] for y in glob_rp.values()]))
  78. coefficients = np.polyfit(xs, ys, degree)
  79. self.polynomial = np.poly1d(coefficients)
  80. self.max_ws = max(xs)
  81. # y_fit = self.polynomial(xs)
  82. # plt.scatter(xs, ys, label='Data', color='red')
  83. # plt.plot(xs, y_fit, label='Fitted polynomial', color='blue')
  84. # plt.plot(xs, y_fit+self.width/2, label='up polynomial', color='purple')
  85. # plt.plot(xs, y_fit-self.width/2, label='down polynomial', color='green')
  86. # plt.legend()
  87. # plt.xlabel('x')
  88. # plt.ylabel('y')
  89. # plt.title(f'Polynomial Fit (degree {degree})')
  90. # plt.show()
  91. def saveVar(self, path, data):
  92. os.makedirs(os.path.dirname(path), exist_ok=True)
  93. with open(path, 'wb') as file:
  94. pickle.dump(data, file)
  95. def filter_unlimited_power(self, ws, real_power):
  96. """
  97. 预测可用功主方法
  98. :param zfs: 要预测可用功率的总辐射
  99. :param k: 斜率
  100. :param b: 偏移量
  101. :return: 预测的可用功率
  102. """
  103. # coe = self.opt.usable_power['outliers_threshold']
  104. # seg = self.xs[np.argmax(self.segs >= ws)]
  105. up_offset = self.opt.usable_power_w['up_offset']
  106. down_offset = self.opt.usable_power_w['down_offset']
  107. high = self.polynomial(ws) + self.width/up_offset if self.polynomial(ws) + self.width/up_offset < self.opt.cap else self.opt.cap
  108. low = self.polynomial(ws) - self.width/down_offset if self.polynomial(ws) - self.width/down_offset > 0 else 0
  109. if low <= real_power <= high:
  110. return True
  111. else:
  112. return False
  113. def clean_limited_power(self, name, cluster=False):
  114. if cluster is True:
  115. glob_rp = self.segment_statis()
  116. self.mapping_relation(glob_rp)
  117. new_weather_power, number = [], 0
  118. # fig, ax = plt.subplots()
  119. for index, row in self.weather_power.iterrows():
  120. zfs = row[self.opt.usable_power_w["env"]]
  121. rp = row[self.opt.target]
  122. if zfs < 0 or rp < 0:
  123. continue
  124. if self.filter_unlimited_power(zfs, rp) and zfs <= self.max_ws:
  125. row['c'] = 'red'
  126. new_weather_power.append(row)
  127. else:
  128. row['c'] = 'blue'
  129. new_weather_power.append(row)
  130. new_weather_power = pd.concat(new_weather_power, axis=1).T
  131. new_weather_power.plot.scatter(x=self.opt.usable_power_w["env"], y='Power', c='c')
  132. plt.savefig(parent_path + '/figs/测风法{}.png'.format(name))
  133. new_weather_power = new_weather_power[new_weather_power['c'] == 'red']
  134. number = len(new_weather_power)
  135. self.logger.info("未清洗限电前,总共有:{}条数据".format(len(self.weather_power)))
  136. self.logger.info("清除限电后保留的点有:" + str(number) + " 占比:" + str(round(number / len(self.weather_power), 2)))
  137. return new_weather_power.loc[:, [self.opt.col_time, self.opt.tagert]]
  138. if __name__ == '__main__':
  139. from logs import Log
  140. from config import myargparse
  141. log = Log().logger
  142. # 实例化配置类
  143. args = myargparse(discription="场站端配置", add_help=False)
  144. power = pd.read_csv('./data/power.csv')
  145. weather = pd.read_csv('./data/tower-1-process.csv')
  146. weather_power = pd.merge(weather, power, on='C_TIME') # 联立数据
  147. lp = LimitPower(log, args, weather_power)
  148. # glob_rp = lp.segment_statis()
  149. # lp.mapping_relation(glob_rp)
  150. lp.clean_limited_power('测试1')
  151. # glob_rp = {k: glob_rp[k] for k in sorted(glob_rp.keys())}
  152. # keys = list(glob_rp.keys())
  153. # values = [v[0] for v in glob_rp.values()]
  154. # import matplotlib.pyplot as plt
  155. # fig, ax = plt.subplots()
  156. # ax.plot(keys, values)
  157. # plt.show()