1- """
2- Simulation and Control of a cruise ?
3- """
4-
1+ """Simulation and Control of cruise control, in all its nonlinear glory"""
52import numpy as np
63from pynumdiff .utils import utility
74
2118
2219
2320def triangle (iterations , dt ):
24- """
25- Create sawtooth pattern of hills for the car to drive over.
26-
27- :param iterations: number of time points in time series
28- :type iterations: int
21+ """Create sawtooth pattern of hills for the car to drive over.
2922
30- :param dt: time step in seconds
31- :type dt: float
32-
33- :return: time series of hills (angle of road as a function of time)
34- :rtype: np.matrix
23+ :param int iterations: number of time points in time series
24+ :param float dt: time step in seconds
3525
26+ :return: (np.array) -- time series of hills (angle of road as a function of time)
3627 """
3728 t = np .arange (0 , iterations * dt , dt )
3829 continuous_x = np .sin (0.02 * t * np .sqrt (t ))
@@ -59,34 +50,25 @@ def triangle(iterations, dt):
5950 reversal_vals = np .array (reversal_vals )[idx ]
6051 reversal_ts = t [reversal_idxs ]
6152
62- x = np .interp (t , reversal_ts , reversal_vals )
63- x = np .matrix (x )
64-
65- return x
53+ return np .interp (t , reversal_ts , reversal_vals )
6654
6755
6856def effective_wheel_radius (v = 20 ):
69- """
70- Allow effective wheel radius to be a function of velocity.
57+ """Allow effective wheel radius to be a function of velocity.
7158
72- :param v: ignored for now
73- :type v:
59+ :param float v: velocity
7460
75- :return: effective wheel radius, constant for now
76- :rtype: float
61+ :return: (float) -- effective wheel radius, constant for now
7762 """
7863 return v
7964
8065
8166def torque (omega ):
82- """
83- Convert throttle input to Torque. See Astrom and Murray 2008 Chapter 3.
67+ """Convert throttle input to Torque. See Astrom and Murray 2008 Chapter 3.
8468
85- :param omega: throttle
86- :type omega: float
69+ :param float omega: throttle
8770
88- :return: motor torque
89- :rtype: float
71+ :return: **torque** (float) -- motor torque
9072 """
9173 omega_m = parameters ['omega_m' ]
9274 t_m = parameters ['T_m' ]
@@ -96,25 +78,17 @@ def torque(omega):
9678
9779# pylint: disable-msg=too-many-locals
9880def step_forward (state_vals , disturbances , desired_v , dt ):
99- """
100- One-step Euler integrator that takes the current state, disturbances, and desired velocity and calculates the subsequent state.
101-
102- :param state_vals: current state [position, velocity, road_angle]
103- :type state_vals: np.matrix
104-
105- :param disturbances: current hill angle
106- :type disturbances: np.matrix
107-
108- :param desired_velocity: current desired velocity
109- :type desired_velocity: np.matrix
81+ """One-step Euler integrator that takes the current state, disturbances, and
82+ desired velocity and calculates the subsequent state.
11083
111- :param dt: time step (seconds)
112- :type dt: float
84+ :param np.array state_vals: current state [position, velocity, road_angle]
85+ :param np.array disturbances: current hill angle
86+ :param np.array desired_v: current desired velocity
87+ :param float dt: time step (seconds)
11388
114- :return: a tuple consisting of:
115- - new_state: new state
116- - u: control inputs
117- :rtype: tuple -> (np.matrix, np.matrix)
89+ :return: tuple[np.array, np.array] of\n
90+ - **new_state** -- new state
91+ - **u** -- control inputs
11892 """
11993 p = state_vals [0 , - 1 ]
12094 v = state_vals [1 , - 1 ]
@@ -125,9 +99,9 @@ def step_forward(state_vals, disturbances, desired_v, dt):
12599 rho = parameters ['rho' ]
126100 Cd = parameters ['Cd' ]
127101 A = parameters ['A' ]
128- v_r = desired_v [0 , - 1 ]
102+ v_r = desired_v [- 1 ]
129103 alpha_n = effective_wheel_radius (v )
130- z = np .sum (desired_v [ 0 , :] - state_vals [1 , :])* dt
104+ z = np .sum (desired_v - state_vals [1 , :])* dt
131105 k_p = parameters ['k_p' ]
132106 k_i = parameters ['k_i' ]
133107 u = k_p * (v_r - v ) + k_i * z
@@ -141,87 +115,63 @@ def step_forward(state_vals, disturbances, desired_v, dt):
141115 # driving force
142116 Fd = alpha_n * u * torque (alpha_n * v )
143117 vdot = 1 / m * (Fd - (Fr + Fa + Fg ))
144- new_state = np .matrix ([[p + dt * v ], [v + vdot * dt ], [theta ]])
145- return new_state , np . matrix ( u )
118+ new_state = np .array ([[p + dt * v ], [v + vdot * dt ], [theta ]])
119+ return new_state , u
146120
147121
148122# disturbance
149123def hills (iterations , dt , factor ):
150- """
151- Wrapper for creating a hill profile for the car to drive over that has an appropriate length and magnitude
152-
153- :param iterations: number of time points to simulate
154- :type iterations: int
155-
156- :param dt: timestep of simulation in seconds
157- :type dt: float
124+ """Wrapper for creating a hill profile for the car to drive over that has an appropriate length and magnitude
158125
159- :param factor: determines magnitude of the hills
160- :type factor: int
126+ :param int iterations: number of time points to simulate
127+ :param float dt: timestep of simulation in seconds
128+ :param int factor: determines magnitude of the hills
161129
162-
163- :return: hills, the output of the triangle function, a [1,M] matrix where M is the number of time points simulated
164- :rtype: np.matrix
130+ :return: **hills** (np.array) -- the output of the triangle function, a shape (M,) array where M is the number
131+ of time points simulated
165132 """
166133 return triangle (iterations , dt )* 0.3 / factor
167134
168135
169136# desired velocity
170137def desired_velocity (n , factor ):
171- """
172- Wrapper for defining the desired velocity as a matrix with size [1, M], where M is the number of time points to simulate
173- See function "run" for how this function gets used.
174-
175- :param n: number of time points to simulate
176- :type n: int
138+ """Wrapper for defining the desired velocity as an array of shape (M,), where M is the number of time points
139+ to simulate.
177140
178- :param factor: factor that determines the magnitude of the desired velocity
179- :type factor: float
141+ :param int n: number of time points to simulate
142+ :param float factor: factor that determines the magnitude of the desired velocity
180143
181- :return: desired velocity as function of time, a [1,M] matrix, M is the number of time points to simulate
182- :rtype: np.matrix
144+ :return: (np.array) -- desired velocity as function of time
183145 """
184- return np .matrix ([2 / factor ]* n )
146+ return np .array ([2 / factor ]* n )
185147
186148
187- def run (timeseries_length = 4 , dt = 0.01 ):
188- """
189- Simulate proportional integral control of a car attempting to maintain constant velocity while going up and down hills.
190- This function is used for testing differentiation methods.
191-
192- See Astrom and Murray 2008 Chapter 3.
193-
194- :param timeseries_length: number of seconds to simulate
195- :type timeseries_length: float
149+ def run (duration = 4 , dt = 0.01 ):
150+ """Simulate proportional integral control of a car attempting to maintain constant velocity while going up
151+ and down hills. This function can be used for testing differentiation methods. See Astrom and Murray 2008
152+ Chapter 3.
196153
197- :param dt: timestep in seconds
198- :type dt: float
154+ :param float duration: number of seconds to simulate
155+ :param float dt: timestep in seconds
199156
200- :return: a tuple consisting of arrays of size [N, M], where M is the number of time steps.:
201- - state_vals: state of the car, i.e. position and velocity as a function of time
202- - disturbances: disturbances, ie. hills, that the car is subjected to
203- - controls: control inputs applied by the car
204- :rtype: tuple -> (np.array, np.array, np.array)
157+ :return: tuple[np.array, np.array, np.array] of\n
158+ - **state_vals** -- state of the car, i.e. position and velocity as a function of time, shape (N,M)
159+ - **disturbances** -- disturbances from hills that the car is subjected to, shape (M,)
160+ - **controls** -- control inputs applied by the car, shape (M+1,)
205161 """
206- t = np .arange (0 , timeseries_length , dt )
162+ t = np .arange (0 , duration , dt )
207163 iterations = len (t )
208164
209- # hills
210- disturbances = np .matrix (np .zeros ([3 , iterations + 1 ]))
211- h = hills (iterations + 1 , dt , factor = 0.5 * timeseries_length / 2 )
212- disturbances [2 , :] = h [:, 0 :disturbances .shape [1 ]]
213-
214- # controls
215- controls = np .matrix ([[0 ]])
216-
217- # initial condition
218- state_vals = np .matrix ([[0 ], [0 ], [0 ]])
165+ disturbances = np .array (np .zeros ([3 , iterations + 1 ])) # disturbance from hills
166+ h = hills (iterations + 1 , dt , factor = 0.5 * duration / 2 )
167+ disturbances [2 , :] = h [0 :disturbances .shape [1 ]]
219168
220- # desired vel
221- v_r = desired_velocity (iterations , factor = 0.5 * iterations * dt / 2 )
169+ controls = np .array ([0 ])
170+ state_vals = np .array ([[0 ], [0 ], [0 ]]) # initial condition
171+ v_r = desired_velocity (iterations , factor = 0.5 * iterations * dt / 2 ) # desired, reference velocity
222172
223173 for i in range (1 , iterations + 1 ):
224- new_state , u = step_forward (state_vals , disturbances [:, 0 :i ], v_r [:, 0 :i ], dt )
174+ new_state , u = step_forward (state_vals , disturbances [:, 0 :i ], v_r [0 :i ], dt )
225175 state_vals = np .hstack ((state_vals , new_state ))
226176 controls = np .hstack ((controls , u ))
227177
0 commit comments