Skip to content

Commit 0d8d0df

Browse files
committed
add notes on solving for open loop from closed loop
1 parent 4052167 commit 0d8d0df

File tree

1 file changed

+40
-1
lines changed

1 file changed

+40
-1
lines changed

docs/src/man/creating_systems.md

+40-1
Original file line numberDiff line numberDiff line change
@@ -520,4 +520,43 @@ vline!([5 10], l=(:black, :dash), label="Band-pass limits", sp=1)
520520
```
521521

522522
See also
523-
- [`ControlSystemsBase.seriesform`](@ref)
523+
- [`ControlSystemsBase.seriesform`](@ref)
524+
525+
## Open loop in terms of closed loop
526+
The following identities are useful when solving for open-loop transfer functions in terms of closed-loop transfer functions. This is relevant, e.g., when system identification has to be performed in closed-loop.
527+
```math
528+
\begin{aligned}
529+
L_o &= PC \\
530+
L_i &= CP \\
531+
L_x &= S_x^{-1} - I \\
532+
L_x &= T_x (I - T_x)^{-1} \\
533+
(I + L)^{-1} &= I - (I + L)^{-1}L = I - L(I + L)^{-1} \text{("push-through identity")} \Rightarrow\\
534+
\Rightarrow S &= I - T \qquad S + T = I\\
535+
G &= (I + PC)^{-1}P \Longrightarrow P = G(I - CG)^{-1} \\
536+
G &= (I + CP)^{-1}C \Longrightarrow C = G(I - PG)^{-1} \\
537+
\end{aligned}
538+
```
539+
Solving for ``P`` from ``S`` or ``T`` naively requires ``C`` to be invertible (and vice versa). Solving for ``P`` from ``SP = (I + PC)^{-1}P`` is thus recommended. See also [`DescriptorSystems.grsol`](https://andreasvarga.github.io/DescriptorSystems.jl/dev/advanced_operations.html#DescriptorSystems.grsol) (and the corresponding `glsol`) which can solve transfer-matrix equations like `PC = B` for ``C`` when ``P`` is not invertible. The solution is only unique if the largest transfer function between ``S_o`` and ``S_i``, or between ``T_o`` and ``T_i`` is used.
540+
541+
As an example, below we solve for ``P`` using ``S_o \in \mathbb{C}^{2 \times 2}`` which produces the correct result
542+
```julia
543+
using ControlSystemsBase, DescriptorSystems, Plots, LinearAlgebra
544+
P = ssrand(2,1,2)
545+
C = ssrand(1,2,2)
546+
S = output_sensitivity(P, C)
547+
P′ = (inv(S)-I(2)) / C # Errors due to C not being invertible
548+
DescriptorSystems.dss(sys::ControlSystemsBase.StateSpace) = DescriptorSystems.dss(sys.A, sys.B, sys.C, sys.D; Ts = ControlSystemsBase.isdiscrete(sys) ? sys.Ts : 0)
549+
P′d, _ = DescriptorSystems.glsol(dss(C), dss(inv(S)-I(2)))
550+
P′s, _ = dss2ss(P′d)
551+
P′ = ss(P′s.A, P′s.B, P′s.C, P′s.D)
552+
bodeplot([P, P′])
553+
```
554+
555+
Had we used ``S_i \in \mathbb{C}^{1 \times 1}`` instead, we would generally not have obtained the correct ``P`` since this system of equations is underdetermined
556+
```julia
557+
Si = input_sensitivity(P, C)
558+
P′d, _ = DescriptorSystems.grsol(dss(C), dss(inv(Si)-I(1)))
559+
P′s, _ = dss2ss(P′d)
560+
P′ = ss(P′s.A, P′s.B, P′s.C, P′s.D)
561+
bodeplot([P, P′])
562+
```

0 commit comments

Comments
 (0)