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

Allow place to handle multi input systems #384

Closed
albheim opened this issue Oct 30, 2020 · 2 comments
Closed

Allow place to handle multi input systems #384

albheim opened this issue Oct 30, 2020 · 2 comments
Assignees

Comments

@albheim
Copy link
Member

albheim commented Oct 30, 2020

Currently place only handles SISO systems and it might be nice to try to implement something similar as matlab has where they find a robust set of poles for multi input systems according to Robust Pole Assignment in Linear State Feedback. Have not managed to understand the algorithm but could try to take a look at it if it is of interest.

@baggepinnen
Copy link
Member

baggepinnen commented Dec 13, 2020

In anticipation of a better method, the following does an okay job

function generic_place(A, B::AbstractMatrix, desired_poles; max_tries = 20, λ=1e-8)
    function loss(K)
        e = eigvals(A-B*K)
        mean(abs2.(e-desired_poles)) + λ*mean(abs2, K)
    end    
    desired_poles = sort(complex.(desired_poles), by=LinearAlgebra.eigsortby)
    nu = size(B,2)    
    local res
    for i = 1:max_tries
        if nu > 1
            v = randn(nu)
            B0 = B*v
            K0 = place(A,B0, desired_poles)
            K = v*K0
        else
            K = place(A, B, desired_poles) .+ 0.1 .* randn.()
        end
        res = Optim.optimize(
            loss,
            K,
            BFGS(),
            Optim.Options(
                store_trace       = false,
                show_trace        = false,
                show_every        = 1,
                iterations        = 10000,
                allow_f_increases = false,
                time_limit        = 100,
                x_tol             = 1e-10,
                f_tol             = 1e-10,
                g_tol             = 1e-12,
                f_calls_limit     = 0,
                g_calls_limit     = 0,
                ),
                )
        (res.f_converged || res.g_converged || res.x_converged) && break
    end
    real.(res.minimizer), res
end

nx = 10
A = randn(nx,nx) - 2I
B = randn(nx,3)

desired_poles = sort(randn(nx) .- 4)


PK = place(A,B,desired_poles)
OK, res = generic_place(A,B,desired_poles, λ=1e-8)

@test PK  OK rtol=1e-2

Of course, you may add additional penalties to the loss function, encouraging use of potential redundancy to reduce noise influence etc. And it should probably be initialized using the trick to project B along a random direction and calling place
EDIT: I made that update

@baggepinnen
Copy link
Member

Closed by #854

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants