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

Release 0.5.4 option2 #236

Merged
merged 10 commits into from
Nov 12, 2019
Merged
Show file tree
Hide file tree
Changes from 7 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
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ language: julia
julia:
- 1.0
- 1.1
- 1.2
- nightly
matrix:
allow_failures:
Expand Down
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name = "ControlSystems"
uuid = "a6e380b2-a6ca-5380-bf3e-84a91bcd477e"
authors = ["Dept. Automatic Control, Lund University"]
repo = "https://github.com/JuliaControl/ControlSystems.jl.git"
version = "0.5.3"
version = "0.5.4"

[deps]
Colors = "5ae59095-9a9b-59fe-a467-6f913c188581"
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ Pkg.add("ControlSystems")
```

## News
### 2019-11-03
- Poles and zeros are "not sorted" as in Julia versions < 1.2, even on newer versions of Julia. This should imply that complex conjugates are kept together.

### 2019-05-28
#### Delay systems
- We now support systems with time delays. Example:
Expand Down
4 changes: 3 additions & 1 deletion src/ControlSystems.jl
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,9 @@ export LTISystem,


# QUESTION: are these used? LaTeXStrings, Requires, IterTools
using Polynomials, Plots, LaTeXStrings, LinearAlgebra
using Plots, LaTeXStrings, LinearAlgebra
import Polynomials
import Polynomials: Poly, coeffs, polyval
using OrdinaryDiffEq, DelayDiffEq
export Plots
import Base: +, -, *, /, (==), (!=), isapprox, convert, promote_op
Expand Down
4 changes: 2 additions & 2 deletions src/analysis.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""`pole(sys)`

Compute the poles of system `sys`."""
pole(sys::AbstractStateSpace) = eigvals(sys.A)
pole(sys::AbstractStateSpace) = eigvalsnosort(sys.A)
pole(sys::SisoTf) = error("pole is not implemented for type $(typeof(sys))")

# Seems to have a lot of rounding problems if we run the full thing with sisorational,
Expand Down Expand Up @@ -224,7 +224,7 @@ function tzero(A::AbstractMatrix{T}, B::AbstractMatrix{T}, C::AbstractMatrix{T},
m = size(D_rc, 2)
Af = ([A_rc B_rc] * W)[1:nf, 1:nf]
Bf = ([Matrix{T}(I, nf, nf) zeros(nf, m)] * W)[1:nf, 1:nf]
zs = eigvals(Af, Bf)
zs = eigvalsnosort(Af, Bf)
_fix_conjugate_pairs!(zs) # Generalized eigvals does not return exact conj. pairs
else
zs = complex(T)[]
Expand Down
10 changes: 5 additions & 5 deletions src/matrix_comps.jl
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ function dare(A, B, Q, R)
if (!isposdef(R))
error("R must be positive definite.");
end

n = size(A, 1);

E = [
Matrix{Float64}(I, n, n) B/R*B';
zeros(size(A)) A'
Expand All @@ -58,10 +58,10 @@ function dare(A, B, Q, R)
A zeros(size(A));
-Q Matrix{Float64}(I, n, n)
];

QZ = schur(F, E);
QZ = ordschur(QZ, abs.(QZ.alpha./QZ.beta) .< 1);

return QZ.Z[(n+1):end, 1:n]/QZ.Z[1:n, 1:n];
end

Expand Down Expand Up @@ -292,7 +292,7 @@ function normLinf_twoSteps_ct(sys::AbstractStateSpace, tol=1e-6, maxIters=1000,
if isreal(p) # only real poles
omegap = minimum(abs.(p))
else # at least one pair of complex poles
tmp = maximum(abs.(imag.(p)./(real.(p).*abs.(p))))
tmp = abs.(imag.(p)./(real.(p).*abs.(p)))
omegap = abs(p[argmax(tmp)]) # TODO This is highly suspicious
end
(lb, idx) = findmax([lb, T(maximum(svdvals(evalfr(sys, omegap*1im))))]) #TODO remove T() in julia 0.7.0
Expand Down
4 changes: 2 additions & 2 deletions src/types/conversion.jl
Original file line number Diff line number Diff line change
Expand Up @@ -285,12 +285,12 @@ end
# TODO: Could perhaps be made more accurate. See: An accurate and efficient
# algorithm for the computation of the # characteristic polynomial of a general square matrix.
function charpoly(A::AbstractMatrix{<:Number})
Λ = eigvals(A)
Λ = eigvalsnosort(A)

return prod(roots2poly_factors(Λ)) # Compute the polynomial factors directly?
end
function charpoly(A::AbstractMatrix{<:Real})
Λ = eigvals(A)
Λ = eigvalsnosort(A)
return prod(roots2real_poly_factors(Λ))
end

Expand Down
51 changes: 38 additions & 13 deletions src/utilities.jl
Original file line number Diff line number Diff line change
Expand Up @@ -16,35 +16,30 @@ to_matrix(T, A::Number) = fill(T(A), 1, 1)
# Handle Adjoint Matrices
to_matrix(T, A::Adjoint{R, MT}) where {R<:Number, MT<:AbstractMatrix} = to_matrix(T, MT(A))


@static if VERSION > v"1.2.0-DEV.0"
eigvalsnosort(args...; kwargs...) = eigvals(args...; sortby=nothing, kwargs...)
else
eigvalsnosort(args...; kwargs...) = eigvals(args...; kwargs...)
end

# NOTE: Tolerances for checking real-ness removed, shouldn't happen from LAPACK?
# TODO: This doesn't play too well with dual numbers..
# Allocate for maxiumum possible length of polynomial vector?
#
# This function rely on that the every complex roots is followed by its exact conjugate,
# and that the first complex root in each pair has positive real part. This formaat is always
# and that the first complex root in each pair has positive real part. This format is always
mfalt marked this conversation as resolved.
Show resolved Hide resolved
# returned by LAPACK routines for eigenvalues.
function roots2real_poly_factors(roots::Vector{cT}) where cT <: Number
T = real(cT)
poly_factors = Vector{Poly{T}}()
@static if VERSION > v"1.2.0-DEV.0" # Sort one more time to handle GenericLinearAlgebra not being updated
sort!(roots, by=LinearAlgebra.eigsortby)
end
for k=1:length(roots)
r = roots[k]

if isreal(r)
push!(poly_factors,Poly{T}([-real(r),1]))
else
@static if VERSION > v"1.2.0-DEV.0" # Flipped order in this version
if imag(r) > 0 # This roots was handled in the previous iteration # TODO: Fix better error handling
continue
end
else
if imag(r) < 0 # This roots was handled in the previous iteration # TODO: Fix better error handling
continue
end
if imag(r) < 0 # This roots was handled in the previous iteration # TODO: Fix better error handling
continue
end

if k == length(roots) || r != conj(roots[k+1])
Expand Down Expand Up @@ -119,3 +114,33 @@ index2range(ind1, ind2) = (index2range(ind1), index2range(ind2))
index2range(ind::T) where {T<:Number} = ind:ind
index2range(ind::T) where {T<:AbstractArray} = ind
index2range(ind::Colon) = ind

# We rely on eigenvalues being sorted with complex conjugates in pairs, so overload roots
# Copied from Polynomials.jl, Copyright Jameson Nash and other contributors
function roots(p::Poly{T}) where {T}
R = promote_type(T, Float64)
length(p) == 0 && return zeros(R, 0)

num_leading_zeros = 0
while p[num_leading_zeros] ≈ zero(T)
if num_leading_zeros == length(p)-1
return zeros(R, 0)
end
num_leading_zeros += 1
end
num_trailing_zeros = 0
while p[end - num_trailing_zeros] ≈ zero(T)
num_trailing_zeros += 1
end
n = lastindex(p)-(num_leading_zeros + num_trailing_zeros)
n < 1 && return zeros(R, length(p) - num_trailing_zeros - 1)

companion = diagm(-1 => ones(R, n-1))
an = p[end-num_trailing_zeros]
companion[1,:] = -p[(end-num_trailing_zeros-1):-1:num_leading_zeros] / an

D = eigvalsnosort(companion)
r = zeros(eltype(D),length(p)-num_trailing_zeros-1)
r[1:n] = D
return r
end
4 changes: 2 additions & 2 deletions test/test_synthesis.jl
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,11 @@ A = randn(3,3)
B = randn(3,1)
p = [3.0,2,1]
K = ControlSystems.acker(A,B,p)
@test eigvals(A-B*K) ≈ p
@test eigvalsnosort(A-B*K) ≈ p

p = [-1+im, -1-im, -1]
K = ControlSystems.acker(A,B,p)
@test eigvals(A-B*K) ≈ p
@test eigvalsnosort(A-B*K) ≈ p
end

end