From 173e25c9f6f717d7f4ae692060b76fa0e66a0ecb Mon Sep 17 00:00:00 2001 From: XyDrKRulof Date: Wed, 29 May 2024 15:16:01 +0200 Subject: [PATCH 1/3] Added denormalization (Issue #223) --- .../physical_system_wrappers/cos_sin_processor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gym_electric_motor/physical_system_wrappers/cos_sin_processor.py b/src/gym_electric_motor/physical_system_wrappers/cos_sin_processor.py index fd18dadb..01afa37e 100644 --- a/src/gym_electric_motor/physical_system_wrappers/cos_sin_processor.py +++ b/src/gym_electric_motor/physical_system_wrappers/cos_sin_processor.py @@ -84,6 +84,6 @@ def _get_cos_sin(self, state): return np.concatenate( ( state, - [np.cos(state[self._angle_index]), np.sin(state[self._angle_index])], + [np.cos(state[self._angle_index]*np.pi), np.sin(state[self._angle_index])*np.pi], ) ) From 35e1b3061f73b5f8d6b7af2661c56fd492182864 Mon Sep 17 00:00:00 2001 From: XyDrKRulof Date: Wed, 29 May 2024 15:17:11 +0200 Subject: [PATCH 2/3] Added pole pair number to angle advancement (Issue #224) and added EESM (Issue #231) --- .../dq_to_abc_action_processor.py | 60 ++++++++++++------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/src/gym_electric_motor/physical_system_wrappers/dq_to_abc_action_processor.py b/src/gym_electric_motor/physical_system_wrappers/dq_to_abc_action_processor.py index 2d5a1da6..4787a773 100644 --- a/src/gym_electric_motor/physical_system_wrappers/dq_to_abc_action_processor.py +++ b/src/gym_electric_motor/physical_system_wrappers/dq_to_abc_action_processor.py @@ -5,7 +5,6 @@ from .physical_system_wrapper import PhysicalSystemWrapper - class DqToAbcActionProcessor(PhysicalSystemWrapper): """The DqToAbcActionProcessor converts an inner system with an AC motor and actions in abc coordinates to a system to which actions in the dq-coordinate system can be applied. @@ -31,12 +30,11 @@ def register_transformation(cls, motor_types): def wrapper(callable_): for motor_type in motor_types: cls._registry[motor_type] = callable_ - return wrapper @classmethod def make(cls, motor_type, *args, **kwargs): - assert motor_type in cls._registry.keys(), f"Not supported motor_type {motor_type}." + assert motor_type in cls._registry.keys(), f'Not supported motor_type {motor_type}.' class_ = cls._registry[motor_type] inst = class_(*args, **kwargs) return inst @@ -58,21 +56,20 @@ def __init__(self, angle_name, physical_system=None): def set_physical_system(self, physical_system): # Docstring of super class - assert isinstance( - physical_system.electrical_motor, ps.ThreePhaseMotor - ), "The motor in the system has to derive from the ThreePhaseMotor to define transformations." + assert isinstance(physical_system.electrical_motor, ps.ThreePhaseMotor), \ + 'The motor in the system has to derive from the ThreePhaseMotor to define transformations.' super().set_physical_system(physical_system) - self._omega_index = physical_system.state_names.index("omega") + self._omega_index = physical_system.state_names.index('omega') self._angle_index = physical_system.state_names.index(self._angle_name) - assert self._angle_name in physical_system.state_names, ( - f"Angle {self._angle_name} not in the states of the physical system. " - f"Probably a flux observer is required." - ) + self._pole_pair_number = physical_system._electrical_motor.motor_parameter['p'] + assert self._angle_name in physical_system.state_names, \ + f'Angle {self._angle_name} not in the states of the physical system. ' \ + f'Probably a flux observer is required.' self._angle_advance = 0.5 # If dead time has been added to the system increase the angle advance by the amount of dead time steps - if hasattr(physical_system, "dead_time"): + if hasattr(physical_system, 'dead_time'): self._angle_advance += physical_system.dead_time return self @@ -87,10 +84,12 @@ def reset(self, **kwargs): return normalized_state def _advance_angle(self, state): - return state[self._angle_index] + self._angle_advance * self._physical_system.tau * state[self._omega_index] + return state[self._angle_index] + self._angle_advance \ + * self._physical_system.tau * state[self._omega_index] * self._pole_pair_number class _ClassicDqToAbcActionProcessor(DqToAbcActionProcessor): + @property def action_space(self): return gymnasium.spaces.Box(-1, 1, shape=(2,), dtype=np.float64) @@ -104,24 +103,25 @@ def simulate(self, action): return normalized_state -DqToAbcActionProcessor.register_transformation(["PMSM"])( - lambda angle_name="epsilon", *args, **kwargs: _ClassicDqToAbcActionProcessor(angle_name, *args, **kwargs) +DqToAbcActionProcessor.register_transformation(['PMSM'])( + lambda angle_name='epsilon', *args, **kwargs: _ClassicDqToAbcActionProcessor(angle_name, *args, **kwargs) ) -DqToAbcActionProcessor.register_transformation(["SCIM"])( - lambda angle_name="psi_angle", *args, **kwargs: _ClassicDqToAbcActionProcessor(angle_name, *args, **kwargs) +DqToAbcActionProcessor.register_transformation(['SCIM'])( + lambda angle_name='psi_angle', *args, **kwargs: _ClassicDqToAbcActionProcessor(angle_name, *args, **kwargs) ) -@DqToAbcActionProcessor.register_transformation(["DFIM"]) +@DqToAbcActionProcessor.register_transformation(['DFIM']) class _DFIMDqToAbcActionProcessor(DqToAbcActionProcessor): + @property def action_space(self): return gymnasium.spaces.Box(-1, 1, shape=(4,)) def __init__(self, physical_system=None): - super().__init__("epsilon", physical_system=physical_system) - self._flux_angle_name = "psi_abs" + super().__init__('epsilon', physical_system=physical_system) + self._flux_angle_name = 'psi_abs' self._flux_angle_index = None def simulate(self, action): @@ -144,5 +144,23 @@ def simulate(self, action): def set_physical_system(self, physical_system): super().set_physical_system(physical_system) - self._flux_angle_index = physical_system.state_names.index("psi_angle") + self._flux_angle_index = physical_system.state_names.index('psi_angle') return self + +@DqToAbcActionProcessor.register_transformation(['EESM']) +class _EESMDqToAbcActionProcessor(DqToAbcActionProcessor): + @property + def action_space(self): + return gymnasium.spaces.Box(-1, 1, shape=(3,)) + + def __init__(self, physical_system=None): + super().__init__('epsilon', physical_system=physical_system) + + def simulate(self, action): + # Docstring of superclass + advanced_angle = self._advance_angle(self._state) + abc_action = self._transformation(action[:-1], advanced_angle) + abc_action = np.append(abc_action, action[-1]) + normalized_state = self._physical_system.simulate(abc_action) + self._state = normalized_state * self._physical_system.limits + return normalized_state From dd3324844cbeef4a3a635e276281c9f0c9a95fb8 Mon Sep 17 00:00:00 2001 From: XyDrKRulof Date: Wed, 29 May 2024 15:53:02 +0200 Subject: [PATCH 3/3] Fixed Wrappers and changed tests to reflect on correct Wrapper behavior --- .../physical_system_wrappers/cos_sin_processor.py | 2 +- .../physical_system_wrappers/dq_to_abc_action_processor.py | 2 +- tests/test_physical_system_wrappers/test_cos_sin_processor.py | 2 +- .../test_dq_to_abc_action_processor.py | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/gym_electric_motor/physical_system_wrappers/cos_sin_processor.py b/src/gym_electric_motor/physical_system_wrappers/cos_sin_processor.py index 01afa37e..ec875f34 100644 --- a/src/gym_electric_motor/physical_system_wrappers/cos_sin_processor.py +++ b/src/gym_electric_motor/physical_system_wrappers/cos_sin_processor.py @@ -84,6 +84,6 @@ def _get_cos_sin(self, state): return np.concatenate( ( state, - [np.cos(state[self._angle_index]*np.pi), np.sin(state[self._angle_index])*np.pi], + [np.cos(state[self._angle_index]*np.pi), np.sin(state[self._angle_index]*np.pi)], ) ) diff --git a/src/gym_electric_motor/physical_system_wrappers/dq_to_abc_action_processor.py b/src/gym_electric_motor/physical_system_wrappers/dq_to_abc_action_processor.py index 4787a773..f6ef88a6 100644 --- a/src/gym_electric_motor/physical_system_wrappers/dq_to_abc_action_processor.py +++ b/src/gym_electric_motor/physical_system_wrappers/dq_to_abc_action_processor.py @@ -61,7 +61,7 @@ def set_physical_system(self, physical_system): super().set_physical_system(physical_system) self._omega_index = physical_system.state_names.index('omega') self._angle_index = physical_system.state_names.index(self._angle_name) - self._pole_pair_number = physical_system._electrical_motor.motor_parameter['p'] + self._pole_pair_number = physical_system.electrical_motor.motor_parameter['p'] assert self._angle_name in physical_system.state_names, \ f'Angle {self._angle_name} not in the states of the physical system. ' \ f'Probably a flux observer is required.' diff --git a/tests/test_physical_system_wrappers/test_cos_sin_processor.py b/tests/test_physical_system_wrappers/test_cos_sin_processor.py index 933f0846..7f934e6b 100644 --- a/tests/test_physical_system_wrappers/test_cos_sin_processor.py +++ b/tests/test_physical_system_wrappers/test_cos_sin_processor.py @@ -45,6 +45,6 @@ def test_simulate(self, processor, physical_system, action): assert all( state == np.concatenate( - (ps_state, [np.cos(cos_sin_state), np.sin(cos_sin_state)]) + (ps_state, [np.cos(cos_sin_state*np.pi), np.sin(cos_sin_state*np.pi)]) ) ) diff --git a/tests/test_physical_system_wrappers/test_dq_to_abc_action_processor.py b/tests/test_physical_system_wrappers/test_dq_to_abc_action_processor.py index 60d24b5c..1d763a3c 100644 --- a/tests/test_physical_system_wrappers/test_dq_to_abc_action_processor.py +++ b/tests/test_physical_system_wrappers/test_dq_to_abc_action_processor.py @@ -35,12 +35,12 @@ def test_action_space(self, processor, physical_system): ( np.array([0.0, 1.0]), np.array([12.8, 0.123, 0.0]), - np.array([-0.23752263, 0.96000281, -0.72248018]), + np.array([-0.45595422, 0.99874252, -0.54278829]), ), ( np.array([0.0, 0.5]), np.array([-10.0, 0.123, 0.0]), - np.array([-0.49324109, 0.31757774, 0.17566335]), + np.array([ 0.36929056, -0.47656712, 0.10727657]), ), ], )