Skip to content

Commit 38afacc

Browse files
authored
Merge pull request #952 from JuliaControl/fb2dof
make `feedback2dof` work for any system type
2 parents 5982cc3 + a7cd0f0 commit 38afacc

File tree

5 files changed

+55
-14
lines changed

5 files changed

+55
-14
lines changed

docs/src/man/creating_systems.md

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ Continuous-time transfer function model
3434
```
3535

3636
The transfer functions created using this method will be of type `TransferFunction{SisoRational}`.
37-
For more general expressions, it is often more convenient to define `s = tf("s")`:
37+
For more general expressions, it is sometimes more convenient to define `s = tf("s")` (only use this approach for low-order systems).:
3838
#### Example:
3939
```julia
4040
julia> s = tf("s")
@@ -295,10 +295,10 @@ The returned closed-loop system will have a state vector comprised of the state
295295
---
296296
Closed-loop system from reference to output
297297
```
298-
r ┌─────┐ ┌─────┐
299-
───►│ │ u │ │ y
300-
│ C ├────►│ P ├─┬─►
301-
-┌►│ │ │ │ │
298+
┌─────┐ ┌─────┐
299+
r │ │ u │ │ y
300+
──+►│ C ├────►│ P ├─┬─►
301+
-│ │ │ │ │
302302
│ └─────┘ └─────┘ │
303303
│ │
304304
└─────────────────────┘
@@ -396,6 +396,32 @@ Here, we have reversed the order of `P` and `C` to get the correct sign of the c
396396

397397
---
398398

399+
Two degree of freedom control system with feedforward ``F`` and feedback controller ``C``
400+
401+
```
402+
+-------+
403+
| |
404+
+-----> F +----+
405+
| | | |
406+
| +-------+ |
407+
| +-------+ | +-------+
408+
r | - | | | | | y
409+
+--+-----> C +----+----> P +---+-->
410+
| | | | | |
411+
| +-------+ +-------+ |
412+
| |
413+
+--------------------------------+
414+
```
415+
416+
```math
417+
Y = (F+C)\dfrac{P}{I + PC}R
418+
```
419+
420+
Code: `feedback(P,C)*(F+C)` or `feedback2dof(P, C, F)`
421+
- [`feedback2dof`](@ref)
422+
423+
---
424+
399425
Linear fractional transformation
400426

401427
```
@@ -445,9 +471,9 @@ I & P
445471
w_1 \\ w_2
446472
\end{bmatrix}
447473
```
448-
Code: This function requires the package [RobustAndOptimalControl.jl](https://juliacontrol.github.io/RobustAndOptimalControl.jl/dev/).
474+
Code:
449475
```julia
450-
RobustAndOptimalControl.extended_gangoffour(P, C, pos=true)
476+
extended_gangoffour(P, C, pos=true)
451477
# For SISO P
452478
S = G[1, 1]
453479
PS = G[1, 2]

