1+ using  ModelingToolkit, Test
2+ using  Symbolics
3+ using  StaticArrays
4+ 
5+ @testset  " input_affine_form" begin 
6+     #  Test with simple linear system
7+     @testset  " Simple linear system" begin 
8+         @variables  x1 x2 u1 u2
9+         state =  [x1, x2]
10+         inputs =  [u1, u2]
11+         
12+         eqs =  [
13+             - x1 +  2 * x2 +  u1,
14+             x1* x2 -  x2 +  u1 +  2 * u2
15+         ]
16+         
17+         f, g =  input_affine_form (eqs, inputs)
18+         
19+         #  Verify reconstruction
20+         eqs_reconstructed =  f +  g *  inputs
21+         @test  isequal (Symbolics. simplify .(eqs_reconstructed), Symbolics. simplify .(eqs))
22+         
23+         #  Check dimensions
24+         @test  length (f) ==  length (eqs)
25+         @test  size (g) ==  (length (eqs), length (inputs))
26+     end 
27+ 
28+     #  Test with Segway dynamics example
29+     @testset  " Segway dynamics" begin 
30+         #  Segway parameters
31+         grav =  9.81 
32+         R =  0.195 
33+         M =  2  *  2.485 
34+         Jc =  2  *  0.0559 
35+         L =  0.169 
36+         m =  44.798 
37+         Jg =  3.836 
38+         m0 =  52.710 
39+         J0 =  5.108 
40+         Km =  2  *  1.262 
41+         bt =  2  *  1.225 
42+ 
43+         #  Dynamics of Segway in Euler-Lagrange form
44+         D (q) =  [m0 m* L* cos (q[2 ]); m* L* cos (q[2 ]) J0]
45+         function  H (q, q̇)
46+             return  SA[
47+                 - m *  L *  sin (q[2 ]) *  q̇[2 ] +  bt *  (q̇[1 ] -  R *  q̇[2 ]) /  R,
48+                 - m *  grav *  L *  sin (q[2 ]) -  bt *  (q̇[1 ] -  R *  q̇[2 ]),
49+             ]
50+         end 
51+         B (q) =  SA[Km /  R, - Km]
52+ 
53+         #  Convert to control affine form
54+         function  f_seg (x)
55+             q, q̇ =  x[SA[1 ,2 ]], x[SA[3 ,4 ]]
56+             return  [q̇; - D (q) \  H (q, q̇)]
57+         end 
58+         function  g_seg (x)
59+             q, q̇ =  x[SA[1 ,2 ]], x[SA[3 ,4 ]]
60+             return  [SA[0 ,0 ]; D (q) \  B (q)]
61+         end 
62+ 
63+         #  Trace dynamics symbolically
64+         @variables  q1 q2 qd1 qd2 u
65+         x =  [q1; q2; qd1; qd2]
66+         inputs =  [u]
67+         eqs =  f_seg (x) +  g_seg (x) *  u
68+ 
69+         #  Extract control-affine form
70+         fe, ge =  input_affine_form (eqs, inputs)
71+         
72+         #  Test reconstruction
73+         eqs2 =  fe +  ge *  inputs
74+         diff =  Symbolics. simplify .(eqs2 -  eqs, expand= true )
75+         
76+         #  The difference should be zero or very close to zero symbolically
77+         #  We test numerically since symbolic simplification might not be perfect
78+         f2, _ =  build_function (fe, x, expression= false )
79+         g2, _ =  build_function (ge, x, expression= false )
80+         
81+         for  i =  1 : 10 
82+             x_val =  rand (length (x))
83+             @test  f2 (x_val) ≈  f_seg (x_val) rtol= 1e-10 
84+             @test  g2 (x_val) ≈  g_seg (x_val) rtol= 1e-10 
85+         end 
86+     end 
87+ 
88+     #  Test with multiple inputs
89+     @testset  " Multiple inputs" begin 
90+         @variables  x1 x2 x3 u1 u2
91+         state =  [x1, x2, x3]
92+         inputs =  [u1, u2]
93+         
94+         eqs =  [
95+             x2,
96+             x3,
97+             - x1 -  2 * x2 -  x3 +  u1 +  3 * u2
98+         ]
99+         
100+         f, g =  input_affine_form (eqs, inputs)
101+         
102+         #  Expected results
103+         f_expected =  [x2, x3, - x1 -  2 * x2 -  x3]
104+         g_expected =  [0  0 ; 0  0 ; 1  3 ]
105+         
106+         @test  isequal (Symbolics. simplify .(f), Symbolics. simplify .(f_expected))
107+         
108+         #  Test g matrix elements
109+         for  i in  1 : size (g, 1 ), j in  1 : size (g, 2 )
110+             @test  isequal (Symbolics. simplify (g[i,j]), g_expected[i,j])
111+         end 
112+     end 
113+ 
114+     #  Test with nonlinear state dynamics
115+     @testset  " Nonlinear state dynamics" begin 
116+         @variables  x1 x2 u
117+         state =  [x1, x2]
118+         inputs =  [u]
119+         
120+         eqs =  [
121+             x2,
122+             - sin (x1) -  x2 +  u
123+         ]
124+         
125+         f, g =  input_affine_form (eqs, inputs)
126+         
127+         #  Expected results
128+         f_expected =  [x2, - sin (x1) -  x2]
129+         g_expected =  reshape ([0 , 1 ], 2 , 1 )
130+         
131+         @test  isequal (Symbolics. simplify .(f), Symbolics. simplify .(f_expected))
132+         @test  isequal (g, g_expected)
133+     end 
134+ 
135+ end 
0 commit comments