-
Notifications
You must be signed in to change notification settings - Fork 84
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #118 from JuliaControl/autodiff
Generic types, major rewriting, bugfixes and several tests, finally!
- Loading branch information
Showing
61 changed files
with
2,920 additions
and
2,319 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
julia 0.6.0 | ||
julia 0.6.0 0.7.0 | ||
Plots 0.7.4 | ||
Polynomials | ||
Polynomials 0.3.0 | ||
LaTeXStrings | ||
Requires | ||
OrdinaryDiffEq | ||
IterTools |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,5 @@ sminreal | |
ss | ||
ss2tf | ||
tf | ||
tfg | ||
zpk | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
using ControlSystems, OrdinaryDiffEq, NLopt, BlackBoxOptim | ||
p0 = Float64[0.2,0.8,1] # Initial guess | ||
K(kp,ki,kd) = pid(kp=kp, ki=ki, kd=kd) | ||
K(p) = K(p...) | ||
|
||
# Define process model | ||
ζ = 0.1 | ||
ω = 1.; ω² = ω^2 | ||
P = tf(ω²,[1, 2ζ*ω, ω²])*tf(1,[1,1]) | ||
|
||
Ω = logspace(-1,2,150) # Frequency vector to eval constraints | ||
h = 0.1 # Sample time for time-domain evaluation | ||
Tf = 60. # Time horizon | ||
t = 0:h:Tf-h | ||
|
||
Ms = 1.4 # Maximum allowed magnitude of sensitivity function | ||
Mt = 1.4 # Maximum allowed magnitude of complimentary sensitivity function | ||
|
||
p = copy(p0) | ||
|
||
function timedomain(p) | ||
C = K(p[1], p[2], p[3]) | ||
S = 1/(1+P*C) # Sensitivity fun | ||
PS = ss(P*S) # TF from load disturbance to output | ||
s = Simulator(PS, (t,x) -> [1]) # Sim. unit step load disturbance | ||
ty = eltype(p) # So that all inputs to solve have same numerical type (ForwardDiff.Dual) | ||
x0 = zeros(PS.nx) .|> ty | ||
tspan = (ty(0.),ty(Tf)) | ||
sol = solve(s, x0, tspan, Tsit5()) | ||
y = PS.C*sol(t) # y = C*x | ||
C,y | ||
end | ||
|
||
function freqdomain(p) | ||
C = K(p[1], p[2], p[3]) | ||
S = 1/(1+P*C) # Sensitivity fun | ||
T = tf(1.) - S# Comp. Sensitivity fun | ||
Sw = vec(bode(S,Ω)[1]) # Freq. domain constraints | ||
Tw = vec(bode(T,Ω)[1]) # Freq. domain constraints | ||
Sw,Tw | ||
end | ||
|
||
# Evaluates and plots candidate controller | ||
function evalsol(p::Vector) | ||
C,y = timedomain(p) | ||
Sw,Tw = freqdomain(p) | ||
plot(t,y', layout=2, show=false) | ||
plot!(Ω, [Sw Tw] , lab=["Sw" "Tw"], subplot=2, xscale=:log10, yscale=:log10, show=false) | ||
plot!([Ω[1],Ω[end]], [Ms,Ms], c = :black, l=:dash, subplot=2, show=false, lab="Ms") | ||
plot!([Ω[1],Ω[end]], [Mt,Mt], c = :purple, l=:dash, subplot=2, lab="Mt") | ||
gui() | ||
false | ||
end | ||
evalsol(res::BlackBoxOptim.OptimizationResults) = evalsol(best_candidate(res)) | ||
|
||
|
||
function constraintfun(p) | ||
Sw,Tw = freqdomain(p) | ||
[maximum(Sw)-Ms; maximum(Tw)-Mt] | ||
end | ||
|
||
|
||
function costfun(p) | ||
C,y = timedomain(p) | ||
mean(abs,y) # ~ Integrated absolute error IAE | ||
end | ||
|
||
|
||
function runopt(p, costfun, constraintfun; | ||
f_tol = 1e-5, | ||
x_tol = 1e-3, | ||
c_tol = 1e-8, | ||
f_cfg = ForwardDiff.GradientConfig(costfun, p), | ||
g_cfg = ForwardDiff.JacobianConfig(constraintfun, p), | ||
lb = zeros(length(p))) | ||
|
||
c1 = constraintfun(p) | ||
np = length(p) | ||
nc = length(c1) | ||
|
||
function f(p::Vector, grad::Vector) | ||
if length(grad) > 0 | ||
grad .= ForwardDiff.gradient(costfun,p,f_cfg) | ||
end | ||
costfun(p) | ||
end | ||
|
||
function c(result, p::Vector, grad) | ||
if length(grad) > 0 | ||
grad .= ForwardDiff.jacobian(constraintfun,p,g_cfg)' | ||
end | ||
result .= constraintfun(p) | ||
end | ||
|
||
opt = Opt(:LD_SLSQP, np) | ||
lower_bounds!(opt, lb) | ||
xtol_rel!(opt, x_tol) | ||
ftol_rel!(opt, f_tol) | ||
|
||
min_objective!(opt, f) | ||
inequality_constraint!(opt, c, c_tol*ones(nc)) | ||
minf,minx,ret = NLopt.optimize(opt, p) | ||
end | ||
|
||
f_cfg = ForwardDiff.GradientConfig(costfun, p) | ||
g_cfg = ForwardDiff.JacobianConfig(constraintfun, p) | ||
@time minf,minx,ret = runopt(1p0, costfun, constraintfun, x_tol=1e-6, c_tol=1e-12, f_cfg=f_cfg, g_cfg=g_cfg) | ||
evalsol(minx) | ||
|
||
# # Optimize costfun using derivative-free method | ||
# res1 = compare_optimizers(costfun; SearchRange = (0.,2.), NumDimensions = length(p0), MaxTime = 20.0) | ||
# res2 = bboptimize(costfun, NumDimensions = length(p0), MaxTime = 20.0) | ||
# evalsol(res2) | ||
# p = best_candidate(res2) |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
using Revise | ||
using ControlSystems | ||
using SymPy | ||
|
||
# Some basic demonstations of working with symbolic LTI systems | ||
# Functionality is rather limited, and for complicated expressions the | ||
# printing is awful. Anyway, let's get started... | ||
|
||
|
||
# Need to modify some functions, to work with the Sym type | ||
# Some of these changes are on their way into the respective packages | ||
Base.complex(::Type{SymPy.Sym}) = Sym | ||
Base.eigvals(a::Matrix{Sym}) = Vector{Sym}(collect(keys(call_matrix_meth(a, :eigenvals)))) | ||
|
||
function Polynomials.roots(p::Polynomials.Poly{SymPy.Sym}) | ||
x = Sym("x") | ||
return SymPy.solve(p(x), x) | ||
end | ||
|
||
function SymPy.simplify(G::TransferFunction{ControlSystems.SisoZpk{Sym,Sym}}) | ||
z, p, k = zpkdata(G) | ||
|
||
return zpk(map(x->simplify.(x), z), map(x->simplify.(x), p), map(x->simplify.(x), k)) | ||
end | ||
|
||
function ControlSystems.impulse(sys::StateSpace{Sym}) | ||
t = symbols("t", real=true) | ||
return simplify.(sys.C * exp(sys.A*t) * sys.B) | ||
end | ||
|
||
|
||
# Define a symbolic parameter | ||
a = symbols("a", real=true) | ||
|
||
# Define a statespace and a trasnfer function | ||
sys = ss([1 a; a 1], [0; 1], [1 0], 0) | ||
|
||
s = tf("s") | ||
G = (s/(5a)) / ((s/a)^2 + s/(5a) + 1) | ||
|
||
|
||
# Simple conversions | ||
@edit zpk(sys) | ||
tf(sys) | ||
|
||
# The coefficient looks a bit complicated, but simplifying gives.. | ||
z, p, k = zpkdata(tf(sys)) | ||
simplify.(k[1]) | ||
|
||
zpkdata(G) | ||
ss(G) | ||
|
||
|
||
# Controllability/observability matrices | ||
Mc = ctrb(sys) | ||
Mo = obsv(sys) | ||
|
||
|
||
## Compute the L∞ norm (or actually L∞ norm squared) for two symbolic systems | ||
w = symbols("w", real=true) | ||
|
||
sys_to_consider = sys # G | ||
|
||
sys_fr = simplify(evalfr(sys_to_consider, im*w)[1]) | ||
sys_fr_mag = simplify(abs(sys_fr)^2) | ||
|
||
n, _ = fraction( diff(sys_fr_mag, w) ) | ||
roots = SymPy.solve(SymPy.Poly(n), w) | ||
|
||
real_roots = roots[SymPy.imag(roots) .== 0] | ||
|
||
maximum([subs(sys_fr_mag, w => r) for r in real_roots]) | ||
|
||
|
||
# Compute the impulse resonse of some systems (on statespace form) | ||
impulse(sys)[1] | ||
simplify(impulse(ss(G))[1]) | ||
|
||
rosenbrock = [1/(s+1) 1/(s+a); 1/(s+1) 1/(s+1)] | ||
ss(rosenbrock) | ||
impulse(ss(rosenbrock)) | ||
|
||
|
||
# Analytic impulse response | ||
sys2 = ss([-2.5 0;1 1.5],[1;3],[1 2],Sym(2.5)) | ||
impulse(sys2)[1] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.