diff --git a/Environments.md b/Environments.md index 412b41c..d1a010b 100644 --- a/Environments.md +++ b/Environments.md @@ -6,6 +6,8 @@ | Two wheeled System (Constant Goal) | x | ✓ | 3 | 2 | | Two wheeled System (Moving Goal) (Coming soon) | x | ✓ | 3 | 2 | | Cartpole (Swing up) | x | ✓ | 4 | 1 | +| Nonlinear Sample System Env | x | ✓ | 2 | 1 | + ## [FistOrderLagEnv](PythonLinearNonlinearControl/envs/first_order_lag.py) @@ -53,4 +55,14 @@ mc = 1, mp = 0.2, l = 0.5, g = 9.81 ### Cost. - \ No newline at end of file + + +## [Nonlinear Sample System Env](PythonLinearNonlinearControl/envs/nonlinear_sample_system.py) + +## System equation. + + + +### Cost. + + diff --git a/PythonLinearNonlinearControl/common/utils.py b/PythonLinearNonlinearControl/common/utils.py index 27d67ce..bcbde9f 100644 --- a/PythonLinearNonlinearControl/common/utils.py +++ b/PythonLinearNonlinearControl/common/utils.py @@ -46,15 +46,16 @@ def fit_angle_in_range(angles, min_angle=-np.pi, max_angle=np.pi): return output.reshape(output_shape) -def update_state_with_Runge_Kutta(state, u, functions, dt=0.01): +def update_state_with_Runge_Kutta(state, u, functions, dt=0.01, batch=True): """ update state in Runge Kutta methods Args: state (array-like): state of system u (array-like): input of system functions (list): update function of each state, - each function will be called like func(*state, *u) + each function will be called like func(state, u) We expect that this function returns differential of each state dt (float): float in seconds + batch (bool): state and u is given by batch or not Returns: next_state (np.array): next state of system @@ -68,36 +69,50 @@ def update_state_with_Runge_Kutta(state, u, functions, dt=0.01): Note that the function return x_dot. """ - state_size = len(state) - assert state_size == len(functions), \ - "Invalid functions length, You need to give the state size functions" + if not batch: + state_size = len(state) + assert state_size == len(functions), \ + "Invalid functions length, You need to give the state size functions" - k0 = np.zeros(state_size) - k1 = np.zeros(state_size) - k2 = np.zeros(state_size) - k3 = np.zeros(state_size) + k0 = np.zeros(state_size) + k1 = np.zeros(state_size) + k2 = np.zeros(state_size) + k3 = np.zeros(state_size) - inputs = np.concatenate([state, u]) + for i, func in enumerate(functions): + k0[i] = dt * func(state, u) - for i, func in enumerate(functions): - k0[i] = dt * func(*inputs) + for i, func in enumerate(functions): + k1[i] = dt * func(state + k0 / 2., u) - add_state = state + k0 / 2. - inputs = np.concatenate([add_state, u]) + for i, func in enumerate(functions): + k2[i] = dt * func(state + k1 / 2., u) - for i, func in enumerate(functions): - k1[i] = dt * func(*inputs) + for i, func in enumerate(functions): + k3[i] = dt * func(state + k2, u) - add_state = state + k1 / 2. - inputs = np.concatenate([add_state, u]) + return (k0 + 2. * k1 + 2. * k2 + k3) / 6. - for i, func in enumerate(functions): - k2[i] = dt * func(*inputs) + else: + batch_size, state_size = state.shape + assert state_size == len(functions), \ + "Invalid functions length, You need to give the state size functions" - add_state = state + k2 - inputs = np.concatenate([add_state, u]) + k0 = np.zeros(batch_size, state_size) + k1 = np.zeros(batch_size, state_size) + k2 = np.zeros(batch_size, state_size) + k3 = np.zeros(batch_size, state_size) - for i, func in enumerate(functions): - k3[i] = dt * func(*inputs) + for i, func in enumerate(functions): + k0[:, i] = dt * func(state, u) - return (k0 + 2. * k1 + 2. * k2 + k3) / 6. + for i, func in enumerate(functions): + k1[:, i] = dt * func(state + k0 / 2., u) + + for i, func in enumerate(functions): + k2[:, i] = dt * func(state + k1 / 2., u) + + for i, func in enumerate(functions): + k3[:, i] = dt * func(state + k2, u) + + return (k0 + 2. * k1 + 2. * k2 + k3) / 6. diff --git a/PythonLinearNonlinearControl/envs/nonlinear_sample_system.py b/PythonLinearNonlinearControl/envs/nonlinear_sample_system.py index a17390b..01f7cd5 100644 --- a/PythonLinearNonlinearControl/envs/nonlinear_sample_system.py +++ b/PythonLinearNonlinearControl/envs/nonlinear_sample_system.py @@ -59,9 +59,9 @@ class NonlinearSampleEnv(Env): self.config["input_lower_bound"], self.config["input_upper_bound"]) - funtions = [self._func_x_1, self._func_x_2] + functions = [self._func_x_1, self._func_x_2] - next_x = update_state_with_Runge_Kutta(self._curr_x, u, + next_x = update_state_with_Runge_Kutta(self.curr_x, u, functions, self.config["dt"]) # cost @@ -82,16 +82,16 @@ class NonlinearSampleEnv(Env): self.step_count > self.config["max_step"], \ {"goal_state": self.g_x} - def _func_x_1(self, x_1, x_2, u): + def _func_x_1(self, x, u): """ """ - x_dot = x_2 + x_dot = x[1] return x_dot - def _func_x_2(self, x_1, x_2, u): + def _func_x_2(self, x, u): """ """ - x_dot = (1. - x_1**2 - x_2**2) * x_2 - x_1 + u + x_dot = (1. - x[0]**2 - x[1]**2) * x[1] - x[0] + u return x_dot def plot_func(self, to_plot, i=None, history_x=None, history_g_x=None):