Skip to content

Commit f49ed38

Browse files
author
Shunichi09
committed
Add runge kutta
1 parent 969fee7 commit f49ed38

File tree

3 files changed

+155
-1
lines changed

3 files changed

+155
-1
lines changed

PythonLinearNonlinearControl/common/utils.py

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,60 @@ def fit_angle_in_range(angles, min_angle=-np.pi, max_angle=np.pi):
4141
output += min_angle
4242

4343
output = np.minimum(max_angle, np.maximum(min_angle, output))
44-
return output.reshape(output_shape)
44+
return output.reshape(output_shape)
45+
46+
def update_state_with_Runge_Kutta(state, u, functions, dt=0.01):
47+
""" update state in Runge Kutta methods
48+
Args:
49+
state (array-like): state of system
50+
u (array-like): input of system
51+
functions (list): update function of each state,
52+
each function will be called like func(*state, *u)
53+
We expect that this function returns differential of each state
54+
dt (float): float in seconds
55+
56+
Returns:
57+
next_state (np.array): next state of system
58+
59+
Notes:
60+
sample of function is as follows:
61+
62+
def func_x(self, x_1, x_2, u):
63+
x_dot = (1. - x_1**2 - x_2**2) * x_2 - x_1 + u
64+
return x_dot
65+
66+
Note that the function return x_dot.
67+
"""
68+
state_size = len(state)
69+
assert state_size == len(functions), \
70+
"Invalid functions length, You need to give the state size functions"
71+
72+
k0 = np.zeros(state_size)
73+
k1 = np.zeros(state_size)
74+
k2 = np.zeros(state_size)
75+
k3 = np.zeros(state_size)
76+
77+
inputs = np.concatenate([state, u])
78+
79+
for i, func in enumerate(functions):
80+
k0[i] = dt * func(*inputs)
81+
82+
add_state = state + k0 / 2.
83+
inputs = np.concatenate([add_state, u])
84+
85+
for i, func in enumerate(functions):
86+
k1[i] = dt * func(*inputs)
87+
88+
add_state = state + k1 / 2.
89+
inputs = np.concatenate([add_state, u])
90+
91+
for i, func in enumerate(functions):
92+
k2[i] = dt * func(*inputs)
93+
94+
add_state = state + k2
95+
inputs = np.concatenate([add_state, u])
96+
97+
for i, func in enumerate(functions):
98+
k3[i] = dt * func(*inputs)
99+
100+
return (k0 + 2. * k1 + 2. * k2 + k3) / 6.

PythonLinearNonlinearControl/configs/nonlinear_system_sample.py

Whitespace-only changes.
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
import numpy as np
2+
import scipy
3+
from scipy import integrate
4+
from .env import Env
5+
from ..common.utils import update_state_with_Runge_Kutta
6+
7+
class NonlinearSampleEnv(Env):
8+
""" Nonlinear Sample Env
9+
"""
10+
def __init__(self):
11+
"""
12+
"""
13+
self.config = {"state_size" : 2,\
14+
"input_size" : 1,\
15+
"dt" : 0.01,\
16+
"max_step" : 250,\
17+
"input_lower_bound": [-0.5],\
18+
"input_upper_bound": [0.5],
19+
}
20+
21+
super(NonlinearSampleEnv, self).__init__(self.config)
22+
23+
def reset(self, init_x=np.array([2., 0.])):
24+
""" reset state
25+
Returns:
26+
init_x (numpy.ndarray): initial state, shape(state_size, )
27+
info (dict): information
28+
"""
29+
self.step_count = 0
30+
31+
self.curr_x = np.zeros(self.config["state_size"])
32+
33+
if init_x is not None:
34+
self.curr_x = init_x
35+
36+
# goal
37+
self.g_x = np.array([0., 0.])
38+
39+
# clear memory
40+
self.history_x = []
41+
self.history_g_x = []
42+
43+
return self.curr_x, {"goal_state": self.g_x}
44+
45+
def step(self, u):
46+
"""
47+
Args:
48+
u (numpy.ndarray) : input, shape(input_size, )
49+
Returns:
50+
next_x (numpy.ndarray): next state, shape(state_size, )
51+
cost (float): costs
52+
done (bool): end the simulation or not
53+
info (dict): information
54+
"""
55+
# clip action
56+
u = np.clip(u,
57+
self.config["input_lower_bound"],
58+
self.config["input_upper_bound"])
59+
60+
funtions = [self._func_x_1, self._func_x_2]
61+
62+
next_x = update_state_with_Runge_Kutta(self._curr_x, u,
63+
functions, self.config["dt"])
64+
65+
# cost
66+
cost = 0
67+
cost = np.sum(u**2)
68+
cost += np.sum((self.curr_x - self.g_x)**2)
69+
70+
# save history
71+
self.history_x.append(next_x.flatten())
72+
self.history_g_x.append(self.g_x.flatten())
73+
74+
# update
75+
self.curr_x = next_x.flatten()
76+
# update costs
77+
self.step_count += 1
78+
79+
return next_x.flatten(), cost, \
80+
self.step_count > self.config["max_step"], \
81+
{"goal_state" : self.g_x}
82+
83+
def _func_x_1(self, x_1, x_2, u):
84+
"""
85+
"""
86+
x_dot = x_2
87+
return x_dot
88+
89+
def _func_x_2(self, x_1, x_2, u):
90+
"""
91+
"""
92+
x_dot = (1. - x_1**2 - x_2**2) * x_2 - x_1 + u
93+
return x_dot
94+
95+
def plot_func(self, to_plot, i=None, history_x=None, history_g_x=None):
96+
"""
97+
"""
98+
raise ValueError("NonlinearSampleEnv does not have animation")

0 commit comments

Comments
 (0)