-
Notifications
You must be signed in to change notification settings - Fork 89
use timeevol types to dispatch matrix equations #629
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,42 +1,52 @@ | ||
| """`care(A, B, Q, R)` | ||
| """ | ||
| are(::Continuous, A, B, Q, R) | ||
|
|
||
| Compute 'X', the solution to the continuous-time algebraic Riccati equation, | ||
| defined as A'X + XA - (XB)R^-1(B'X) + Q = 0, where R is non-singular. | ||
|
|
||
| Uses `MatrixEquations.arec`. | ||
| """ | ||
| function care(A, B, Q, R) | ||
| function are(::ContinuousType, A::AbstractMatrix, B, Q, R) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why type on
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assume there is a reason since I see it is done on a few more spots, just curios and want to understand :)
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If I do not type the |
||
| arec(A, B, R, Q)[1] | ||
| end | ||
|
|
||
| care(A::Number, B::Number, Q::Number, R::Number) = care(fill(A,1,1),fill(B,1,1),fill(Q,1,1),fill(R,1,1)) | ||
|
|
||
| """ | ||
| dare(A, B, Q, R; kwargs...) | ||
| are(::Discrete, A, B, Q, R; kwargs...) | ||
|
|
||
| Compute `X`, the solution to the discrete-time algebraic Riccati equation, | ||
| defined as A'XA - X - (A'XB)(B'XB + R)^-1(B'XA) + Q = 0, where Q>=0 and R>0 | ||
|
|
||
| Uses `MatrixEquations.ared`. For keyword arguments, see the docstring of `ControlSystems.MatrixEquations.ared` | ||
| """ | ||
| function dare(A, B, Q, R; kwargs...) | ||
| function are(::DiscreteType, A::AbstractMatrix, B, Q, R; kwargs...) | ||
| ared(A, B, R, Q; kwargs...)[1] | ||
| end | ||
|
|
||
| dare(A::Number, B::Number, Q::Number, R::Number) = dare(fill(A,1,1),fill(B,1,1),fill(Q,1,1),fill(R,1,1)) | ||
| are(t::TimeEvolType, A::Number, B::Number, Q::Number, R::Number) = are(t, fill(A,1,1),fill(B,1,1),fill(Q,1,1),fill(R,1,1)) | ||
|
|
||
| @deprecate care(args...; kwargs...) are(Continuous, args...; kwargs...) | ||
| @deprecate dare(args...; kwargs...) are(Discrete, args...; kwargs...) | ||
|
|
||
| """ | ||
| dlyap(A, Q; kwargs...) | ||
| lyap(A, Q; kwargs...) | ||
|
|
||
| Compute the solution `X` to the discrete Lyapunov equation | ||
| `AXA' - X + Q = 0`. | ||
|
|
||
| Uses `MatrixEquations.lyapd`. For keyword arguments, see the docstring of `ControlSystems.MatrixEquations.lyapd` | ||
| """ | ||
| function dlyap(A::AbstractMatrix, Q; kwargs...) | ||
| function lyap(::DiscreteType, A::AbstractMatrix, Q; kwargs...) | ||
| lyapd(A, Q; kwargs...) | ||
| end | ||
|
|
||
| LinearAlgebra.lyap(::ContinuousType, args...; kwargs...) = lyap(args...; kwargs...) | ||
| LinearAlgebra.lyap(::DiscreteType, args...; kwargs...) = dlyap(args...; kwargs...) | ||
|
|
||
| plyap(::ContinuousType, args...; kwargs...) = MatrixEquations.plyapc(args...; kwargs...) | ||
| plyap(::DiscreteType, args...; kwargs...) = MatrixEquations.plyapd(args...; kwargs...) | ||
|
|
||
| @deprecate dlyap(args...; kwargs...) lyap(Discrete, args...; kwargs...) | ||
|
|
||
|
|
||
| """ | ||
| U = grampd(sys, opt; kwargs...) | ||
|
|
@@ -53,11 +63,10 @@ function grampd(sys::AbstractStateSpace, opt::Symbol; kwargs...) | |
| if !isstable(sys) | ||
| error("gram only valid for stable A") | ||
| end | ||
| func = iscontinuous(sys) ? MatrixEquations.plyapc : MatrixEquations.plyapd | ||
| if opt === :c | ||
| func(sys.A, sys.B; kwargs...) | ||
| plyap(sys.timeevol, sys.A, sys.B; kwargs...) | ||
| elseif opt === :o | ||
| func(sys.A', sys.C'; kwargs...) | ||
| plyap(sys.timeevol, sys.A', sys.C'; kwargs...) | ||
| else | ||
| error("opt must be either :c for controllability grammian, or :o for | ||
| observability grammian") | ||
|
|
@@ -147,10 +156,9 @@ function covar(sys::AbstractStateSpace, W) | |
| if !isstable(sys) | ||
| return fill(Inf,(size(C,1),size(C,1))) | ||
| end | ||
| func = iscontinuous(sys) ? plyapc : plyapd | ||
| Wc = cholesky(W).L | ||
| Q1 = sys.nx == 0 ? B*Wc : try | ||
| func(A, B*Wc) | ||
| plyap(sys.timeevol, A, B*Wc) | ||
| catch e | ||
| @error("No solution to the Lyapunov equation was found in covar.") | ||
| rethrow(e) | ||
|
|
@@ -178,7 +186,7 @@ covar(sys::TransferFunction, W) = covar(ss(sys), W) | |
| # Note: the H∞ norm computation is probably not as accurate as with SLICOT, | ||
| # but this seems to be still reasonably ok as a first step | ||
| """ | ||
| `.. norm(sys, p=2; tol=1e-6)` | ||
| norm(sys, p=2; tol=1e-6) | ||
|
|
||
| `norm(sys)` or `norm(sys,2)` computes the H2 norm of the LTI system `sys`. | ||
|
|
||
|
|
@@ -206,7 +214,7 @@ LinearAlgebra.norm(sys::TransferFunction, p::Real=2; tol=1e-6) = norm(ss(sys), p | |
|
|
||
|
|
||
| """ | ||
| ` (Ninf, ω_peak) = hinfnorm(sys; tol=1e-6)` | ||
| Ninf, ω_peak = hinfnorm(sys; tol=1e-6) | ||
|
|
||
| Compute the H∞ norm `Ninf` of the LTI system `sys`, together with a frequency | ||
| `ω_peak` at which the gain Ninf is achieved. | ||
|
|
@@ -234,7 +242,7 @@ hinfnorm(sys::AbstractStateSpace{<:Discrete}; tol=1e-6) = _infnorm_two_steps_dt( | |
| hinfnorm(sys::TransferFunction; tol=1e-6) = hinfnorm(ss(sys); tol=tol) | ||
|
|
||
| """ | ||
| ` (Ninf, ω_peak) = linfnorm(sys; tol=1e-6)` | ||
| Ninf, ω_peak = linfnorm(sys; tol=1e-6) | ||
|
|
||
| Compute the L∞ norm `Ninf` of the LTI system `sys`, together with a frequency | ||
| `ω_peak` at which the gain `Ninf` is achieved. | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't really followed the discussion about these changes, but to me it feels slightly strange with
Discreteas first argument. But I guess you always have to supply an argument, we don't want to make one default?The other one where you send in a system looks nice, so maybe it makes sense that the system information comes in with the leftmost argument in some type of consistency with that.
Nothing I have strong feelings about, just reacted to it and unsure if there are good alternatives (I don't have any that I think are really better)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having one as default is part of what we're trying to get away from, since
lqr(sys)andlqr(A, B)then not mean the same if the system is discrete. The idea here was to use the namelqrrather thanlqr/lqrdand at the same time allow for dispatch onsys.timeevolrather than having manualif isdiscrete(sys)everywhere.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, makes sense.