diff --git a/tools.py b/tools.py index fc57326..99c4322 100644 --- a/tools.py +++ b/tools.py @@ -4,6 +4,7 @@ import numpy as np import numpy.random as rd import pandas as pd import torch +import json from gurobipy import GRB @@ -14,9 +15,6 @@ def optimization_base_result(env, month, day, initial_soc): irradiance = env.data_manager.get_series_irradiance_data(month, day) wind_speed = env.data_manager.get_series_wind_data(month, day) - pv = [env.solar.step(temp, irr) for temp, irr in zip(temperature, irradiance)] - wind = [env.wind.step(ws) for ws in wind_speed] - period = env.episode_length DG_parameters = env.dg_parameters @@ -28,7 +26,6 @@ def optimization_base_result(env, month, day, initial_soc): a_para = [] b_para = [] c_para = [] - for name, gen_info in parameters.items(): p_max.append(gen_info['power_output_max']) p_min.append(gen_info['power_output_min']) @@ -44,7 +41,10 @@ def optimization_base_result(env, month, day, initial_soc): battery_capacity = env.battery.capacity battery_efficiency = env.battery.efficiency solar_cofficient = env.solar.opex_cofficient + volatage_change_percent = env.solar.change_percent wind_cofficient = env.wind.opex_cofficient + battery_degradation = env.battery.degradation + battery_holding = env.battery.holding m = gp.Model("UC") @@ -52,16 +52,24 @@ def optimization_base_result(env, month, day, initial_soc): on_off = m.addVars(NUM_GEN, period, vtype=GRB.BINARY, name='on_off') gen_output = m.addVars(NUM_GEN, period, vtype=GRB.CONTINUOUS, name='output') # 设置充放电约束 + soc = m.addVars(period, vtype=GRB.CONTINUOUS, lb=0.2, ub=0.8, name='SOC') battery_energy_change = m.addVars(period, vtype=GRB.CONTINUOUS, lb=-env.battery.max_charge, ub=env.battery.max_charge, name='battery_action') # 设置外部电网与能源系统交换约束 grid_energy_import = m.addVars(period, vtype=GRB.CONTINUOUS, lb=0, ub=env.grid.exchange_ability, name='import') grid_energy_export = m.addVars(period, vtype=GRB.CONTINUOUS, lb=0, ub=env.grid.exchange_ability, name='export') - soc = m.addVars(period, vtype=GRB.CONTINUOUS, lb=0.2, ub=0.8, name='SOC') + # 设置电压控制约束 + pv_voltage = m.addVars(period, vtype=GRB.CONTINUOUS, lb=-1, ub=1, name='pv_voltage') + + # 计算光伏和风力发电量 + pv = [(0.2 * irradiance[t] + 0.05 * temperature[t] - 9.25) * + (1 + volatage_change_percent * pv_voltage[t]) for t in range(period)] + wind = [172.265625 * wind_speed[t] ** 3 / 1e3 if 3 <= wind_speed[t] < 8 + else (172.265625 * 8 ** 3 / 1e3 if 8 <= wind_speed[t] < 12 else 0) for t in range(period)] # 1. 添加平衡约束 - m.addConstrs(((sum(gen_output[g, t] for g in range(NUM_GEN)) + pv[t] + wind[t] + grid_energy_import[t] >= load[t] + - battery_energy_change[t] + grid_energy_export[t]) for t in range(period)), name='powerbalance') + m.addConstrs(((sum(gen_output[g, t] for g in range(NUM_GEN)) + pv[t] + wind[t] + grid_energy_import[t] >= load[t] + + battery_energy_change[t] + grid_energy_export[t]) for t in range(period)), name='powerbalance') # 2. 添加发电机最大/最小功率约束 m.addConstrs((gen_output[g, t] <= on_off[g, t] * p_max[g] for g in range(NUM_GEN) for t in range(period)), 'gen_output_max') @@ -81,14 +89,18 @@ def optimization_base_result(env, month, day, initial_soc): cost_gen = gp.quicksum( (a_para[g] * gen_output[g, t] * gen_output[g, t] + b_para[g] * gen_output[g, t] + c_para[g] * on_off[g, t]) for t in range(period) for g in range(NUM_GEN)) - cost_grid_import = gp.quicksum(grid_energy_import[t] * price[t] for t in range(period)) - cost_grid_export = gp.quicksum(grid_energy_export[t] * price[t] * env.sell_coefficient for t in range(period)) + cost_battery = gp.quicksum(battery_energy_change[t] * battery_degradation + soc[t] * battery_holding for t in range(period)) + cost_import = gp.quicksum(grid_energy_import[t] * price[t] for t in range(period)) + cost_export = gp.quicksum(grid_energy_export[t] * price[t] * env.sell_coefficient for t in range(period)) cost_solar = gp.quicksum(pv[t] * solar_cofficient for t in range(period)) cost_wind = gp.quicksum(wind[t] * wind_cofficient for t in range(period)) - m.setObjective((cost_gen + cost_grid_import - cost_grid_export + cost_solar + cost_wind), GRB.MINIMIZE) + m.setObjective((cost_gen + cost_battery + cost_import - cost_export + cost_solar + cost_wind), GRB.MINIMIZE) m.optimize() + # 记录数据便于绘图 + pv = [(0.2 * irradiance[t] + 0.05 * temperature[t] - 9.25) * + (1 + volatage_change_percent * pv_voltage[t].x) for t in range(period)] output_record = {'pv': [], 'wind': [], 'price': [], 'load': [], 'netload': [], 'soc': [], 'battery_energy_change': [], 'grid_import': [], 'grid_export': [], 'gen1': [], 'gen2': [], 'gen3': [], 'step_cost': []} @@ -96,8 +108,9 @@ def optimization_base_result(env, month, day, initial_soc): gen_cost = sum((on_off[g, t].x * ( a_para[g] * gen_output[g, t].x * gen_output[g, t].x + b_para[g] * gen_output[g, t].x + c_para[g])) for g in range(NUM_GEN)) - grid_import_cost = grid_energy_import[t].x * price[t] - grid_export_cost = grid_energy_export[t].x * price[t] * env.sell_coefficient + battery_cost = battery_energy_change[t].x * battery_degradation + soc[t].x * battery_holding + import_cost = grid_energy_import[t].x * price[t] + export_cost = grid_energy_export[t].x * price[t] * env.sell_coefficient solar_cost = pv[t] * solar_cofficient wind_cost = wind[t] * wind_cofficient output_record['pv'].append(pv[t]) @@ -112,7 +125,18 @@ def optimization_base_result(env, month, day, initial_soc): output_record['gen1'].append(gen_output[0, t].x) output_record['gen2'].append(gen_output[1, t].x) output_record['gen3'].append(gen_output[2, t].x) - output_record['step_cost'].append(gen_cost + grid_import_cost - grid_export_cost + solar_cost + wind_cost) + output_record['step_cost'].append(gen_cost + battery_cost + import_cost - export_cost + solar_cost + wind_cost) + + # 记录动作便于辅助决策 + results = [] + for t in range(period): + action = [battery_energy_change[t].x/100, (gen_output[0, t].x - (gen_output[0, t-1].x if t > 0 else 0))/100, + (gen_output[1, t].x - (gen_output[1, t-1].x if t > 0 else 0))/100, + (gen_output[2, t].x - (gen_output[2, t-1].x if t > 0 else 0))/200, + pv_voltage[t].x - (pv_voltage[t-1].x if t > 0 else 0)] + results.append(action) + with open('./results.json', 'w') as f: + json.dump(results, f, indent=2) output_record_df = pd.DataFrame.from_dict(output_record) return output_record_df @@ -184,7 +208,7 @@ def test_one_episode(env, act, device): record_output = [] record_cost = [] record_unbalance = [] - record_system_info = [] # [time price,netload,action,real action, output*4,soc,unbalance(exchange+penalty)] + record_system_info = [] # [time,price,netload,action,real action,soc,output*4,unbalance(exchange+penalty),cost] record_init_info = [] # include month,day,time,intial soc env.TRAIN = False state = env.reset() @@ -207,7 +231,8 @@ def test_one_episode(env, act, device): record_unbalance.append(env.unbalance) state = next_state # add information of last step dg1, dh2, dg3, soc - record_system_info[-1][7:10] = [env.final_step_outputs[0], env.final_step_outputs[1], env.final_step_outputs[2]] + record_system_info[-1][7:12] = [env.final_step_outputs[0], env.final_step_outputs[1], env.final_step_outputs[2], + env.final_step_outputs[4], env.final_step_outputs[5]] record_system_info[-1][5] = env.final_step_outputs[3] record = {'init_info': record_init_info, 'system_info': record_system_info, 'state': record_state, 'action': record_action, 'reward': record_reward, 'cost': record_cost, 'unbalance': record_unbalance,