Skip to content
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

add check on fundamental limitations #699

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions src/analysis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -598,3 +598,84 @@ function gangofseven(P::LTISystem, C::LTISystem, F::LTISystem)
RE = S*F
return S, PS, CS, T, RY, RU, RE
end

"""
lower, upper = fundamental_limitations(P::LTISystem{Continuous},[ C]; verbose=true)
Check the following list of rules-of-thumb for fundamental limitations on the gain-crossover frequency ωgc imposed by RHP poles and zeros and time delays.
- A RHP zero z: gives an upper bound to bandwidth: ωgc / z < 0.5
- A double RHP zero: ωgc / z < 0.25
- A time delay L gives an upper bound to bandwidth: ωgc * L < 1
- A RHP pole p gives a lower bound to bandwidth: ωgc / p > 2
- A double RHP pole: ωgc / p > 4
- A RHP pole zero pair requires: z / p > 4
These rules, give sensitivities Mₛ and Mₜ around 2 and phase lags of the nonminimum phase factor around 90°.
If a controller `C` is provided as the second argument, a check of the gain-crossover frequency of `P*C` is performed.
Ref: "Loop Shaping", Bo Bernhardsson and Karl Johan Åström 2016
"""
function fundamental_limitations(P::LTISystem{Continuous}, C=nothing; verbose=true, Ms = nothing)

ωgc_l = 0.0
ωgc_u = Inf

if P isa DelayLtiSystem
τ = maximum(P.Tau)
verbose && @info "ωgc upper bounded by a time delay to ωgc < 1/τ = $(1/τ) rad/s"
ωgc_u = min(ωgc_u, 1/τ)
return (; ωgc_l, ωgc_u)
end

ps = poles(P)
zs = tzeros(P)
rhpp = filter(p->real(p) > 0, ps)
rhpz = filter(z->real(z) > 0, zs)

p = maximum(abs, rhpp)
if length(rhpp) >= 2
verbose && @info "ωgc lower bounded by double RHP pole to ωgc > 4*p = $(4p) rad/s"
ωgc_l = 4p

elseif length(rhpp) == 1
verbose && @info "ωgc lower bounded by RHP pole to ωgc > 2*p = $(2p) rad/s"
ωgc_l = 2p
if Ms isa Number
ωgc_l2 = p*√((Ms+1)/(Ms-1)) # https://www.control.lth.se/fileadmin/control/staff/KJ/200113FeedbackFundamentals.pdf slide 51
verbose && @info "ωgc lower bounded by RHP pole and Ms to ωgc > p*√((Ms+1)/(Ms-1)) = $(p*√((Ms+1)/(Ms-1))) rad/s"
ωgc_l = max(ωgc_l, ωgc_l2)
end
end

z = maximum(abs, rhpz)
if length(rhpz) >= 2
verbose && @info "ωgc upper bounded by double RHP zero to ωgc < z/4 = $(z/4) rad/s"
ωgc_u = z/4
elseif length(rhpz) == 1
verbose && @info "ωgc upper bounded by RHP zero to ωgc < z/2 = $(z/2) rad/s"
ωgc_u = z/2

if Ms isa Number
ωgc_u2 = z*√((Ms-1)/(Ms+1)) # https://www.control.lth.se/fileadmin/control/staff/KJ/200113FeedbackFundamentals.pdf slide 51
verbose && @info "ωgc upper bounded by RHP zero and Ms to ωgc < z*√((Ms-1)/(Ms+1)) = $(z*√((Ms-1)/(Ms+1))) rad/s"
ωgc_u = min(ωgc_u, ωgc_u2)
end

end

if length(rhpp) > 1 && length(rhpz) > 1
verbose && @info "RHP pole and zero requires z > 4p which is $(z > 4p)"
verbose && @info "Ms and Mt are always larger than |(p+z) / (p-z)| = $(abs((p+z) / (p-z))) due to RHP pole and zero pair"
end

if C !== nothing
wgm, gm, wpm, pm = margin(P*C)
# ωgc = wpm
if isfinite(pm[]) # No gain crossover if phase margin is not finite
if (ωgc_l ≤ maximum(wpm) ≤ ωgc_u)
verbose && @info("Controller satisifes rules of thumb, ωgc = $wpm")
else
@error("Failed to meet rules-of-thumb with the given controller, ωgc = $wpm")
end
end
end

(; ωgc_l, ωgc_u)
end