-
Notifications
You must be signed in to change notification settings - Fork 458
Expand file tree
/
Copy pathnlsys_test.py
More file actions
94 lines (77 loc) · 3.32 KB
/
Copy pathnlsys_test.py
File metadata and controls
94 lines (77 loc) · 3.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
"""nlsys_test.py - test nonlinear input/output system operations
RMM, 18 Jun 2022
This test suite checks various newer functions for NonlinearIOSystems.
The main test functions are contained in iosys_test.py.
"""
import pytest
import numpy as np
import control as ct
# Basic test of nlsys()
def test_nlsys_basic():
def kincar_update(t, x, u, params):
l = params.get('l', 1) # wheelbase
return np.array([
np.cos(x[2]) * u[0], # x velocity
np.sin(x[2]) * u[0], # y velocity
np.tan(u[1]) * u[0] / l # angular velocity
])
def kincar_output(t, x, u, params):
return x[0:2] # x, y position
kincar = ct.nlsys(
kincar_update, kincar_output,
states=['x', 'y', 'theta'],
inputs=2, input_prefix='U',
outputs=2)
assert kincar.input_labels == ['U[0]', 'U[1]']
assert kincar.output_labels == ['y[0]', 'y[1]']
assert kincar.state_labels == ['x', 'y', 'theta']
# Test nonlinear initial, step, and forced response
@pytest.mark.parametrize(
"nin, nout, input, output", [
( 1, 1, None, None),
( 2, 2, None, None),
( 2, 2, 0, None),
( 2, 2, None, 1),
( 2, 2, 1, 0),
])
def test_lti_nlsys_response(nin, nout, input, output):
sys_ss = ct.rss(4, nin, nout, strictly_proper=True)
sys_nl = ct.nlsys(
lambda t, x, u, params: sys_ss.A @ x + sys_ss.B @ u,
lambda t, x, u, params: sys_ss.C @ x + sys_ss.D @ u,
inputs=nin, outputs=nout, states=4)
# Figure out the time to use from the linear impulse response
resp_ss = ct.impulse_response(sys_ss)
timepts = np.linspace(0, resp_ss.time[-1]/10, 100)
# Initial response
resp_ss = ct.initial_response(sys_ss, timepts, output=output)
resp_nl = ct.initial_response(sys_nl, timepts, output=output)
np.testing.assert_equal(resp_ss.time, resp_nl.time)
np.testing.assert_allclose(resp_ss.states, resp_nl.states, atol=0.01)
# Step response
resp_ss = ct.step_response(sys_ss, timepts, input=input, output=output)
resp_nl = ct.step_response(sys_nl, timepts, input=input, output=output)
np.testing.assert_equal(resp_ss.time, resp_nl.time)
np.testing.assert_allclose(resp_ss.states, resp_nl.states, atol=0.01)
# Forced response
X0 = np.linspace(0, 1, sys_ss.nstates)
U = np.zeros((nin, timepts.size))
for i in range(nin):
U[i] = 0.01 * np.sin(timepts + i)
resp_ss = ct.forced_response(sys_ss, timepts, U, X0=X0)
resp_nl = ct.forced_response(sys_nl, timepts, U, X0=X0)
np.testing.assert_equal(resp_ss.time, resp_nl.time)
np.testing.assert_allclose(resp_ss.states, resp_nl.states, atol=0.05)
# Test to make sure that impulse responses are not allowed
def test_nlsys_impulse():
sys_ss = ct.rss(4, 1, 1, strictly_proper=True)
sys_nl = ct.nlsys(
lambda t, x, u, params: sys_ss.A @ x + sys_ss.B @ u,
lambda t, x, u, params: sys_ss.C @ x + sys_ss.D @ u,
inputs=1, outputs=1, states=4)
# Figure out the time to use from the linear impulse response
resp_ss = ct.impulse_response(sys_ss)
timepts = np.linspace(0, resp_ss.time[-1]/10, 100)
# Impulse_response (not implemented)
with pytest.raises(ValueError, match="system must be LTI"):
resp_nl = ct.impulse_response(sys_nl, timepts)