7017
|
1 ## Copyright (C) 1996, 1998, 2000, 2002, 2004, 2005, 2006, 2007 |
|
2 ## Auburn University. All rights reserved. |
3430
|
3 ## |
|
4 ## This file is part of Octave. |
|
5 ## |
|
6 ## Octave is free software; you can redistribute it and/or modify it |
7016
|
7 ## under the terms of the GNU General Public License as published by |
|
8 ## the Free Software Foundation; either version 3 of the License, or (at |
|
9 ## your option) any later version. |
3430
|
10 ## |
7016
|
11 ## Octave is distributed in the hope that it will be useful, but |
|
12 ## WITHOUT ANY WARRANTY; without even the implied warranty of |
|
13 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
|
14 ## General Public License for more details. |
3430
|
15 ## |
|
16 ## You should have received a copy of the GNU General Public License |
7016
|
17 ## along with Octave; see the file COPYING. If not, see |
|
18 ## <http://www.gnu.org/licenses/>. |
3430
|
19 |
|
20 ## -*- texinfo -*- |
5016
|
21 ## @deftypefn {Function File} {@var{clsys} =} sysconnect (@var{sys}, @var{out_idx}, @var{in_idx}, @var{order}, @var{tol}) |
3430
|
22 ## Close the loop from specified outputs to respective specified inputs |
|
23 ## |
|
24 ## @strong{Inputs} |
|
25 ## @table @var |
|
26 ## @item sys |
5016
|
27 ## System data structure. |
3430
|
28 ## @item out_idx |
|
29 ## @itemx in_idx |
5016
|
30 ## Names or indices of signals to connect (see @code{sysidx}). |
3462
|
31 ## The output specified by @math{out_idx(ii)} is connected to the input |
|
32 ## specified by @math{in_idx(ii)}. |
3430
|
33 ## @item order |
|
34 ## logical flag (default = 0) |
|
35 ## @table @code |
|
36 ## @item 0 |
5016
|
37 ## Leave inputs and outputs in their original order. |
3430
|
38 ## @item 1 |
5016
|
39 ## Permute inputs and outputs to the order shown in the diagram below. |
3430
|
40 ## @end table |
|
41 ## @item tol |
5016
|
42 ## Tolerance for singularities in algebraic loops, default: 200@code{eps}. |
3430
|
43 ## @end table |
|
44 ## |
|
45 ## @strong{Outputs} |
5016
|
46 ## @table @var |
|
47 ## @item clsys |
|
48 ## Resulting closed loop system. |
|
49 ## @end table |
3430
|
50 ## |
|
51 ## @strong{Method} |
5016
|
52 ## |
3430
|
53 ## @code{sysconnect} internally permutes selected inputs, outputs as shown |
|
54 ## below, closes the loop, and then permutes inputs and outputs back to their |
|
55 ## original order |
|
56 ## @example |
|
57 ## @group |
5016
|
58 ## -------------------- |
3430
|
59 ## u_1 ----->| |----> y_1 |
|
60 ## | sys | |
|
61 ## old u_2 | | |
|
62 ## u_2* ---->(+)--->| |----->y_2 |
5016
|
63 ## (in_idx) ^ -------------------- | (out_idx) |
3430
|
64 ## | | |
|
65 ## ------------------------------- |
|
66 ## @end group |
|
67 ## @end example |
|
68 ## The input that has the summing junction added to it has an * added to |
|
69 ## the end of the input name. |
|
70 ## @end deftypefn |
|
71 |
|
72 ## Author: A. S. Hodel <a.s.hodel@eng.auburn.edu> |
|
73 ## Created: August 1995 |
|
74 ## modified by John Ingram July 1996 |
|
75 |
|
76 function sys = sysconnect (sys, output_list, input_list, order, tol) |
|
77 |
7135
|
78 if (nargin < 3 || nargin > 5) |
6046
|
79 print_usage (); |
3430
|
80 endif |
|
81 |
|
82 ## check order |
7135
|
83 if (nargin < 4) |
3430
|
84 order = 0; |
7135
|
85 elseif (order != 0 && order != 1) |
|
86 error ("sysconnect: order must be either 0 or 1") |
3430
|
87 endif |
|
88 |
7135
|
89 if (nargin < 5) |
3430
|
90 tol = 200*eps; |
7135
|
91 elseif (! is_sample (tol)) |
|
92 error ("sysconnect: tol must be a positive scalar"); |
|
93 elseif (tol > 1e2*sqrt(eps)) |
|
94 warning ("sysconnect: tol set to large value=%g, eps=%g", tol, eps); |
3430
|
95 endif |
|
96 |
3462
|
97 ## convert signal names to indices |
7135
|
98 if (is_signal_list (input_list) || ischar (input_list)) |
|
99 input_list = sysidx (sys, "in", input_list); |
3462
|
100 endif |
7135
|
101 if (is_signal_list (output_list) || ischar (output_list)) |
|
102 output_list = sysidx (sys, "out", output_list); |
3462
|
103 endif |
|
104 |
3430
|
105 ## verify sizes,format of input, output lists |
7135
|
106 if (min (size (output_list)) * min (size (input_list)) != 1) |
|
107 error ("output_list and input_list must be vectors"); |
3430
|
108 else |
7135
|
109 lo = length (output_list); |
|
110 li = length (input_list); |
|
111 if (lo != li) |
|
112 error ("output_list and input_list must be of the same length") |
3430
|
113 endif |
|
114 |
7135
|
115 if (is_duplicate_entry (output_list) || is_duplicate_entry (input_list)) |
|
116 error ("duplicate entry in input_list and/or output_list"); |
3430
|
117 endif |
|
118 endif |
|
119 |
7135
|
120 [nc, nz, mm, pp] = sysdimensions (sys); |
3430
|
121 nn = nc+nz; |
|
122 |
7135
|
123 if (! isstruct (sys)) |
|
124 error ("sys must be in structured system form") |
|
125 elseif (pp < lo) |
|
126 error ("length(output_list)=%d, sys has only %d system outputs", lo, pp); |
|
127 elseif (mm < li) |
|
128 error ("length(input_list)=%d, sys has only %d system inputs", li, mm); |
3430
|
129 endif |
|
130 |
|
131 ## check that there are enough inputs/outputs in the system for the lists |
7135
|
132 if (max (input_list) > mm) |
|
133 error ("max(input_list) exceeds the number of inputs"); |
|
134 elseif (max (output_list) > pp) |
|
135 error ("max(output_list) exceeds the number of outputs"); |
3430
|
136 endif |
|
137 |
7135
|
138 output_list = reshape (output_list, 1, length (output_list)); |
3430
|
139 |
|
140 ## make sure we're in state space form |
|
141 sys = sysupdate (sys, "ss"); |
|
142 |
|
143 ## permute rows and columns of B,C,D matrices into pseudo-dgkf form... |
7135
|
144 all_inputs = sysreorder (mm, input_list); |
|
145 all_outputs = sysreorder (pp, output_list); |
3430
|
146 |
7135
|
147 [aa, bb, cc, dd] = sys2ss (sys); |
3430
|
148 bb = bb(:,all_inputs); |
|
149 cc = cc(all_outputs,:); |
|
150 dd = dd(all_outputs,all_inputs); |
|
151 |
7135
|
152 yd = sysgetsignals (sys, "yd"); |
3430
|
153 yd = yd(all_outputs); |
|
154 |
|
155 ## m1, p1 = number of inputs, outputs that are not being connected |
|
156 m1 = mm-li; |
|
157 p1 = pp-li; |
|
158 |
|
159 ## m2, p2: 1st column, row of B, C that is being connected |
|
160 m2 = m1+1; |
|
161 p2 = p1+1; |
|
162 |
|
163 ## partition system into a DGKF-like form; the loop is closed around |
|
164 ## B2, C2 |
7135
|
165 if (m1 > 0) |
3430
|
166 B1 = bb(:,1:m1); |
|
167 D21= dd(p2:pp,1:m1); |
|
168 endif |
|
169 B2 = bb(:,m2:mm); |
7135
|
170 if (p1 > 0) |
3430
|
171 C1 = cc(1:p1,:); |
|
172 D12= dd(1:p1,m2:mm); |
|
173 endif |
|
174 C2 = cc(p2:pp,:); |
7135
|
175 if (m1*p1 > 0) |
|
176 D11 = dd(1:p1,1:m1); |
3430
|
177 endif |
7135
|
178 D22 = dd(p2:pp,m2:mm); |
3430
|
179 |
7135
|
180 if (norm (D22)) |
|
181 warning ("sysconnect: possible algebraic loop, D22 non-zero"); |
|
182 D22i = eye (size (D22)) - D22; |
3430
|
183 C2h = D22i\C2; |
7135
|
184 if (m1 > 0) |
3430
|
185 D21h = D22i\D21; |
|
186 endif |
|
187 D22h = D22i\D22; |
|
188 else |
|
189 C2h = C2; |
7135
|
190 if (m1 > 0) |
3430
|
191 D21h = D21; |
|
192 endif |
|
193 D22h = D22; |
|
194 |
|
195 endif |
|
196 |
|
197 ## check cont state -> disc output -> cont state |
7135
|
198 dyi = find (yd(p2:pp)); |
3430
|
199 |
|
200 ## disp("sysconnect: dyi=") |
|
201 ## dyi |
|
202 ## nc |
|
203 ## disp("/sysconnect"); |
|
204 |
7137
|
205 if ((nc > 0) & find (dyi > 0)) |
3430
|
206 B2con = B2(1:nc,dyi); # connection to cont states |
|
207 C2hd = C2h(dyi,1:nc); # cont states -> outputs |
|
208 else |
|
209 B2con = C2hd = []; |
|
210 endif |
|
211 |
7135
|
212 if (max (size (B2con)) & max (size (C2hd))) |
|
213 if (norm (B2con*C2hd)) |
|
214 warning ("sysconnect: cont-state -> disc output -> cont state derivative"); |
|
215 warning ("connection made; resulting system may not be meaningful"); |
3430
|
216 endif |
|
217 endif |
|
218 |
|
219 Ac = aa+B2*C2h; |
7135
|
220 if (m1 > 0) |
3430
|
221 B1c = B1 + B2*D21h; |
|
222 endif |
|
223 B2c = B2*(eye(size(D22h)) + D22h); |
7135
|
224 if (p1*m1 > 0) |
3430
|
225 D11c = D11 + D12*D21h; |
|
226 endif |
7135
|
227 if (p1 > 0) |
3430
|
228 C1c = C1+D12*C2h; |
|
229 D12c = D12*(eye(size(D22h))+D22h); |
|
230 endif |
|
231 |
|
232 ## construct system data structure |
7135
|
233 if (m1 > 0) |
3430
|
234 Bc = [B1c, B2c]; |
|
235 else |
|
236 Bc = B2c; |
|
237 endif |
|
238 |
7135
|
239 if (p1 > 0) |
3430
|
240 Cc = [C1c;C2h]; |
|
241 else |
|
242 Cc = C2h; |
|
243 endif |
|
244 |
7135
|
245 if (m1*p1 > 0) |
3430
|
246 Dc = [D11c,D12c; D21h,D22h]; |
7135
|
247 elseif (m1 > 0) |
3430
|
248 Dc = [D21h, D22h]; |
7135
|
249 elseif (p1 > 0) |
3430
|
250 Dc = [D12c; D22h]; |
|
251 else |
|
252 Dc = D22h; |
|
253 endif |
|
254 |
|
255 ## permute rows and columns of Bc, Cc, Dc back into original order |
7135
|
256 Im = eye (mm, mm); |
3430
|
257 Pi = Im(:,all_inputs); |
|
258 back_inputs = Pi*[1:mm]'; |
|
259 |
7135
|
260 Ip = eye (pp, pp); |
3430
|
261 Po = Ip(:,all_outputs); |
|
262 back_outputs = Po*[1:pp]'; |
|
263 |
|
264 Bc = Bc(:,back_inputs); |
|
265 Cc = Cc(back_outputs,:); |
|
266 Dc = Dc(back_outputs,back_inputs); |
|
267 yd = yd(back_outputs); |
|
268 |
|
269 ## rebuild system |
7135
|
270 Ts = sysgettsam (sys); |
|
271 [stnam, innam, outnam] = sysgetsignals (sys); |
|
272 sys = ss (Ac, Bc, Cc, Dc, Ts, nc, nz, stnam, innam, outnam, find (yd)); |
3430
|
273 |
|
274 ## update connected input names |
|
275 for ii = 1:length(input_list) |
|
276 idx = input_list(ii); |
7135
|
277 tmpval = sysgetsignals (sys, "in", idx); |
|
278 strval = sprintf ("%s*", tmpval{1} ); |
|
279 sys = syssetsignals (sys, "in", strval, idx); |
3430
|
280 endfor |
|
281 |
|
282 ## maintain original system type if it was SISO |
|
283 if (strcmp (sysgettype (sys), "tf")) |
|
284 sysupdate (sys, "tf"); |
|
285 elseif (strcmp (sysgettype (sys),"zp")) |
|
286 sysupdate (sys, "zp"); |
|
287 endif |
|
288 |
|
289 endfunction |