def test_dc_permex_motor(): motor_state = ['i'] # list of state names motor_parameter = test_motor_parameter['DcPermEx']['motor_parameter'] nominal_values = test_motor_parameter['DcPermEx']['nominal_values'] # dict limit_values = test_motor_parameter['DcPermEx']['limit_values'] # dict # default initialization without parameters motor_1_default = make_module(ElectricMotor, 'DcPermEx') motor_2_default = DcPermanentlyExcitedMotor() # initialization parameters as dicts motor_1 = make_module(ElectricMotor, 'DcPermEx', motor_parameter=motor_parameter, nominal_values=nominal_values, limit_values=limit_values) motor_2 = DcPermanentlyExcitedMotor(motor_parameter, nominal_values, limit_values) motor_testing(motor_1_default, motor_2_default, motor_1, motor_2, motor_state, limit_values, nominal_values, motor_parameter) permex_motor_state_space_testing(motor_1_default, motor_2_default) permex_motor_state_space_testing(motor_1, motor_2) permex_motor_electrical_ode_testing(motor_1_default) permex_motor_electrical_ode_testing(motor_1)
def test_dc_shunt_motor(): """ tests the dc shunt motor class :return: """ # set up test parameter motor_state = ['i_a', 'i_e'] # list of state names motor_parameter = test_motor_parameter['DcShunt']['motor_parameter'] nominal_values = test_motor_parameter['DcShunt']['nominal_values'] # dict limit_values = test_motor_parameter['DcShunt']['limit_values'] # dict # default initialization of electric motor motor_1_default = make_module(ElectricMotor, 'DcShunt') motor_2_default = DcShuntMotor() motor_1 = make_module(ElectricMotor, 'DcShunt', motor_parameter=motor_parameter, nominal_values=nominal_values, limit_values=limit_values) motor_2 = DcShuntMotor(motor_parameter, nominal_values, limit_values) # test if both initializations work correctly for limits and nominal values motor_testing(motor_1_default, motor_2_default, motor_1, motor_2, motor_state, limit_values, nominal_values, motor_parameter) shunt_motor_state_space_testing(motor_1_default, motor_2_default) shunt_motor_state_space_testing(motor_1, motor_2) # test electrical_ode function shunt_motor_electrical_ode_testing(motor_1_default) shunt_motor_electrical_ode_testing(motor_1)
def test_discrete_single_initializations(convert, convert_class, tau, interlocking_time, dead_time): """ test of both ways of initialization lead to the same result :param convert: string name of the converter :param convert_class: class name of the converter :return: """ # test default initialization converter_1 = make_module(PowerElectronicConverter, convert) converter_2 = convert_class() assert converter_1._tau == converter_2._tau # test with different parameters interlocking_time *= tau # initialize converters converter_1 = make_module(PowerElectronicConverter, convert, tau=tau, interlocking_time=interlocking_time, dead_time=dead_time) converter_2 = convert_class( tau=tau, interlocking_time=interlocking_time, dead_time=dead_time) parameter = str(tau) + " " + str(dead_time) + " " + str(interlocking_time) # test if they are equal assert converter_1.reset() == converter_2.reset() assert converter_1.action_space == converter_2.action_space assert converter_1._tau == converter_2._tau == tau, "Error (tau): " + parameter assert converter_1._dead_time == converter_2._dead_time == dead_time, "Dead time Error" assert converter_1._interlocking_time == converter_2._interlocking_time == interlocking_time, \ "Error (interlocking): " + parameter
def setup_dc_converter(conv, motor_type): """ This function initializes the converter. It differentiates between single and double converter and can be used for discrete and continuous converters. :param conv: converter name (string) :param motor_type: motor name (string) :return: initialized converter """ if motor_type == 'DcExtEx': # setup double converter if 'Disc' in conv: double_converter = 'Disc-Double' else: double_converter = 'Cont-Double' converter = make_module(PowerElectronicConverter, double_converter, interlocking_time=converter_parameter['interlocking_time'], dead_time=converter_parameter['dead_time'], subconverters=[make_module(PowerElectronicConverter, conv, tau=converter_parameter['tau'], dead_time=converter_parameter['dead_time'], interlocking_time=converter_parameter['interlocking_time']), make_module(PowerElectronicConverter, conv, tau=converter_parameter['tau'], dead_time=converter_parameter['dead_time'], interlocking_time=converter_parameter['interlocking_time'])]) else: # setup single converter converter = make_module(PowerElectronicConverter, conv, tau=converter_parameter['tau'], dead_time=converter_parameter['dead_time'], interlocking_time=converter_parameter['interlocking_time']) return converter
def test_visualization(motor_type, converter_type, plotted_variables, turn_off_windows): """ test initialization and basic functions for all motor and converters :param motor_type: motor name (string) :param converter_type: converter name (string) :param plotted_variables: shown variables (list/True/False) :return: """ # set parameters update_period = 1E-2 visu_period = 0.1 # setup physical system physical_system = setup_physical_system(motor_type, converter_type) # setup reference generator reference_generator = setup_reference_generator('SinusReference', physical_system) # setup reward function reward_function = make_module(RewardFunction, 'WSE') reward_function.set_modules(physical_system, reference_generator) # initializations of dashboards in different ways dashboard_default = MotorDashboard() dashboard_make = make_module(ElectricMotorVisualization, 'MotorDashboard', visu_period=visu_period, update_period=update_period, plotted_variables=plotted_variables) dashboard_1 = MotorDashboard(visu_period=visu_period, update_period=update_period, plotted_variables=plotted_variables) # setup state, reference, reward for testing len_state = len(physical_system.state_names) reference = physical_system.state_space.low reward = -0.5 dashboards = [dashboard_default, dashboard_make, dashboard_1] # test references given in each step for dashboard in dashboards: if plotted_variables == ['none' ] and dashboard is not dashboard_default: with pytest.warns(Warning): dashboard.set_modules(physical_system, reference_generator, reward_function) dashboard.reset() dashboard.step(physical_system.state_space.sample(), physical_system.state_space.sample(), 0) else: dashboard.set_modules(physical_system, reference_generator, reward_function) dashboard.reset() dashboard.step(physical_system.state_space.sample(), physical_system.state_space.sample(), 0) for k in range(2): state = np.ones(len_state) * np.sin(k / 1000) / 2 + 0.5 dashboard.step(state, reference, reward) dashboard.close()
def test_visualization_parameter(motor_type, converter_type, plotted_variables, update_period, visu_period, turn_off_windows): """ test visu period and update period :param motor_type: motor name (string) :param converter_type: converter name (string) :param plotted_variables: shown variables (list/True/False) :param update_period: update period from dashboard :param visu_period: visu period from dashboard :return: """ # setup physical system physical_system = setup_physical_system(motor_type, converter_type) # setup reference generator reference_generator = setup_reference_generator('StepReference', physical_system) # setup reward function reward_function = make_module(RewardFunction, 'WSE') reward_function.set_modules(physical_system, reference_generator) # initializations of dashboards in different ways dashboard = MotorDashboard(plotted_variables=plotted_variables, update_period=update_period, visu_period=visu_period) # setup the modules dashboard.set_modules(physical_system, reference_generator, reward_function) # test for given references in the reset dashboard.reset() reward = 0 len_state = len(physical_system.state_names) for k in range(150): state = np.ones(len_state) * np.sin(k / 1000) / 2 + 0.5 reference = np.ones(len_state) * np.cos(k / 2000) / 2 + 0.5 dashboard.step(state, reference, reward) dashboard.close()
def test_visualization_plotted_variables(motor_type, converter_type, plotted_variables, turn_off_windows): """ test initialization and basic functions for all motor and converters :param motor_type: motor name (string) :param converter_type: converter name (string) :param plotted_variables: shown variables (list/True/False) :return: """ # setup physical system physical_system = setup_physical_system(motor_type, converter_type) # setup reference generator reference_generator = setup_reference_generator('SinusReference', physical_system) # setup reward function reward_function = make_module(RewardFunction, 'WSE') reward_function.set_modules(physical_system, reference_generator) # initializations of dashboards in different ways dashboard_default = MotorDashboard(plotted_variables=plotted_variables) # test for warning with pytest.warns(Warning): dashboard_default.set_modules(physical_system, reference_generator, reward_function) dashboard_default.reset() dashboard_default.step(physical_system.state_space.sample(), physical_system.state_space.sample(), 0) dashboard_default.close()
def test_discrete_single_power_electronic_converter(converter_type, action_space_n, actions, i_ins, test_voltages, dead_time, interlocking_time, tau): """ test the initialization of all single converters for different tau, interlocking times, dead times furthermore, test the other functions: reset, convert with different parameters :param converter_type: converter name (string) :param action_space_n: number of elements in the action space :param actions: pre defined actions for testing :param i_ins: used input currents for testing :param test_voltages: expected voltages for ideal and non ideal behaviour :param dead_time: specifies if a dead time is considered or not :param interlocking_time: the used interlocking time :param tau: sampling time :return: """ # test with default initialization converter = make_module(PowerElectronicConverter, converter_type) g_times = g_times_4qc times = g_times * converter._tau discrete_converter_functions_testing(converter, action_space_n, times, actions, i_ins, test_voltages[0], test_voltages[1], test_voltages[2], test_voltages[3]) # define various constants for test times = g_times * tau interlocking_time *= tau # setup converter # initialize converter with given parameter converter = make_module(PowerElectronicConverter, converter_type, tau=tau, interlocking_time=interlocking_time, dead_time=dead_time) assert converter.reset() == [0.0] # test if reset returns 0.0 # test the conversion function of the converter discrete_converter_functions_testing(converter, action_space_n, times, actions, i_ins, test_voltages[0], test_voltages[1], test_voltages[2], test_voltages[3], interlocking_time=interlocking_time, dead_time=dead_time)
def setup_physical_system(motor_type, converter_type, three_phase=False): """ Function to set up a physical system with test parameters :param motor_type: motor name (string) :param converter_type: converter name (string) :param three_phase: if True, than a synchronous motor system will be instantiated :return: instantiated physical system """ # get test parameter tau = converter_parameter['tau'] u_sup = test_motor_parameter[motor_type]['motor_parameter']['u_sup'] motor_parameter = test_motor_parameter[motor_type]['motor_parameter'] # dict nominal_values = test_motor_parameter[motor_type]['nominal_values'] # dict limit_values = test_motor_parameter[motor_type]['limit_values'] # dict # setup load load = PolynomialStaticLoad(load_parameter=load_parameter['parameter']) # setup voltage supply voltage_supply = IdealVoltageSupply(u_sup) # setup converter if motor_type == 'DcExtEx': if 'Disc' in converter_type: double_converter = 'Disc-Double' else: double_converter = 'Cont-Double' converter = make_module(PowerElectronicConverter, double_converter, subconverters=[converter_type, converter_type], tau=converter_parameter['tau'], dead_time=converter_parameter['dead_time'], interlocking_time=converter_parameter['interlocking_time']) else: converter = make_module(PowerElectronicConverter, converter_type, tau=converter_parameter['tau'], dead_time=converter_parameter['dead_time'], interlocking_time=converter_parameter['interlocking_time']) # setup motor motor = make_module(ElectricMotor, motor_type, motor_parameter=motor_parameter, nominal_values=nominal_values, limit_values=limit_values) # setup solver solver = ScipySolveIvpSolver(method='RK45') # combine all modules to a physical system if three_phase: physical_system = SynchronousMotorSystem(converter=converter, motor=motor, ode_solver=solver, supply=voltage_supply, load=load, tau=tau) else: physical_system = DcMotorSystem(converter=converter, motor=motor, ode_solver=solver, supply=voltage_supply, load=load, tau=tau) return physical_system
def setup_reward_function(reward_function_type, physical_system, reference_generator, reward_weights, observed_states): reward_function = make_module(RewardFunction, reward_function_type, observed_states=observed_states, reward_weights=reward_weights) reward_function.set_modules(physical_system, reference_generator) return reward_function
def test_discrete_double_power_electronic_converter(tau, interlocking_time, dead_time): """ setup all combinations of single converters and test the convert function if no error is raised :return: """ # define all converter all_single_disc_converter = ['Disc-1QC', 'Disc-2QC', 'Disc-4QC'] interlocking_time *= tau for conv_1 in all_single_disc_converter: for conv_2 in all_single_disc_converter: converter = make_module( PowerElectronicConverter, 'Disc-Double', tau=tau, interlocking_time=interlocking_time, dead_time=dead_time, subconverters=[conv_1, conv_2] ) comparable_converter_1 = make_module(PowerElectronicConverter, conv_1, tau=tau, interlocking_time=interlocking_time, dead_time=dead_time) comparable_converter_2 = make_module(PowerElectronicConverter, conv_2, tau=tau, interlocking_time=interlocking_time, dead_time=dead_time) action_space_n = converter.action_space.n assert converter.reset() == [0.0, 0.0] # test if reset returns 0.0 actions = [randint(0, action_space_n) for _ in range(100)] times = np.arange(100) * tau action_space_1_n = comparable_converter_1.action_space.n action_space_2_n = comparable_converter_2.action_space.n for action, t in zip(actions, times): time_steps = converter.set_action(action, t) time_steps_1 = comparable_converter_1.set_action(action % action_space_1_n, t) time_steps_2 = comparable_converter_2.set_action((action // action_space_1_n) % action_space_2_n, t) for time_step in time_steps_1 + time_steps_2: assert time_step in time_steps for time_step in time_steps: i_in_1 = uniform(-1, 1) i_in_2 = uniform(-1, 1) i_in = [i_in_1, i_in_2] voltage = converter.convert(i_in, time_step) voltage_1 = comparable_converter_1.convert([i_in_1], time_step) voltage_2 = comparable_converter_2.convert([i_in_2], time_step) converter.i_sup(i_in) assert voltage[0] == voltage_1[0], "First converter is wrong" assert voltage[1] == voltage_2[0], "Second converter is wrong"
def setup_reference_generator(reference_type, physical_system, reference_state='omega'): """ Function to setup the reference generator :param reference_type: name of reference generator :param physical_system: instantiated physical system :param reference_state: referenced state name (string) :return: instantiated reference generator """ reference_generator = make_module(ReferenceGenerator, reference_type, reference_state=reference_state) reference_generator.set_modules(physical_system) reference_generator.reset() return reference_generator
def test_visualization_reset(motor_type, converter_type, plotted_variables, update_period, visu_period, turn_off_windows): """ test reset with given references :param motor_type: motor name (string) :param converter_type: converter name (string) :param plotted_variables: shown variables (list/True/False) :param update_period: update period from dashboard :param visu_period: visu period from dashboard :return: """ # setup physical system physical_system = setup_physical_system(motor_type, converter_type) # setup reference generator reference_generator = setup_reference_generator('WienerProcessReference', physical_system) # setup reward function reward_function = make_module(RewardFunction, 'WSE') reward_function.set_modules(physical_system, reference_generator) # initializations of dashboards in different ways dashboard = MotorDashboard(plotted_variables=plotted_variables, update_period=update_period, visu_period=visu_period) # setup the modules dashboard.set_modules(physical_system, reference_generator, reward_function) # test for given references in the reset len_state = len(physical_system.state_names) # setup different pre defined references len_reference = 1000 reference_basic = np.ones((len_state, len_reference)) references_1 = reference_basic references_1[0, :] *= physical_system.limits[0] * 0.8 references_1[1, :] = None references_2 = reference_basic[:len_state, :] * 0.5 references_2[2, :] = None references_3 = reference_basic reset_args = [references_1, references_2, references_3, None] # test for given references in the reset for reset_arg in reset_args: dashboard.reset(reset_arg) for k in range(50): state = np.ones(len_state) * np.sin(k / 1000) / 2 + 0.5 dashboard.step(state, None, None) # test reset() and step function with step reference dashboard.reset() for k in range(50): state = np.ones(len_state) * np.sin(k / 1000) / 2 + 0.5 reference_generator.get_reference_observation() reference = reference_generator.get_reference() dashboard.step(state, reference, None) dashboard.close()
def test_dc_series_motor(): motor_state = ['i', 'i'] # list of state names motor_parameter = test_motor_parameter['DcSeries']['motor_parameter'] nominal_values = test_motor_parameter['DcSeries']['nominal_values'] # dict limit_values = test_motor_parameter['DcSeries']['limit_values'] # dict # default initialization motor_1_default = make_module(ElectricMotor, 'DcSeries') motor_2_default = DcSeriesMotor() # initialization parameters as dicts motor_1 = make_module(ElectricMotor, 'DcSeries', motor_parameter=motor_parameter, nominal_values=nominal_values, limit_values=limit_values) motor_2 = DcSeriesMotor(motor_parameter, nominal_values, limit_values) motor_testing(motor_1_default, motor_2_default, motor_1, motor_2, motor_state, limit_values, nominal_values, motor_parameter) series_motor_state_space_testing(motor_1_default, motor_2_default) series_motor_state_space_testing(motor_1, motor_2) series_motor_electrical_ode_testing(motor_1_default) series_motor_electrical_ode_testing(motor_1)
def test_make_module(monkeypatch): registry = {} monkeypatch.setattr(utils, "_registry", registry) utils.register_superclass(core.PhysicalSystem) utils.register_class(dummies.DummyPhysicalSystem, core.PhysicalSystem, 'DummySystem') kwargs = dict(a=0, b=5) dummy_sys = utils.make_module(core.PhysicalSystem, 'DummySystem', **kwargs) assert isinstance(dummy_sys, dummies.DummyPhysicalSystem) assert dummy_sys.kwargs == kwargs with pytest.raises(Exception): _ = registry[core.ReferenceGenerator]['DummySystem'] with pytest.raises(Exception): _ = registry[core.PhysicalSystem]['NonExistingKey']
def test_shifted_weighted_sum_of_errors(normed, reward_power, motor_type, converter_type, number_reward_weights): """ Test the ShiftedWeightedSumOfErrors Class :param normed: specifies if the reward is normed (True/False) :param reward_power: specifies the used power order (int) :param motor_type: motor name (string) :param converter_type: converter name (string :param number_reward_weights: specifies how many states are considered for the reward :return: """ # setup physical system and reference generator physical_system = setup_physical_system(motor_type, converter_type) reference_generator = setup_reference_generator('SinusReference', physical_system) reference_generator.reset() len_state = len(physical_system.state_names) state = np.ones(len_state) # * physical_system.limits reference = physical_system.state_space.low # * physical_system.limits # set parameter gamma = 0.99 observed_states = physical_system.state_names reward_weights_dict = test_motor_parameter[motor_type]['reward_weights'] # setup reward functions reward_fct_default = ShiftedWeightedSumOfErrors() reward_fct_1 = ShiftedWeightedSumOfErrors(reward_weights_dict, normed, observed_states, gamma, reward_power) reward_fct_2 = ShiftedWeightedSumOfErrors(reward_weights=reward_weights_dict, normed=normed, observed_states=observed_states, gamma=gamma, reward_power=reward_power) reward_fct_3 = make_module(RewardFunction, 'SWSE', observed_states=observed_states, reward_weights=reward_weights_dict) reward_fct_list = [reward_fct_default, reward_fct_1, reward_fct_2, reward_fct_3] # test reset, reward, close function for index, reward_fct in enumerate(reward_fct_list): reward_fct.set_modules(physical_system, reference_generator) reward_fct.reset() assert reward_fct.reward_range[0] == 0, 'Wrong reward range lower limit' assert reward_fct.reward_range[1] > 0, 'Wrong reward range upper limit ' rew, done = reward_fct.reward(state, reference) assert done == 0 assert reward_fct.reward_range[0] <= rew <= reward_fct.reward_range[1], "Reward out of range" # test limit violation exceeding_state = 1.2 * state rew, done = reward_fct.reward(exceeding_state, reference) if index > 0: assert done == 1 assert rew == 0 else: assert done == 0 reward_fct.close()
def test_continuous_power_electronic_converter(converter_type, tau, interlocking_time, dead_time): """ test the functions and especially the conversion of continuous single converter :param converter_type: :return: """ interlocking_time *= tau # setup converter converter = make_module(PowerElectronicConverter, converter_type, tau=tau, interlocking_time=interlocking_time, dead_time=dead_time) assert converter.reset() == [0.0], "Error reset function" action_space = converter.action_space # take 100 random actions seed(123) actions = [[uniform(action_space.low, action_space.high)] for _ in range(len(g_times_cont))] times = g_times_cont * tau continuous_converter_functions_testing(converter, times, interlocking_time, dead_time, actions, converter_type)
def test_discrete_double_converter_initializations(tau, interlocking_time, dead_time): """ tests different initializations of the converters :return: """ # define all converter all_single_disc_converter = ['Disc-1QC', 'Disc-2QC', 'Disc-4QC'] interlocking_time *= tau # chose every combination of single converters for conv_1 in all_single_disc_converter: for conv_2 in all_single_disc_converter: converter = make_module( PowerElectronicConverter, 'Disc-Double', tau=tau, interlocking_time=interlocking_time, dead_time=dead_time, subconverters=[conv_1, conv_2] ) # test if both converter have the same parameter assert converter._subconverters[0]._tau == converter._subconverters[1]._tau == tau assert converter._subconverters[0]._interlocking_time == converter._subconverters[1]._interlocking_time \ == interlocking_time assert converter._subconverters[0]._dead_time == converter._subconverters[1]._dead_time == dead_time
def test_continuous_double_power_electronic_converter(tau, interlocking_time, dead_time): """ test functions of continuous double converter :return: """ # define all converter all_single_cont_converter = ['Cont-1QC', 'Cont-2QC', 'Cont-4QC'] interlocking_time *= tau times = g_times_cont * tau for conv_1 in all_single_cont_converter: for conv_2 in all_single_cont_converter: # setup converter with all possible combinations converter = make_module(PowerElectronicConverter, 'Cont-Double', tau=tau, interlocking_time=interlocking_time, dead_time=dead_time, subconverters=[conv_1, conv_2]) assert all(converter.reset() == np.zeros(2)) action_space = converter.action_space seed(123) actions = [uniform(action_space.low, action_space.high) for _ in range(0, 100)] continuous_double_converter_functions_testing(converter, times, interlocking_time, dead_time, actions, [conv_1, conv_2])
def test_discrete_b6_bridge(): """ test discrete b6 bridge :return: """ tau = converter_parameter['tau'] # test default initializations converter_default_init_1 = make_module(PowerElectronicConverter, 'Disc-B6C') converter_default_init_2 = DiscB6BridgeConverter() assert converter_default_init_1._tau == 1E-5 for subconverter in converter_default_init_1._subconverters: assert subconverter._tau == 1E-5 assert subconverter._interlocking_time == 0 assert subconverter._dead_time is False # test default initialized converter converters_default = [converter_default_init_1, converter_default_init_2] for converter in converters_default: assert all(converter.reset() == -0.5 * np.ones(3)) assert converter._subconverters[0].action_space.n == 3 assert converter.action_space.n == 8 # 1 1 1 1 2 2 2 1 2 1 # Action for the converter actions_1 = [4, 5, 6, 7, 0, 1, 2, 5, 3, 6] actions_2 = [2, 3, 6, 7, 0, 1, 4, 2, 5, 6] actions_3 = [1, 3, 5, 7, 0, 2, 4, 3, 6, 5] actions = [actions_1, actions_2, actions_3] times = np.arange(len(actions[0])) * tau i_ins = [0.5, 0, -0.5, 0.5, 0.5, 0, -0.5, -0.5, 0.5, 0.5] u_out = np.array([1, 1, 1, 1, -1, -1, -1, 1, -1, 1]) # test each subconverter individually for k in range(3): converter.reset() step_counter = 0 i_in = [[0.5], [0], [-0.5]] for time, action, i_in_ in zip(times, actions[k], i_ins): time_steps = converter.set_action(action, time) for time_step in time_steps: i_in[k] = [i_in_] voltage = converter.convert(i_in, time_step) assert voltage[k] == 0.5 * u_out[step_counter], "Wrong action without dead time " + str( step_counter) step_counter += 1 # test parametrized converter converter_init_1 = make_module(PowerElectronicConverter, 'Disc-B6C', **converter_parameter) converter_init_2 = DiscB6BridgeConverter(**converter_parameter) assert converter_init_1._tau == converter_parameter['tau'] for subconverter in converter_init_1._subconverters: assert subconverter._tau == converter_parameter['tau'] assert subconverter._interlocking_time == converter_parameter['interlocking_time'] assert subconverter._dead_time == converter_parameter['dead_time'] # set parameter actions = [6, 6, 4, 5, 1, 2, 3, 7, 0, 4] i_ins = [[[0.5], [0.5], [-0.5]], [[0], [0.5], [0]], [[-0.5], [0.5], [-0.5]], [[0.5], [0.5], [0.5]], [[0.5], [0.5], [-0.5]], [[0], [-0.5], [0]], [[-0.5], [-0.5], [0.5]], [[-0.5], [-0.5], [-0.5]], [[0.5], [-0.5], [0]], [[0.5], [-0.5], [0.5]]] expected_voltage = np.array([[-1, -1, 1], [1, 1, -1], [1, 1, -1], [1, -1, -1], [1, -1, -1], [1, -1, 1], [1, -1, 1], [-1, -1, 1], [-1, -1, 1], [-1, 1, -1], [-1, 1, -1], [-1, 1, 1], [-1, 1, 1], [-1, 1, 1], [1, 1, 1], [-1, 1, -1], [-1, -1, -1]]) / 2 times = np.arange(len(actions)) * tau converters_init = [converter_init_1, converter_init_2] # test every initialized converter for a given action sequence for converter in converters_init: converter.reset() step_counter = 0 for time, action, i_in in zip(times, actions, i_ins): time_steps = converter.set_action(action, time) i_in = np.array(i_in) for time_step in time_steps: voltage = np.array(converter.convert(i_in, time_step)) converter.i_sup(i_in) assert all(voltage == expected_voltage[step_counter]), "Wrong voltage calculated " + str(step_counter) step_counter += 1
def test_continuous_b6_bridge(): converter_default_init_1 = ContB6BridgeConverter() converter_default_init_2 = make_module(PowerElectronicConverter, 'Cont-B6C') converters_default = [converter_default_init_1, converter_default_init_2] actions = np.array([[1, -1, 0.65], [0.75, -0.95, -0.3], [-0.25, 0.98, -1], [0.65, 0.5, -0.95], [-0.3, 0.5, 0.98], [-1, 1, 0.5], [-0.95, 0.75, 0.5], [0.98, -0.25, 1], [0.5, 0.65, 0.75], [0.5, -0.3, -0.25]]) i_ins = [[[0.5], [-0.2], [1]], [[-0.6], [-0.5], [0.8]], [[0.3], [0.4], [0.9]], [[-0.2], [0.7], [0.5]], [[-0.5], [1], [-0.6]], [[0.4], [0.8], [0.3]], [[0.7], [0.9], [-0.2]], [[1], [0.5], [-0.5]], [[0.8], [-0.6], [0.4]], [[0.9], [0.75], [0.7]]] times = np.arange(len(actions)) * 1E-4 for converter in converters_default: # parameter testing assert converter._tau == 1E-4 assert converter._dead_time is False assert converter._interlocking_time == 0 assert all(converter.reset() == -0.5 * np.ones(3)) assert converter.action_space.shape == (3,) assert all(converter.action_space.low == -1 * np.ones(3)) assert all(converter.action_space.high == 1 * np.ones(3)) for subconverter in converter._subconverters: assert subconverter._tau == 1E-4 assert subconverter._dead_time is False assert subconverter._interlocking_time == 0 # conversion testing for time, action, i_in in zip(times, actions, i_ins): i_in = np.array(i_in) i_sup = converter.i_sup(i_in) time_step = converter.set_action(action, time) voltages = converter.convert(i_in, time_step) for voltage, single_action in zip(voltages, action): assert abs(voltage[0] - single_action / 2) < 1E-9 # testing parametrized converter expected_voltages = np.array([[-5, -4.95, -5], [5, -4.95, 3.2], [3.7, -4.8, -1.55], [-1.2, 4.85, -5], [3.3, 2.45, -4.7], [-1.55, 2.45, 4.85], [-5, 4.95, 2.55], [-4.8, 3.7, 2.55], [4.85, -1.2, 4.95], [2.45, 3.2, 3.7]]) / 10 converter_init_1 = ContB6BridgeConverter(**converter_parameter) converter_init_2 = make_module(PowerElectronicConverter, 'Cont-B6C', **converter_parameter) converters = [converter_init_1, converter_init_2] for converter in converters: # parameter testing assert converter._tau == converter_parameter['tau'] assert converter._dead_time == converter_parameter['dead_time'] assert converter._interlocking_time == converter_parameter['interlocking_time'] assert all(converter.reset() == -0.5 * np.ones(3)) assert converter.action_space.shape == (3,) assert all(converter.action_space.low == -1 * np.ones(3)) assert all(converter.action_space.high == 1 * np.ones(3)) for subconverter in converter._subconverters: assert subconverter._tau == converter_parameter['tau'] assert subconverter._dead_time == converter_parameter['dead_time'] assert subconverter._interlocking_time == converter_parameter['interlocking_time'] # conversion testing for time, action, i_in, expected_voltage in zip(times, actions, i_ins, expected_voltages): i_in = np.array(i_in) time_step = converter.set_action(action.tolist(), time) voltages = converter.convert(i_in, time_step) for voltage, test_voltage in zip(voltages, expected_voltage): assert abs(voltage - test_voltage) < 1E-9
def setup_sub_generator(generator, **kwargs): return make_module(ReferenceGenerator, generator, **kwargs)
def test_synchronous_motor_testing(motor_type, motor_class): """ testing the synrm and pmsm consider that it uses dq coordinates and the state is [i_q, i_d, epsilon]!!. The same goes with the voltages u_qd and not as usual dq!! :return: """ parameter = test_motor_parameter[motor_type] # use this values for testing state = np.array([0.5, 0.3, 0.68]) # i_q, i_d, epsilon u_qd = np.array([200, 50]) omega = 25 # test default initialization first default_init_1 = make_module(ElectricMotor, motor_type) default_init_2 = motor_class() # test parameters assert default_init_1.motor_parameter == default_init_2.motor_parameter assert default_init_1.nominal_values == default_init_2.nominal_values assert default_init_1.limits == default_init_2.limits # test functions mp = default_init_1.motor_parameter if motor_type == 'SynRM': mp.update({'psi_p': 0}) for motor in [default_init_1, default_init_2]: assert motor.torque(state) == torque_testing(state, mp) assert all(motor.i_in(state) == state[0:2]) ode = motor.electrical_ode(state, u_qd, omega) test_ode = synchronous_motor_ode_testing(state, u_qd, omega, mp) assert sum(abs(ode - test_ode)) < 1E-8, "Motor ode is wrong: " + str( [ode, test_ode]) # test parametrized motors motor_init_1 = make_module(ElectricMotor, motor_type, motor_parameter=parameter['motor_parameter'], nominal_values=parameter['nominal_values'], limit_values=parameter['limit_values']) motor_init_2 = motor_class(motor_parameter=parameter['motor_parameter'], nominal_values=parameter['nominal_values'], limit_values=parameter['limit_values']) for motor in [motor_init_1, motor_init_2]: # test motor parameter assert motor.motor_parameter == parameter['motor_parameter'], "Different Parameter: " + \ str([motor.motor_parameter, parameter['motor_parameter']]) mp = motor.motor_parameter if motor_type == 'SynRM': mp.update({'psi_p': 0}) # test limits factor_abc_to_alpha_beta = 1 for limit_key in motor_init_1.limits.keys(): if 'i_' in limit_key: assert motor_init_1.limits[limit_key] == parameter['limit_values']['i'] or \ motor_init_1.limits[limit_key] == factor_abc_to_alpha_beta * parameter['limit_values']['i'] if 'u_' in limit_key: assert motor_init_1.limits[limit_key] == parameter['limit_values']['u'] or \ motor_init_1.limits[limit_key] == .5 * factor_abc_to_alpha_beta * parameter['limit_values']['u']\ or motor_init_1.limits[limit_key] == .5 * parameter['limit_values']['u'] if limit_key in parameter['limit_values'].keys(): assert motor_init_1.limits[limit_key] == parameter[ 'limit_values'][limit_key] if 'i_' in limit_key: assert motor_init_1.nominal_values[limit_key] == parameter['nominal_values']['i'] or \ motor_init_1.nominal_values[limit_key] == factor_abc_to_alpha_beta\ * parameter['nominal_values']['i'] if 'u_' in limit_key: assert motor_init_1.nominal_values[limit_key] == 0.5 * factor_abc_to_alpha_beta * \ parameter['nominal_values']['u'] or \ motor_init_1.nominal_values[limit_key] == parameter['nominal_values']['u'] \ or motor_init_1.nominal_values[limit_key] == .5 * parameter['nominal_values']['u'] if limit_key in parameter['nominal_values'].keys(): assert motor_init_1.nominal_values[limit_key] == parameter[ 'nominal_values'][limit_key] # test functions assert motor.torque(state) == torque_testing(state, mp) assert all(motor.i_in(state) == state[0:2]) ode = motor.electrical_ode(state, u_qd, omega) test_ode = synchronous_motor_ode_testing(state, u_qd, omega, mp) assert sum(abs(ode - test_ode)) < 1E-8, "Motor ode is wrong: " + str( [ode, test_ode])
def test_initialization_weighted_sum_of_errors(normed, reward_power, motor_type, converter_type, number_reward_weights): """ Function to test the basic methods and functions ot the WeightedSumOfErrors class :param normed: specifies if the reward is normed (True/False) :param reward_power: specifies the used power order (int) :param motor_type: motor name (string) :param converter_type: converter name (string :param number_reward_weights: specifies how many states are considered for the reward :return: """ # setup physical system and reference generator physical_system = setup_physical_system(motor_type, converter_type) reference_generator = setup_reference_generator('SinusReference', physical_system) reference_generator.reset() len_state = len(physical_system.state_names) state = np.ones(len_state) reference = physical_system.state_space.low # set parameters gamma = 0.99 # observe the limits for all state variables observed_states = physical_system.state_names # set different types of reward weights reward_weights_dict = test_motor_parameter[motor_type]['reward_weights'] # test different numbers of reward weights if number_reward_weights == 1: reward_weights_dict['torque'] = 0 elif number_reward_weights == 3: reward_weights_dict['u_sup'] = 1 reward_weights_list = list(reward_weights_dict.values()) reward_weights_array = np.array(reward_weights_list) # initialize the reward function with different types of reward weights reward_fct_default = WeightedSumOfErrors(observed_states=None) reward_fct_initial_dict = WeightedSumOfErrors(reward_weights_dict, observed_states=None) reward_fct_initial_list = WeightedSumOfErrors(reward_weights_list, observed_states=None) reward_fct_initial_array = WeightedSumOfErrors(reward_weights_array, observed_states=None) reward_fct_make = make_module(RewardFunction, 'WSE', reward_weights=reward_weights_dict, observed_states=None) # initialize a reward function where all parameters are set reward_fct_test = WeightedSumOfErrors(reward_weights_dict, normed, gamma, reward_power, observed_states=observed_states) reward_fcts = [ reward_fct_default, reward_fct_initial_dict, reward_fct_initial_list, reward_fct_initial_array, reward_fct_make, reward_fct_test ] for reward_fct in reward_fcts: reward_fct.set_modules(physical_system, reference_generator) # test if reward weights of default initialization are different to the parametrized initialization assert reward_fct_default._reward_weights is not reward_fct_initial_dict._reward_weights # test if all parametrized initializations result in the same reward weights assert all(reward_fct_initial_dict._reward_weights == reward_fct_initial_list._reward_weights) \ and all(reward_fct_initial_dict._reward_weights == reward_fct_initial_array._reward_weights) # test the reward range, it should be negative and therefore, the upper limit is always zero assert reward_fct_test.reward_range[1] == 0 # if the reward is normalized the minimum reward should be -1 if normed: assert reward_fct_test.reward_range[0] == -1 # test the reset, reward and close function as well as the limit violation in a basic test scenario for index, reward_fct in enumerate(reward_fcts): reward_fct.reset() reward_fct.close() rew, done = reward_fct.reward(state, reference) # test if reward is in the expected range assert reward_fct.reward_range[0] <= rew <= reward_fct.reward_range[1], "Reward out of reward range" +\ str(reward_fct.reward_range) + " " +\ str(reward_fct._normed) + " " +\ str(reward_fct._reward_weights) + " " +\ str(state) + " " + \ str(reference) + " " + \ str(index) assert done == 0 # test if limit check does work exceeding_state = state * 1.2 rew, done = reward_fct.reward(exceeding_state, reference) if index < 5: assert done == 0, "Limit violation recognized " + str( [exceeding_state, physical_system.limits]) else: assert done == 1, "Limit violation is not recognized " + str( [exceeding_state, physical_system.limits]) # test if the punishment is correct assert rew == reward_fct.reward_range[0] / ( 1 - gamma), "Wrong punishment"
def test_cont_three_phase(motor_type): """ test the physical system for continuous-time three phase motors :param motor_type: motor name (string) :return: """ converter_type = 'Cont-B6C' actions = [[1, 1, 1], [0, 0, 0], [-1, -1, -1], [0.5, -0.5, 0.3], [-0.6, 0.5, 0.3]] # test default initializations default_motor = make_module(ElectricMotor, motor_type) default_converter = make_module(PowerElectronicConverter, converter_type) default_mechanical_load = make_module(MechanicalLoad, 'PolyStaticLoad') default_supply = make_module(VoltageSupply, 'IdealVoltageSupply') default_solver = make_module(OdeSolver, 'scipy.solve_ivp') default_scml_1 = SynchronousMotorSystem(converter=converter_type, motor=motor_type) default_scml_2 = SynchronousMotorSystem(motor=default_motor, converter=default_converter, load=default_mechanical_load, supply=default_supply, ode_solver=default_solver) default_scml_3 = SynchronousMotorSystem(motor=motor_type, converter=converter_type, load='PolyStaticLoad', supply='IdealVoltageSupply', ode_solver='scipy.solve_ivp') # test parameters for different default initializations assert all(default_scml_2.limits == default_scml_3.limits), "Different default limits" assert all(default_scml_2.nominal_state == default_scml_3.nominal_state ), "Different default nominal values" assert default_scml_2.tau == default_scml_3.tau == default_scml_1.tau, "Different sampling times" assert default_scml_1.state_names == default_scml_2.state_names == default_scml_3.state_names assert default_scml_1.state_positions == default_scml_2.state_positions == default_scml_3.state_positions == \ dict(omega=0, torque=1, i_a=2, i_b=3, i_c=4, u_a=5, u_b=6, u_c=7, epsilon=8, u_sup=9) assert default_scml_1.state_space.shape == default_scml_2.state_space.shape == \ default_scml_2.state_space.shape == (10,) # test functions as reset, simulate, close for scml in [default_scml_1, default_scml_2, default_scml_3]: assert all(scml.reset() == np.array([0, 0, 0, 0, 0, -1, -1, -1, 0, 1])) assert all(default_scml_1.action_space.low == -1 * np.ones(3)) and all(scml.action_space.high == np.ones(3)) for action in actions: state = scml.simulate(action) assert all(scml.state_space.low <= state / scml.limits) and all( state / scml.limits <= scml.state_space.high) scml.close() # test parametrized initializations mp = test_motor_parameter[motor_type]['motor_parameter'] cp = converter_parameter lp = load_parameter['parameter'] u_sup = mp['u_sup'] tau = cp['tau'] # set up instantiated modules motor = make_module(ElectricMotor, motor_type, motor_parameter=mp) converter = make_module(PowerElectronicConverter, converter_type, converter_parameter=cp) mechanical_load = make_module(MechanicalLoad, 'PolyStaticLoad', load_parameter=lp) supply = make_module(VoltageSupply, 'IdealVoltageSupply', u_nominal=u_sup, tau=tau) solver = make_module(OdeSolver, 'scipy.solve_ivp') # initialize parametrized SCML systems scml_1 = SynchronousMotorSystem(motor=motor, converter=converter, load=mechanical_load, supply=supply, ode_solver=solver, tau=tau) scml_2 = SynchronousMotorSystem(motor=motor_type, converter=converter_type, load='PolyStaticLoad', supply='IdealVoltageSupply', ode_solver='scipy.solve_ivp', motor_parameter=mp, converter_parameter=cp, load_parameter=lp, tau=tau, u_sup=u_sup) # test parameter assert all(scml_1.limits == scml_2.limits), "Different default limits" assert all(scml_1.nominal_state == scml_2.nominal_state), "Different default nominal values" assert scml_1.tau == scml_2.tau == tau, "Different sampling times" assert scml_1.state_names == scml_2.state_names assert scml_1.state_positions == scml_2.state_positions == \ dict(omega=0, torque=1, i_a=2, i_b=3, i_c=4, u_a=5, u_b=6, u_c=7, epsilon=8, u_sup=9) assert scml_1.state_space.shape == scml_2.state_space.shape == (10, ) # test functions reset, simulate, close for scml in [scml_1, scml_2]: assert all( scml.reset() == np.array([0, 0, 0, 0, 0, -.75, -.75, -.75, 0, 1])) assert all(default_scml_1.action_space.low == -1 * np.ones(3)) and all(scml.action_space.high == np.ones(3)) assert all(scml.state_space.high == np.ones(10)) assert all(scml.state_space.low == np.array( [-1, -1, -1, -1, -1, -1, -1, -1, -1, 0])), "Wrong state space" for index, action in enumerate(actions): state_1 = scml_1.simulate(action) state_2 = scml_2.simulate(action) assert all(state_1 == state_2) assert all(scml.state_space.low <= state_1 / scml.limits) and all( state_1 / scml.limits <= scml.state_space.high) assert scml.k == index + 1 scml_1.close() scml_2.close()