limited_power_wind.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import os
  2. import pandas as pd
  3. import numpy as np
  4. np.random.seed(42)
  5. from cache.data_cleaning import cleaning
  6. import matplotlib.pyplot as plt
  7. import pickle
  8. current_path = os.path.dirname(__file__)
  9. class LimitPower(object):
  10. def __init__(self, logger, args, weather_power):
  11. self.logger = logger
  12. self.args = args
  13. self.opt = self.args.parse_args_and_yaml()
  14. self.weather_power = weather_power
  15. self.weather_power = self.weather_power[self.weather_power[self.opt.usable_power["env"]] >= 0]
  16. self.step = self.opt.usable_power['step']
  17. self.segs = np.array([x * self.step for x in range(1, 50)]) # 对风速以50为间隔进行分段
  18. self.xs = np.array([self.segs[i - 1] + x if i > 0 else self.step / 2 for i, x in
  19. enumerate([self.step / 2 for _ in self.segs])]) # 分段的中间点
  20. def segment_statis(self):
  21. """
  22. 对机头风速-实际功率进行分段处理,获取分度的中位点,四分位间距和斜率
  23. :return: glob_rp 总辐射分段
  24. """
  25. glob_rp = {} # dict: key 辐照度分段中间点 value 分段内的实际功率
  26. for index, row in self.weather_power.iterrows():
  27. ws_ = row[self.opt.usable_power["env"]]
  28. rp = row['C_REAL_VALUE']
  29. for i, seg in enumerate(self.segs):
  30. if ws_ <= seg:
  31. glob_rp.setdefault(self.xs[i], []).append(rp)
  32. break
  33. for i, x in enumerate(self.xs):
  34. rps = glob_rp.get(x)
  35. if rps is None:
  36. continue
  37. mean = np.around(np.mean(rps), 3) # 实际功率下四分位点
  38. std = np.around(np.std(rps), 3) # 实际功率中位点
  39. glob_rp[x] = [mean, std] # 更新dict
  40. self.saveVar(os.path.dirname(current_path)+'/var/glob_rp.pickle', glob_rp)
  41. return glob_rp
  42. def saveVar(self, path, data):
  43. os.makedirs(os.path.dirname(path), exist_ok=True)
  44. with open(path, 'wb') as file:
  45. pickle.dump(data, file)
  46. def filter_unlimited_power(self, ws, real_power, glob_rp):
  47. """
  48. 预测可用功主方法
  49. :param zfs: 要预测可用功率的总辐射
  50. :param k: 斜率
  51. :param b: 偏移量
  52. :return: 预测的可用功率
  53. """
  54. coe = self.opt.usable_power['outliers_threshold']
  55. seg = self.xs[np.argmax(self.segs >= ws)]
  56. if seg in glob_rp:
  57. mean, std = glob_rp[seg][0], glob_rp[seg][1]
  58. high = mean + std*coe if mean + std*coe < self.opt.cap else self.opt.cap
  59. low = mean - std*coe if mean - std*coe > 0 else 0
  60. if low <= real_power <= high:
  61. return True
  62. else:
  63. return False
  64. else:
  65. return True
  66. def clean_limited_power(self, name, signal=False):
  67. glob_rp = self.segment_statis()
  68. new_weather_power = []
  69. # fig, ax = plt.subplots()
  70. for index, row in self.weather_power.iterrows():
  71. zfs = row[self.opt.usable_power["env"]]
  72. rp = row['C_REAL_VALUE']
  73. s = int(row['signal']) if signal is True else 2
  74. if self.filter_unlimited_power(zfs, rp, glob_rp):
  75. row['c'] = 'red' if s == 0 or s == 2 else 'cornflowerblue'
  76. new_weather_power.append(row)
  77. else:
  78. row['c'] = 'blue' if s == 1 or s == 2 else 'pink'
  79. new_weather_power.append(row)
  80. new_weather_power = pd.concat(new_weather_power, axis=1).T
  81. new_weather_power.plot.scatter(x=self.opt.usable_power["env"], y='C_REAL_VALUE', c='c')
  82. plt.savefig(current_path + '/figs/限电{}.png'.format(name))
  83. new_weather_power = new_weather_power[new_weather_power['c'] == 'red']
  84. number = len(new_weather_power)
  85. self.logger.info("未清洗限电前,总共有:{}条数据".format(len(self.weather_power)))
  86. self.logger.info("清除限电的点有:" + str(number) + " 占比:" + str(round(number / len(self.weather_power), 2)))
  87. self.args.save_args_yml(self.opt)
  88. return new_weather_power.loc[:, ['C_TIME', 'C_REAL_VALUE', 'C_ABLE_VALUE']]
  89. def clean_limited_power_by_signal(self):
  90. # powers = self.weather_power.copy()
  91. self.weather_power["signal"] = self.weather_power.apply(lambda x: self.signal_result(x["C_IS_RATIONING_BY_MANUAL_CONTROL"], x["C_IS_RATIONING_BY_AUTO_CONTROL"]), axis=1)
  92. # powers['c'] = self.weather_power.apply(lambda x: 'blue' if bool(x["signal"]) is True else 'red', axis=1)
  93. # self.weather_power.plot.scatter(x=self.opt.usable_power["env"], y='C_REAL_VALUE', c='c')
  94. # plt.savefig(current_path + '/figs/限电.png')
  95. new_weather_power = self.weather_power[self.weather_power['signal'] == False]
  96. return new_weather_power.loc[:, ['C_TIME', 'C_REAL_VALUE', 'C_ABLE_VALUE']]
  97. def signal_result(self, manual, auto):
  98. if int(manual) == 0:
  99. if int(auto) == 0:
  100. return False
  101. else:
  102. return True
  103. else:
  104. if int(auto) == 1:
  105. return True
  106. else:
  107. return False
  108. def plt_point(glob_rp, coe):
  109. """
  110. 对最后的可用功范围进行画图
  111. :param glob_rp: 总辐射分段
  112. :param width: 偏移量
  113. :return:
  114. """
  115. fig, ax = plt.subplots()
  116. for x, row in glob_rp.items():
  117. ax.scatter(x, row[0]-row[1]*coe, s=10, alpha=0.5)
  118. ax.scatter(x, row[0]+row[1]*coe, s=10, alpha=0.5)
  119. ax.scatter(x, row[0], s=12, alpha=0.75, marker='x')
  120. plt.savefig('./7月份-优化1.png')
  121. if __name__ == '__main__':
  122. power = pd.read_csv('2023-12-01至2023-12-23实际功率导出文件.csv', date_parser=['时间'])
  123. weather = pd.read_csv('2023-12-01至2023-12-23气象站数据导出文件.csv', date_parser=['时间'])
  124. weather_power = pd.merge(weather, power, on='时间') # 联立数据