ax.set_xlabel(r'$t\,/\,\mathrm{s}$') ax.set_ylabel('$i_{\mathrm{abc}}\,/\,\mathrm{A}$') ax.grid(which='both') plt.legend(handles=ax.lines[::3], labels=('Measurement abc', 'Setpoint dq0')) fig.show() # Define the environment env = gym.make( 'openmodelica_microgrid_gym:ModelicaEnv_test-v1', viz_mode='episode', viz_cols=[ PlotTmpl( [[f'lcl1.inductor{i}.i' for i in '123'], [f'slave.SPI{i}' for i in 'dq0']], callback=update_legend, color=[['b', 'r', 'g'], ['b', 'r', 'g']], style=[[None], ['--']], title= 'Example of using an timevariant external current reference'), ], log_level=logging.INFO, max_episode_steps=max_episode_steps, model_params={ 'rl1.resistor1.R': partial(load_step, gain=20), 'rl1.resistor2.R': partial(load_step, gain=20), 'rl1.resistor3.R': partial(load_step, gain=20), 'rl1.inductor1.L': 0.001, 'rl1.inductor2.L': 0.001, 'rl1.inductor3.L': 0.001 }, model_path='../omg_grid/grid.network.fmu',
r_filt.reset() l_filt.reset() c_filt.reset() plotter = PlotManager(agent, save_results=save_results, save_folder=save_folder, show_plots=show_plots) env = gym.make( 'openmodelica_microgrid_gym:ModelicaEnv_test-v1', reward_fun=rew.rew_fun_vc, viz_cols=[ PlotTmpl([[f'lc.capacitor{i}.v' for i in '123'], [f'master.SPV{i}' for i in 'abc']], callback=plotter.xylables_v_abc, color=[['b', 'r', 'g'], ['b', 'r', 'g']], style=[[None], ['--']]), PlotTmpl([[f'master.CVV{i}' for i in 'dq0'], [f'master.SPV{i}' for i in 'dq0']], callback=plotter.xylables_v_dq0, color=[['b', 'r', 'g'], ['b', 'r', 'g']], style=[[None], ['--']]), PlotTmpl([[f'lc.inductor{i}.i' for i in '123'], [f'master.SPI{i}' for i in 'abc']], callback=plotter.xylables_i_abc, color=[['b', 'r', 'g'], ['b', 'r', 'g']], style=[[None], ['--']]), PlotTmpl( [ [f'master.I_hat{i}' for i in 'abc'],
def xylables_freq(fig): ax = fig.gca() ax.set_xlabel(r'$t\,/\,\mathrm{s}$') ax.set_ylabel('$f_{\mathrm{slave}}\,/\,\mathrm{Hz}$') ax.grid(which='both') time = strftime("%Y-%m-%d %H_%M_%S", gmtime()) fig.savefig(save_folder + '/f_slave' + time + '.pdf') env = gym.make('openmodelica_microgrid_gym:ModelicaEnv_test-v1', reward_fun=Reward().rew_fun, viz_cols=[ PlotTmpl([f'lc1.inductor{i}.i' for i in '123'], callback=xylables_i ), PlotTmpl([f'lc1.capacitor{i}.v' for i in '123'], callback=xylables_v_abc ), PlotTmpl([f'master.instPow'], callback=xylables_P_master ), PlotTmpl([f'slave.instPow'], callback=xylables_P_slave ), PlotTmpl([f'slave.freq'], callback=xylables_freq ), PlotTmpl([f'master.CVV{i}' for i in 'dq0'], callback=xylables_v_dq0
# - inputs to the models are the connection points to the inverters (see user guide for more details) # - model outputs are the the 3 currents through the inductors and the 3 voltages across the capacitors def xylables(fig): ax = fig.gca() ax.set_xlabel(r'$t\,/\,\mathrm{s}$') ax.set_ylabel('$i_{\mathrm{abc}}\,/\,\mathrm{A}$') ax.grid(which='both') fig.show() # fig.savefig('Inductor_currents.pdf') env = gym.make('openmodelica_microgrid_gym:ModelicaEnv_test-v1', reward_fun=Reward().rew_fun, viz_cols=[ PlotTmpl([f'lc1.inductor{i}.i' for i in '123'], callback=xylables) ], log_level=logging.INFO, viz_mode='episode', max_episode_steps=max_episode_steps, net=net, model_path='../omg_grid/grid.network_singleInverter.fmu', history=FullHistory()) ##################################### # Execution of the experiment # Using a runner to execute 'num_episodes' different episodes (i.e. SafeOpt iterations) runner = Runner(agent, env) runner.run(num_episodes, visualise=True)
def xylables_v_dq0(fig): ax = fig.gca() ax.set_xlabel(r'$t\,/\,\mathrm{s}$') ax.set_ylabel('$v_{\mathrm{dq0}}\,/\,\mathrm{V}$') ax.grid(which='both') time = strftime("%Y-%m-%d %H_%M_%S", gmtime()) fig.savefig(save_folder + '/dq0_voltage' + time + '.pdf') env = gym.make('openmodelica_microgrid_gym:ModelicaEnv_test-v1', reward_fun=Reward().rew_fun, viz_cols=[ PlotTmpl([f'lc1.inductor{i}.i' for i in '123'], callback=xylables_i ), PlotTmpl([f'lc1.capacitor{i}.v' for i in '123'], callback=xylables_v_abc ), PlotTmpl([f'master.CVV{i}' for i in 'dq0'], callback=xylables_v_dq0 ) ], log_level=logging.INFO, viz_mode='episode', max_episode_steps=max_episode_steps, net=net, model_path='../omg_grid/grid.network_singleInverter.fmu', history=FullHistory() )
def xylables_i_dq0(fig): ax = fig.gca() ax.set_xlabel(r'$t\,/\,\mathrm{s}$') ax.set_ylabel('$i_{\mathrm{dq0}}\,/\,\mathrm{i}$') ax.grid(which='both') callback = LoadstepCallback() env = gym.make('openmodelica_microgrid_gym:ModelicaEnv_test-v1', reward_fun=Reward().rew_fun, viz_cols=[ PlotTmpl([f'lc1.inductor{i}.i' for i in '123'], callback=xylables ), PlotTmpl([f'rl1.resistor{i}.R' for i in '123'], callback=xylables_R ), PlotTmpl([f'master.CVI{s}' for s in 'dq0'], ), PlotTmpl([f'rl1.inductor{i}.L' for i in '123'], callback=xylables_L ) ], log_level=logging.INFO, viz_mode='episode', model_params={'rl1.resistor1.R': callback.load_step_resistance, # see LoadstepCallback(Callback) 'rl1.resistor2.R': callback.load_step_resistance, 'rl1.resistor3.R': callback.load_step_resistance,
if __name__ == '__main__': def second_plot(fig): ax = fig.gca() ax.set_ylabel('y label!') ax.set_xlabel('$t\,/\,\mathrm{ms}$') fig.savefig('plot2.pdf') env = gym.make('openmodelica_microgrid_gym:ModelicaEnv-v1', viz_mode='episode', viz_cols=[ PlotTmpl([f'lc1.inductor{i}.i' for i in '123'], callback=lambda fig: fig.savefig('plot.pdf'), linewidth=4, style=[None, '--', '*'], linestyle=['None', None, None], marker=[r'$\heartsuit$', None, None], c=['pink', None, None], title='test'), PlotTmpl(['lc1.inductor1.i', 'lc1.inductor2.i'], callback=second_plot, legend=[False, True], label=[None, 'something']) ], max_episode_steps=None, net='../net/net.yaml', model_path='../omg_grid/grid.network.fmu') env.reset() for _ in range(100): env.render()
if t >= .05: i_ref[:] = i_ref2 else: i_ref[:] = i_ref1 return partial(l_load.give_value, n=2)(t) env = gym.make('openmodelica_microgrid_gym:ModelicaEnv_test-v1', # reward_fun=Reward().rew_fun, reward_fun=rew.rew_fun_c, # time_step=delta_t, viz_cols=[ PlotTmpl([[f'lc.inductor{i}.i' for i in '123'], [f'master.SPI{i}' for i in 'abc']], callback=plotter.xylables_i_abc, color=[['b', 'r', 'g'], ['b', 'r', 'g']], style=[[None], ['--']] ), PlotTmpl([[f'master.m{i}' for i in 'abc']], callback=lambda fig: plotter.update_axes(fig, title='Simulation', ylabel='$m_{\mathrm{abc}}\,/\,\mathrm{}$') ), PlotTmpl([[f'master.CVI{i}' for i in 'dq0'], [f'master.SPI{i}' for i in 'dq0']], callback=plotter.xylables_i_dq0, color=[['b', 'r', 'g'], ['b', 'r', 'g']], style=[[None], ['--']] ) ], log_level=logging.INFO, viz_mode='episode',
import pytest from openmodelica_microgrid_gym.env import PlotTmpl v = [['a', 'b'], ['c', 'd']] tmpl = PlotTmpl(v, color=[None, ['C2', 'C1']], style=[None, '--']) @pytest.mark.parametrize( 'i,o', [[[k for k in PlotTmpl(v)], [('a', dict(c='C1')), ('b', dict(c='C2')), ('c', dict(c='C1')), ('d', dict(c='C2'))]], [[k for k in PlotTmpl(v, c=[None, ['C2', 'C1']])], [('a', dict(c='C1')), ('b', dict(c='C2')), ('c', dict(c='C2')), ('d', dict(c='C1'))]], [[k for k in PlotTmpl(v, color=[None, ['C2', 'C1']])], [('a', dict(color='C1')), ('b', dict(color='C2')), ('c', dict(color='C2')), ('d', dict(color='C1'))]], [tmpl[2], ('c', dict(color='C2', style='--'))], [tmpl[1], ('b', dict(color='C2'))]]) def test_plot_tmpl(i, o): assert i == o
ax.set_ylabel('$R_{\mathrm{load}}\,/\,\mathrm{\Omega}$') ax.grid(which='both') ax.set_ylim([lower_bound_load - 2, upper_bound_load + 2]) plt.title( 'Load example drawn from Ornstein-Uhlenbeck process \n- Clipping outside the shown y-range' ) plt.legend() fig.show() env = gym.make('openmodelica_microgrid_gym:ModelicaEnv_test-v1', net=net, model_params={ 'rl1.resistor1.R': load_step, 'rl1.resistor2.R': load_step, 'rl1.resistor3.R': load_step }, viz_cols=[ PlotTmpl([f'rl1.resistor{i}.R' for i in '123'], callback=xylables) ], model_path='../omg_grid/grid.network.fmu') env.reset() for _ in range(1000): env.render() obs, rew, done, info = env.step( env.action_space.sample()) # take a random action if done: break env.close()
ax.grid(which='both') time = strftime("%Y-%m-%d %H_%M_%S", gmtime()) fig.savefig(save_folder + '/dq0_voltage' + time + '.pdf') def xylables_L(fig): ax = fig.gca() ax.set_xlabel(r'$t\,/\,\mathrm{s}$') ax.set_ylabel('$L_{\mathrm{123}}\,/\,\mathrm{H}$') ax.grid(which='both') callback = LoadstepCallback() env = gym.make('openmodelica_microgrid_gym:ModelicaEnv_test-v1', reward_fun=Reward().rew_fun, viz_cols=[ PlotTmpl([f'lc1.inductor{i}.i' for i in '123'], callback=xylables_i), PlotTmpl([f'lc1.capacitor{i}.v' for i in '123'], callback=xylables_v_abc), PlotTmpl([f'rl1.resistor{i}.R' for i in '123'], callback=xylables_R), PlotTmpl([f'master.CVi{s}' for s in 'dq0'], callback=xylables_i_dq0), PlotTmpl([f'master.CVV{i}' for i in 'dq0'], callback=xylables_v_dq0), PlotTmpl([f'rl1.inductor{i}.L' for i in '123'], callback=xylables_L) ], log_level=logging.INFO, viz_mode='episode', model_params={ 'rl1.resistor1.R': callback.load_step_resistance,
r_filt.reset() l_filt.reset() c_filt.reset() plotter = PlotManager(agent, save_results=save_results, save_folder=save_folder, show_plots=show_plots) env = gym.make( 'openmodelica_microgrid_gym:ModelicaEnv_test-v1', reward_fun=rew.rew_fun_v, viz_cols=[ PlotTmpl([[f'lc.capacitor{i}.v' for i in '123'], [f'master.SPV{i}' for i in 'abc']], callback=plotter.xylables_v_abc, color=[['b', 'r', 'g'], ['b', 'r', 'g']], style=[[None], ['--']]), PlotTmpl([[f'master.CVV{i}' for i in 'dq0'], [f'master.SPV{i}' for i in 'dq0']], callback=plotter.xylables_v_dq0, color=[['b', 'r', 'g'], ['b', 'r', 'g']], style=[[None], ['--']]), PlotTmpl([[f'lc.inductor{i}.i' for i in '123'], [f'master.SPI{i}' for i in 'abc']], callback=plotter.xylables_i_abc, color=[['b', 'r', 'g'], ['b', 'r', 'g']], style=[[None], ['--']]), # PlotTmpl([[f'master.I_hat{i}' for i in 'abc'], [f'r_load.resistor{i}.i' for i in '123'], ], # callback=lambda fig: plotter.update_axes(fig, title='Simulation', # ylabel='$i_{\mathrm{o estimate,abc}}\,/\,\mathrm{A}$'),
def xylables_L(fig): ax = fig.gca() ax.set_xlabel(r'$t\,/\,\mathrm{s}$') # zeit ax.set_ylabel('$L_{\mathrm{123}}\,/\,\mathrm{H}$') ax.grid(which='both') callback = LoadstepCallback() env = gym.make('openmodelica_microgrid_gym:ModelicaEnv_test-v1', reward_fun=Reward().rew_fun, viz_cols=[ PlotTmpl([f'slave.freq'], callback=xylables_freq ), PlotTmpl([f'master.CVV{i}' for i in 'dq0'], callback=xylables_v_dq0 ), PlotTmpl([f'rl1.resistor{i}.R' for i in '123'], # Plot Widerstand RL callback=xylables_R ), PlotTmpl([f'rl1.inductor{i}.L' for i in '123'], # Plot Widerstand RL callback=xylables_L ), ], log_level=logging.INFO, viz_mode='episode', max_episode_steps=max_episode_steps, model_params={'rl1.resistor1.R': callback.load_step_resistance,
def run_experiment(len_kp, len_ki): if isfile(f'{save_folder}/{len_kp:.4f},{len_ki:.4f}.txt'): with open(f'{save_folder}/{len_kp:.4f},{len_ki:.4f}.txt', 'r') as f: return strtobool(f.read().strip()) rew = Reward(i_limit=iLimit, i_nominal=iNominal, mu_c=mu, max_episode_steps=max_episode_steps, obs_dict=[[f'lc.inductor{k}.i' for k in '123'], 'master.phase', [f'master.SPI{k}' for k in 'dq0']]) ##################################### # Definitions for the GP prior_mean = 0 # 2 # mean factor of the GP prior mean which is multiplied with the first performance of the # initial set noise_var = 0.001 # 0.001 ** 2 # measurement noise sigma_omega prior_var = 2 # prior variance of the GP bounds = None lengthscale = None if adjust == 'Kp': bounds = [(0.0001, 0.1)] # bounds on the input variable Kp lengthscale = [ .025 ] # length scale for the parameter variation [Kp] for the GP # For 1D example, if Ki should be adjusted if adjust == 'Ki': bounds = [(0, 20)] # bounds on the input variable Ki lengthscale = [ 10 ] # length scale for the parameter variation [Ki] for the GP # For 2D example, choose Kp and Ki as mutable parameters (below) and define bounds and lengthscale for both of them if adjust == 'Kpi': bounds = [(0.001, 0.07), (2, 150)] lengthscale = [0.012, 30.] df_len = pd.DataFrame({ 'lengthscale': lengthscale, 'bounds': bounds, 'balanced_load': balanced_load, 'barrier_param_mu': mu }) # The performance should not drop below the safe threshold, which is defined by the factor safe_threshold times # the initial performance: safe_threshold = 0.8 means. Performance measurement for optimization are seen as # unsafe, if the new measured performance drops below 20 % of the initial performance of the initial safe (!) # parameter set safe_threshold = 0 j_min = cal_j_min(phase_shift, amp_dev) # Used for normalization # The algorithm will not try to expand any points that are below this threshold. This makes the algorithm stop # expanding points eventually. # The following variable is multiplied with the first performance of the initial set by the factor below: explore_threshold = 0 # Factor to multiply with the initial reward to give back an abort_reward-times higher negative reward in case of # limit exceeded # has to be negative due to normalized performance (regarding J_init = 1) abort_reward = 100 * j_min # Definition of the kernel kernel = GPy.kern.Matern32(input_dim=len(bounds), variance=prior_var, lengthscale=lengthscale, ARD=True) ##################################### # Definition of the controllers mutable_params = None current_dqp_iparams = None if adjust == 'Kp': # mutable_params = parameter (Kp gain of the current controller of the inverter) to be optimized using # the SafeOpt algorithm mutable_params = dict(currentP=MutableFloat(0.04)) # Define the PI parameters for the current controller of the inverter current_dqp_iparams = PI_params(kP=mutable_params['currentP'], kI=12, limits=(-1, 1)) # For 1D example, if Ki should be adjusted elif adjust == 'Ki': mutable_params = dict(currentI=MutableFloat(5)) current_dqp_iparams = PI_params(kP=0.005, kI=mutable_params['currentI'], limits=(-1, 1)) # For 2D example, choose Kp and Ki as mutable parameters elif adjust == 'Kpi': mutable_params = dict(currentP=MutableFloat(0.04), currentI=MutableFloat(11.8)) current_dqp_iparams = PI_params(kP=mutable_params['currentP'], kI=mutable_params['currentI'], limits=(-1, 1)) # Define a current sourcing inverter as master inverter using the pi and droop parameters from above ctrl = MultiPhaseDQCurrentSourcingController(current_dqp_iparams, delta_t, undersampling=undersample, name='master', f_nom=net.freq_nom) i_ref = MutableParams([MutableFloat(f) for f in i_ref1]) ##################################### # Definition of the optimization agent # The agent is using the SafeOpt algorithm by F. Berkenkamp (https://arxiv.org/abs/1509.01066) in this example # Arguments described above # History is used to store results agent = SafeOptAgent( mutable_params, abort_reward, j_min, kernel, dict(bounds=bounds, noise_var=noise_var, prior_mean=prior_mean, safe_threshold=safe_threshold, explore_threshold=explore_threshold), [ctrl], dict(master=[[f'lc.inductor{k}.i' for k in '123'], i_ref]), history=FullHistory(), ) ##################################### # Definition of the environment using a FMU created by OpenModelica # (https://www.openmodelica.org/) # Using an inverter supplying a load # - using the reward function described above as callable in the env # - viz_cols used to choose which measurement values should be displayed (here, only the 3 currents across the # inductors of the inverters are plotted. Labels and grid is adjusted using the PlotTmpl (For more information, # see UserGuide) # - inputs to the models are the connection points to the inverters (see user guide for more details) # - model outputs are the the 3 currents through the inductors and the 3 voltages across the capacitors if include_simulate: # Defining unbalanced loads sampling from Gaussian distribution with sdt = 0.2*mean # r_load = Load(R, 0.1 * R, balanced=balanced_load, tolerance=0.1) # l_load = Load(L, 0.1 * L, balanced=balanced_load, tolerance=0.1) # i_noise = Noise([0, 0, 0], [0.0023, 0.0015, 0.0018], 0.0005, 0.32) # if no noise should be included: r_load = Load(R, 0 * R, balanced=balanced_load) l_load = Load(L, 0 * L, balanced=balanced_load) def reset_loads(): r_load.reset() l_load.reset() plotter = PlotManager(agent, save_results=save_results, save_folder=save_folder, show_plots=show_plots) def ugly_foo(t): if t >= .05: i_ref[:] = i_ref2 else: i_ref[:] = i_ref1 return partial(l_load.give_value, n=2)(t) env = gym.make( 'openmodelica_microgrid_gym:ModelicaEnv_test-v1', # reward_fun=Reward().rew_fun, reward_fun=rew.rew_fun_c, # time_step=delta_t, viz_cols=[ PlotTmpl([[f'lc.inductor{i}.i' for i in '123'], [f'master.SPI{i}' for i in 'abc']], callback=plotter.xylables_i_abc, color=[['b', 'r', 'g'], ['b', 'r', 'g']], style=[[None], ['--']]), PlotTmpl([[f'master.m{i}' for i in 'abc']], callback=lambda fig: plotter.update_axes( fig, title='Simulation', ylabel='$m_{\mathrm{abc}}\,/\,\mathrm{}$')), PlotTmpl([[f'master.CVI{i}' for i in 'dq0'], [f'master.SPI{i}' for i in 'dq0']], callback=plotter.xylables_i_dq0, color=[['b', 'r', 'g'], ['b', 'r', 'g']], style=[[None], ['--']]) ], log_level=logging.INFO, viz_mode='episode', max_episode_steps=max_episode_steps, model_params={ 'lc.resistor1.R': partial(r_load.give_value, n=0), 'lc.resistor2.R': partial(r_load.give_value, n=1), 'lc.resistor3.R': partial(r_load.give_value, n=2), 'lc.inductor1.L': partial(l_load.give_value, n=0), 'lc.inductor2.L': partial(l_load.give_value, n=1), 'lc.inductor3.L': ugly_foo }, model_path='../../omg_grid/grid.paper.fmu', # model_path='../omg_grid/omg_grid.Grids.Paper_SC.fmu', net=net, history=FullHistory(), action_time_delay=1 * undersample) runner = MonteCarloRunner(agent, env) runner.run(num_episodes, n_mc=n_MC, visualise=True, prepare_mc_experiment=reset_loads) with open(f'{save_folder}/{len_kp:.4f},{len_ki:.4f}.txt', 'w') as f: print(f'{agent.unsafe}', file=f) return agent.unsafe