lib/ControlSystemsBase/src/connections.jl

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,14 @@ function feedback(sys1::AbstractStateSpace, sys2::AbstractStateSpace;
331331
if !(isa(Y2, Colon) || allunique(Y2)); @warn "Connecting single output to multiple inputs Y2=$Y2"; end
332332
if !(isa(U1, Colon) || allunique(U1)); @warn "Connecting multiple outputs to a single input U1=$U1"; end
333333
if !(isa(U2, Colon) || allunique(U2)); @warn "Connecting a single output to multiple inputs U2=$U2"; end
334+
U1 isa Number && (U1 = [U1])
335+
Y1 isa Number && (Y1 = [Y1])
336+
U2 isa Number && (U2 = [U2])
337+
Y2 isa Number && (Y2 = [Y2])
338+
W1 isa Number && (W1 = [W1])
339+
Z1 isa Number && (Z1 = [Z1])
340+
W2 isa Number && (W2 = [W2])
341+
Z2 isa Number && (Z2 = [Z2])
334342

335343
if (U1 isa Colon ? size(sys1, 2) : length(U1)) != (Y2 isa Colon ? size(sys2, 1) : length(Y2))
336344
error("Lengths of U1 ($U1) and Y2 ($Y2) must be equal")
@@ -394,13 +402,13 @@ function feedback(sys1::AbstractStateSpace, sys2::AbstractStateSpace;
394402
R1 = try
395403
inv*I - s2_D22*s1_D22) # slightly faster than α*inv(I - α*s2_D22*s1_D22)
396404
catch
397-
error("Ill-posed feedback interconnection, I - α*s2_D22*s1_D22 or I - α*s2_D22*s1_D22 not invertible")
405+
error("Ill-posed feedback interconnection, I - α*s2_D22*s1_D22 not invertible")
398406
end
399407

400408
R2 = try
401409
inv(I - α*s1_D22*s2_D22)
402410
catch
403-
error("Ill-posed feedback interconnection, I - α*s2_D22*s1_D22 or I - α*s2_D22*s1_D22 not invertible")
411+
error("Ill-posed feedback interconnection, I - α*s1_D22*s2_D22 not invertible")
404412
end
405413

406414
s2_B2R2 = s2_B2*R2
@@ -442,7 +450,7 @@ end
442450
feedback2dof(B,A,R,S,T) = tf(conv(B,T),zpconv(A,R,B,S))
443451

444452
"""
445-
feedback2dof(P::TransferFunction, C::TransferFunction, F::TransferFunction)
453+
feedback2dof(P, C, F)
446454
447455
Return the transfer function
448456
`P(F+C)/(1+PC)`
@@ -463,7 +471,7 @@ r | - | | | | | y
463471
```
464472
"""
465473
function feedback2dof(P::TransferFunction{TE}, C::TransferFunction{TE}, F::TransferFunction{TE}) where TE
466-
!issiso(P) && error("Feedback not implemented for MIMO systems")
474+
issiso(P) || return tf(feedback2dof(ss(P), ss(C), ss(F)))
467475
timeevol = common_timeevol(P, C, F)
468476

469477
Pn,Pd = numpoly(P)[], denpoly(P)[]
@@ -473,6 +481,10 @@ function feedback2dof(P::TransferFunction{TE}, C::TransferFunction{TE}, F::Trans
473481
tf(Cd*Pn*Fn + Pn*Cn*Fd, den, timeevol)
474482
end
475483

484+
function feedback2dof(P,C,F)
485+
feedback(P,C)*(F+C)
486+
end
487+
476488
"""
477489
lft(G, Δ, type=:l)
478490

lib/ControlSystemsBase/src/pid_design.jl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,9 @@ The `form` can be chosen as one of the following (determines how the arguments `
131131
This controller has negative feedback built in, and the closed-loop system from `r` to `y` is thus formed as
132132
```
133133
Cr, Cy = C[1, 1], C[1, 2]
134-
feedback(P, Cy, pos_feedback=true)*Cr # Alternative 1
135-
feedback(P, -Cy)*Cr # Alternative 2
134+
feedback(P, Cy, pos_feedback=true)*Cr # Alternative 1
135+
feedback(P, -Cy)*Cr # Alternative 2
136+
feedback(P, C, U2=2, W2=1, W1=[], pos_feedback=true) # Alternative 3, less pretty but more efficient, returns smaller realization
136137
```
137138
"""
138139
function pid_2dof(args...; state_space = true, Ts = nothing, disc = :tustin, kwargs...)

lib/ControlSystemsBase/src/sensitivity_functions.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ T = G[P.ny+1:end, P.ny+1:end] # Input complimentary sensitivity function
156156
The gang of four can be plotted like so
157157
```julia
158158
Gcl = extended_gangoffour(G, C) # Form closed-loop system
159-
bodeplot(Gcl, lab=["S" "CS" "PS" "T"], plotphase=false) |> display # Plot gang of four
159+
bodeplot(Gcl, lab=["S" "PS" "CS" "T"], plotphase=false) |> display # Plot gang of four
160160
```
161161
Note, the last input of Gcl is the negative of the `PS` and `T` transfer functions from `gangoffour2`. To get a transfer matrix with the same sign as [`G_PS`](@ref) and [`input_comp_sensitivity`](@ref), call `extended_gangoffour(P, C, pos=false)`.
162162
See `glover_mcfarlane` from RobustAndOptimalControl.jl for an extended example. See also `ncfmargin` and `feedback_control` from RobustAndOptimalControl.jl.

lib/ControlSystemsBase/test/test_connections.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,8 @@ F = tf(1.0, [1,1])
294294
@test feedback2dof(P0, C, 0*F) == feedback(P0*C)
295295
@test_nowarn feedback2dof(P0, C, F)
296296

297+
C = pid(1, 0, 1, form=:parallel)
298+
hinfnorm(minreal(feedback2dof(ss(P0), ss(C*F), ss(F)) - feedback2dof(P0, C*F, F)))[1] < 1e-8
297299

298300

299301
G1 = tf([1, 0],[1, 2, 2])

0 commit comments

Comments
 (0)