@@ -255,77 +255,80 @@ function feedback(sys::Union{StateSpace, DelayLtiSystem})
255
255
end
256
256
257
257
function feedback (sys1:: StateSpace ,sys2:: StateSpace )
258
- sum (abs .(sys1. D)) != 0 && sum (abs .(sys2. D)) != 0 && error (" There can not be a direct term (D) in both sys1 and sys2" )
259
- A = [sys1. A+ sys1. B* (- sys2. D)* sys1. C sys1. B* (- sys2. C); sys2. B* sys1. C sys2. A+ sys2. B* sys1. D* (- sys2. C)]
258
+ if sys1. Ts != sys2. Ts # FIXME : replace with common_sample_time
259
+ error (" Sampling time mismatch" )
260
+ end
261
+
262
+ ! (iszero (sys1. D) || iszero (sys2. D)) && error (" There cannot be a direct term (D) in both sys1 and sys2" )
263
+ A = [sys1. A+ sys1. B* (- sys2. D)* sys1. C sys1. B* (- sys2. C);
264
+ sys2. B* sys1. C sys2. A+ sys2. B* sys1. D* (- sys2. C)]
260
265
B = [sys1. B; sys2. B* sys1. D]
261
266
C = [sys1. C sys1. D* (- sys2. C)]
262
- ss (A,B,C,sys1. D)
267
+
268
+ ss (A, B, C, sys1. D, sys1. Ts)
263
269
end
264
270
265
271
266
272
"""
267
273
feedback(s1::AbstractStateSpace, s2::AbstractStateSpace;
268
- U1=1:size(s1,2), Y1=1:size(s1,1), U2=1:size(s2,2), Y2=1:size(s2,1),
269
- W1=1:size(s1,2), Z1=1:size(s1,1), W2=Int[], Z2=Int[],
270
- w_reorder=nothing, z_reorder=nothing,n
271
- pos_feeback::Bool=false)
274
+ U1=:, Y1=:, U2=:, Y2=:, W1=:, Z1=:, W2=Int[], Z2=Int[],
275
+ Wperm=:, Zperm=:, pos_feedback::Bool=false)
272
276
273
277
274
- `U1`, `Y1`, `U2`, `Y2` contains the indices of the signals that should be connected.
275
- `W1`, `Z1`, `W2`, `Z2` contains the signal indices of `s1` and `s2` that should be kept.
278
+ `U1`, `Y1`, `U2`, `Y2` contain the indices of the signals that should be connected.
279
+ `W1`, `Z1`, `W2`, `Z2` contain the signal indices of `s1` and `s2` that should be kept.
276
280
277
- Specify `Wperm` and `Zperm` to reorder [W1; W2 ] and [Z1; Z2 ] in the resulting statespace model.
281
+ Specify `Wperm` and `Zperm` to reorder [w1; w2 ] and [z1; z2 ] in the resulting statespace model.
278
282
279
283
Negative feedback is the default. Specify `pos_feedback=true` for positive feedback.
280
284
281
285
See Zhou etc. for similar (somewhat less symmetric) formulas.
282
286
"""
283
- function feedback (s1:: AbstractStateSpace , s2:: AbstractStateSpace ;
284
- U1= 1 : size (s1,2 ), Y1= 1 : size (s1,1 ), U2= 1 : size (s2,2 ), Y2= 1 : size (s2,1 ),
285
- W1= 1 : size (s1,2 ), Z1= 1 : size (s1,1 ), W2= Int[], Z2= Int[],
286
- Wperm= nothing , Zperm= nothing ,
287
- pos_feedback:: Bool = false )
288
-
287
+ @views function feedback (sys1:: AbstractStateSpace , sys2:: AbstractStateSpace ;
288
+ U1= :, Y1= :, U2= :, Y2= :, W1= :, Z1= :, W2= Int[], Z2= Int[],
289
+ Wperm= :, Zperm= :, pos_feedback:: Bool = false )
289
290
291
+ if sys1. Ts != sys2. Ts # FIXME : replace with common_sample_time
292
+ error (" Sampling time mismatch" )
293
+ end
290
294
295
+ #= must define allunique(c::Colon) = true for the following checks to work
291
296
if !allunique(Y1); @warn "Connecting single output to multiple inputs Y1=$Y1"; end
292
297
if !allunique(Y2); @warn "Connecting single output to multiple inputs Y2=$Y2"; end
293
298
if !allunique(U1); @warn "Connecting multiple outputs to a single input U1=$U1"; end
294
299
if !allunique(U2); @warn "Connecting a single output to multiple inputs U2=$U2"; end
300
+ =#
295
301
296
- if length (U1) != length (Y2)
297
- error (" Dimensions of input u1 ( $( length ( U1)) ) and output y2 ( $( length (Y2)) ) must be equal" )
302
+ if (U1 isa Colon ? size (sys1, 2 ) : length (U1)) != (Y2 isa Colon ? size (sys2, 1 ) : length (Y2) )
303
+ error (" Lengths of U1 ( $ U1 ) and Y2 ( $Y2 ) must be equal" )
298
304
end
299
- if length (U2) != length (Y1)
300
- error (" Dimensions of input u2 ( $( length ( U2)) ) and output y1 ( $( length (Y2)) ) must be equal" )
305
+ if (U2 isa Colon ? size (sys2, 2 ) : length (U2)) != (Y1 isa Colon ? size (sys1, 1 ) : length (Y1) )
306
+ error (" Lengths of U1 ( $ U2 ) and Y2 ( $Y1 ) must be equal" )
301
307
end
302
308
303
-
304
-
305
309
α = pos_feedback ? 1 : - 1 # The sign of feedback
306
310
307
- s1_B1 = s1. B[:,W1]
308
- s1_B2 = s1. B[:,U1]
309
- s1_C1 = s1. C[Z1,:]
310
- s1_C2 = s1. C[Y1,:]
311
- s1_D11 = s1. D[Z1,W1]
312
- s1_D12 = s1. D[Z1,U1]
313
- s1_D21 = s1. D[Y1,W1]
314
- s1_D22 = s1. D[Y1,U1]
315
-
316
- s2_B1 = s2. B[:,W2]
317
- s2_B2 = s2. B[:,U2]
318
- s2_C1 = s2. C[Z2,:]
319
- s2_C2 = s2. C[Y2,:]
320
- s2_D11 = s2. D[Z2,W2]
321
- s2_D12 = s2. D[Z2,U2]
322
- s2_D21 = s2. D[Y2,W2]
323
- s2_D22 = s2. D[Y2,U2]
324
-
311
+ s1_B1 = sys1. B[:,W1]
312
+ s1_B2 = sys1. B[:,U1]
313
+ s1_C1 = sys1. C[Z1,:]
314
+ s1_C2 = sys1. C[Y1,:]
315
+ s1_D11 = sys1. D[Z1,W1]
316
+ s1_D12 = sys1. D[Z1,U1]
317
+ s1_D21 = sys1. D[Y1,W1]
318
+ s1_D22 = sys1. D[Y1,U1]
319
+
320
+ s2_B1 = sys2. B[:,W2]
321
+ s2_B2 = sys2. B[:,U2]
322
+ s2_C1 = sys2. C[Z2,:]
323
+ s2_C2 = sys2. C[Y2,:]
324
+ s2_D11 = sys2. D[Z2,W2]
325
+ s2_D12 = sys2. D[Z2,U2]
326
+ s2_D21 = sys2. D[Y2,W2]
327
+ s2_D22 = sys2. D[Y2,U2]
325
328
326
329
if iszero (s1_D22) || iszero (s2_D22)
327
- A = [s1 . A + α* s1_B2* s2_D22* s1_C2 α* s1_B2* s2_C2;
328
- s2_B2* s1_C2 s2 . A + α* s2_B2* s1_D22* s2_C2]
330
+ A = [sys1 . A + α* s1_B2* s2_D22* s1_C2 α* s1_B2* s2_C2;
331
+ s2_B2* s1_C2 sys2 . A + α* s2_B2* s1_D22* s2_C2]
329
332
330
333
B = [s1_B1 + α* s1_B2* s2_D22* s1_D21 α* s1_B2* s2_D21;
331
334
s2_B2* s1_D21 s2_B1 + α* s2_B2* s1_D22* s2_D21]
@@ -334,26 +337,34 @@ function feedback(s1::AbstractStateSpace, s2::AbstractStateSpace;
334
337
D = [s1_D11 + α* s1_D12* s2_D22* s1_D21 α* s1_D12* s2_D21;
335
338
s2_D12* s1_D21 s2_D11 + α* s2_D12* s1_D22* s2_D21]
336
339
else
337
- R1 = inv (I - α* s2_D22* s1_D22) # inv seems to be better than lu
338
- R2 = inv (I - α* s1_D22* s2_D22)
339
-
340
- A = [s1. A + α* s1_B2* R1* s2_D22* s1_C2 α* s1_B2* R1* s2_C2;
341
- s2_B2* R2* s1_C2 s2. A + α* s2_B2* R2* s1_D22* s2_C2]
342
-
343
- B = [s1_B1 + α* s1_B2* R1* s2_D22* s1_D21 α* s1_B2* R1* s2_D21;
340
+ # inv seems to be better than lu
341
+ R1 = try
342
+ inv (α* I - s2_D22* s1_D22) # slightly faster than α*inv(I - α*s2_D22*s1_D22)
343
+ catch
344
+ error (" Illposed feedback interconnection, I - α*s2_D22*s1_D22 or I - α*s2_D22*s1_D22 not invertible" )
345
+ end
346
+
347
+ R2 = try
348
+ inv (I - α* s1_D22* s2_D22)
349
+ catch
350
+ error (" Illposed feedback interconnection, I - α*s2_D22*s1_D22 or I - α*s2_D22*s1_D22 not invertible" )
351
+ end
352
+
353
+ A = [sys1. A + s1_B2* R1* s2_D22* s1_C2 s1_B2* R1* s2_C2;
354
+ s2_B2* R2* s1_C2 sys2. A + α* s2_B2* R2* s1_D22* s2_C2]
355
+
356
+ B = [s1_B1 + s1_B2* R1* s2_D22* s1_D21 s1_B2* R1* s2_D21;
344
357
s2_B2* R2* s1_D21 s2_B1 + α* s2_B2* R2* s1_D22* s2_D21]
345
- C = [s1_C1 + α * s1_D12* R1* s2_D22* s1_C2 α * s1_D12* R1* s2_C2;
358
+ C = [s1_C1 + s1_D12* R1* s2_D22* s1_C2 s1_D12* R1* s2_C2;
346
359
s2_D12* R2* s1_C2 s2_C1 + α* s2_D12* R2* s1_D22* s2_C2]
347
- D = [s1_D11 + α * s1_D12* R1* s2_D22* s1_D21 α * s1_D12* R1* s2_D21;
360
+ D = [s1_D11 + s1_D12* R1* s2_D22* s1_D21 s1_D12* R1* s2_D21;
348
361
s2_D12* R2* s1_D21 s2_D11 + α* s2_D12* R2* s1_D22* s2_D21]
349
362
end
350
- # Return while reorganizing into the desired order
351
- return StateSpace (A, isnothing (Wperm) ? B : B[:, Wperm],
352
- isnothing (Zperm) ? C : C[Zperm,:],
353
- isnothing (Wperm) && isnothing (Zperm) ? D : D[Zperm, Wperm])
354
- # return StateSpace(A, B_tmp, C_tmp, D_tmp)
363
+
364
+ return StateSpace (A, B[:, Wperm], C[Zperm,:], D[Zperm, Wperm], sys1. Ts)
355
365
end
356
366
367
+
357
368
"""
358
369
`feedback2dof(P,R,S,T)` Return `BT/(AR+ST)` where B and A are the numerator and denomenator polynomials of `P` respectively
359
370
`feedback2dof(B,A,R,S,T)` Return `BT/(AR+ST)`
@@ -369,28 +380,32 @@ feedback2dof(B,A,R,S,T) = tf(conv(B,T),zpconv(A,R,B,S))
369
380
"""
370
381
lft(G, Δ, type=:l)
371
382
372
- Upper linear fractional transformation between systems `G` and `Δ`.
383
+ Lower and upper linear fractional transformation between systems `G` and `Δ`.
384
+
385
+ Specify `:l` lor lower LFT, and `:u` for upper LFT.
386
+
373
387
`G` must have more inputs and outputs than `Δ` has outputs and inputs.
374
388
375
389
For details, see Chapter 9.1 in
376
390
**Zhou, K. and JC Doyle**. Essentials of robust control, Prentice hall (NJ), 1998
377
391
"""
378
- function lft (G, Δ, type= :l ) # QUESTION: Or lft_u, and lft_l instead?
392
+ function lft (G, Δ, type= :l )
379
393
380
394
if ! (G. nu > Δ. ny && G. ny > Δ. nu)
381
- error (" Must have G.nu > Δ.ny and G.ny > Δ.nu for lower/upper lft. " )
395
+ error (" Must have G.nu > Δ.ny and G.ny > Δ.nu for lower/upper lft" )
382
396
end
383
397
384
398
if type == :l
385
399
feedback (G, Δ, U1= G. nu- Δ. ny+ 1 : G. nu, Y1= G. ny- Δ. nu+ 1 : G. ny, W1= 1 : G. ny- Δ. nu, Z1= 1 : G. nu- Δ. ny, pos_feedback= true )
386
400
elseif type == :u
387
401
feedback (G, Δ, U1= 1 : Δ. ny, Y1= 1 : Δ. nu, W1= Δ. nu+ 1 : G. ny, Z1= Δ. nu+ 1 : G. ny, pos_feedback= true )
388
402
else
389
- error (" Invalid type of lft ($type ). Specify type=:l (:u) for lower (upper) lft. " )
403
+ error (" Invalid type of lft ($type ), specify type=:l (:u) for lower (upper) lft" )
390
404
end
391
405
end
392
406
393
407
408
+
394
409
"""
395
410
starprod(sys1, sys2, dimu, dimy)
396
411
0 commit comments