154 lines
7.3 KiB
Python
154 lines
7.3 KiB
Python
import gym
|
||
import pandas as pd
|
||
|
||
from data_manager import *
|
||
from module import *
|
||
from parameters import *
|
||
|
||
|
||
class WgzGym(gym.Env):
|
||
def __init__(self, **kwargs):
|
||
super(WgzGym, self).__init__()
|
||
self.excess = None
|
||
self.shedding = None
|
||
self.unbalance = None
|
||
self.real_unbalance = None
|
||
self.operation_cost = None
|
||
self.current_output = None
|
||
self.final_step_outputs = None
|
||
self.data_manager = DataManager()
|
||
self._load_year_data()
|
||
self.month = 1
|
||
self.day = 1
|
||
self.TRAIN = True
|
||
self.current_time = None
|
||
self.episode_length = 24
|
||
self.penalty_coefficient = 50 # 约束惩罚系数
|
||
self.sell_coefficient = 0.1 # 售出利润系数
|
||
self.EC_parameters = kwargs.get('EC_parameters', EC_parameters) # 电解水制氢器
|
||
self.HST_parameters = kwargs.get('dg_parameters', dg_parameters) # 储氢罐
|
||
|
||
self.grid = Grid()
|
||
self.EC = EC(self.EC_parameters)
|
||
self.HST = HST(self.HST_parameters)
|
||
|
||
self.action_space = gym.spaces.Box(low=-1, high=1, shape=(3,), dtype=np.float32)
|
||
'''
|
||
时间 光伏 温度(湿度暂未考虑) 电需 热需(转化为对应热水所需瓦数) 人数 电价 7
|
||
电解水制氢功率 市电功率 储氢罐容量占比 3
|
||
'''
|
||
self.state_space = gym.spaces.Box(low=0, high=1, shape=(10,), dtype=np.float32)
|
||
|
||
def reset(self, *args):
|
||
self.month = np.random.randint(1, 13) # choose 12 month
|
||
if self.TRAIN:
|
||
self.day = np.random.randint(1, 20)
|
||
else:
|
||
self.day = np.random.randint(20, Constant.MONTHS_LEN[self.month - 1])
|
||
self.current_time = 0
|
||
self.EC.reset()
|
||
self.HST.reset()
|
||
return self._build_state()
|
||
|
||
def _build_state(self):
|
||
soc = self.HST.SOC()
|
||
ec_output = self.EC.current_output
|
||
time_step = self.current_time
|
||
|
||
price = self.data_manager.get_price_data(self.month, self.day, self.current_time)
|
||
temper = self.data_manager.get_temperature_data(self.month, self.day, self.current_time)
|
||
solar = self.data_manager.get_solar_data(self.month, self.day, self.current_time)
|
||
load = self.data_manager.get_load_data(self.month, self.day, self.current_time)
|
||
heat = self.data_manager.get_heat_data(self.month, self.day, self.current_time)
|
||
people = self.data_manager.get_people_data(self.month, self.day, self.current_time)
|
||
|
||
obs = np.concatenate((np.float32(time_step), np.float32(soc), np.float32(price), np.float32(netload),
|
||
np.float32(dg1_output), np.float32(dg2_output), np.float32(dg3_output),
|
||
np.float32(temperature), np.float32(irradiance), np.float32(windspeed)), axis=None)
|
||
return obs
|
||
|
||
def step(self, action): # state transition: current_obs->take_action->get_reward->get_finish->next_obs
|
||
# 在每个组件中添加动作
|
||
current_obs = self._build_state()
|
||
temperature = current_obs[7]
|
||
irradiance = current_obs[8]
|
||
self.wind.current_power = current_obs[9]
|
||
self.battery.step(action[0]) # 执行状态转换,电池当前容量也改变
|
||
self.dg1.step(action[1])
|
||
self.dg2.step(action[2])
|
||
self.dg3.step(action[3])
|
||
self.solar.step(temperature, irradiance, action[4])
|
||
self.current_output = np.array((self.dg1.current_output, self.dg2.current_output, self.dg3.current_output,
|
||
-self.battery.energy_change, self.solar.current_power, self.wind.current_power))
|
||
actual_production = sum(self.current_output)
|
||
price = current_obs[1]
|
||
netload = current_obs[3] - self.solar.output_change
|
||
unbalance = actual_production - netload
|
||
|
||
# reward = 0.0
|
||
excess_penalty = 0
|
||
deficient_penalty = 0
|
||
sell_benefit, buy_cost = 0, 0
|
||
self.excess, self.shedding = 0, 0
|
||
if unbalance >= 0: # 过剩
|
||
if unbalance <= self.grid.exchange_ability:
|
||
sell_benefit = self.grid.get_cost(price, unbalance) * self.sell_coefficient
|
||
else:
|
||
sell_benefit = self.grid.get_cost(price, self.grid.exchange_ability) * self.sell_coefficient
|
||
# real unbalance:超电网限值
|
||
self.excess = unbalance - self.grid.exchange_ability
|
||
excess_penalty = self.excess * self.penalty_coefficient
|
||
else: # unbalance <0, 缺少惩罚
|
||
if abs(unbalance) <= self.grid.exchange_ability:
|
||
buy_cost = self.grid.get_cost(price, abs(unbalance))
|
||
else:
|
||
buy_cost = self.grid.get_cost(price, self.grid.exchange_ability)
|
||
self.shedding = abs(unbalance) - self.grid.exchange_ability
|
||
deficient_penalty = self.shedding * self.penalty_coefficient
|
||
battery_cost = self.battery.get_cost(self.battery.energy_change)
|
||
dg1_cost = self.dg1.get_cost(self.dg1.current_output)
|
||
dg2_cost = self.dg2.get_cost(self.dg2.current_output)
|
||
dg3_cost = self.dg3.get_cost(self.dg3.current_output)
|
||
solar_cost = self.solar.get_cost(self.solar.current_power)
|
||
wind_cost = self.wind.gen_cost(self.wind.current_power)
|
||
|
||
self.operation_cost = (battery_cost + dg1_cost + dg2_cost + dg3_cost + solar_cost + wind_cost
|
||
+ excess_penalty + deficient_penalty - sell_benefit + buy_cost)
|
||
reward = - self.operation_cost / 1e3
|
||
self.unbalance = unbalance
|
||
self.real_unbalance = self.shedding + self.excess
|
||
final_step_outputs = [self.dg1.current_output, self.dg2.current_output, self.dg3.current_output,
|
||
self.battery.current_capacity, self.solar.current_power, self.wind.current_power]
|
||
self.current_time += 1
|
||
finish = (self.current_time == self.episode_length)
|
||
if finish:
|
||
self.final_step_outputs = final_step_outputs
|
||
self.current_time = 0
|
||
next_obs = self.reset()
|
||
else:
|
||
next_obs = self._build_state()
|
||
return current_obs, next_obs, float(reward), finish
|
||
|
||
def _load_year_data(self):
|
||
data_df = pd.read_csv('data/all_data.csv', sep=',')
|
||
solar = data_df['solar_power'].to_numpy(dtype=float)
|
||
temper = data_df['temper'].to_numpy(dtype=float)
|
||
energy = data_df['energy_demand'].to_numpy(dtype=float)
|
||
water = data_df['water_demand'].to_numpy(dtype=float)
|
||
people = data_df['people_count'].to_numpy(dtype=float)
|
||
price = data_df['price'].to_numpy(dtype=float)
|
||
|
||
'''可根据需求重新设计训练数据大小'''
|
||
|
||
def process_elements(elements, transform_function, add_function):
|
||
for e in elements:
|
||
transformed_e = transform_function(e)
|
||
add_function(transformed_e)
|
||
|
||
process_elements(solar, lambda x: x, self.data_manager.add_load_element)
|
||
process_elements(temper, lambda x: x, self.data_manager.add_load_element)
|
||
process_elements(energy, lambda x: x, self.data_manager.add_irradiance_element)
|
||
process_elements(water, lambda x: x, self.data_manager.add_temperature_element)
|
||
process_elements(people, lambda x: x, self.data_manager.add_wind_element)
|
||
process_elements(price, lambda x: x, self.data_manager.add_price_element)
|