limited_power_wind.py 5.6 KB

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