LSR/env/lib/python3.6/site-packages/control/robust.py
2020-06-04 17:24:47 +02:00

368 lines
10 KiB
Python

# robust.py - tools for robust control
#
# Author: Steve Brunton, Kevin Chen, Lauren Padilla
# Date: 24 Dec 2010
#
# This file contains routines for obtaining reduced order models
#
# Copyright (c) 2010 by California Institute of Technology
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the California Institute of Technology nor
# the names of its contributors may be used to endorse or promote
# products derived from this software without specific prior
# written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CALTECH
# OR THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
# OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#
# $Id$
# External packages and modules
import numpy as np
from .exception import *
from .statesp import StateSpace
from .statefbk import *
def h2syn(P, nmeas, ncon):
"""H_2 control synthesis for plant P.
Parameters
----------
P: partitioned lti plant (State-space sys)
nmeas: number of measurements (input to controller)
ncon: number of control inputs (output from controller)
Returns
-------
K: controller to stabilize P (State-space sys)
Raises
------
ImportError
if slycot routine sb10hd is not loaded
See Also
--------
StateSpace
Examples
--------
>>> K = h2syn(P,nmeas,ncon)
"""
# Check for ss system object, need a utility for this?
# TODO: Check for continous or discrete, only continuous supported right now
# if isCont():
# dico = 'C'
# elif isDisc():
# dico = 'D'
# else:
dico = 'C'
try:
from slycot import sb10hd
except ImportError:
raise ControlSlycot("can't find slycot subroutine sb10hd")
n = np.size(P.A, 0)
m = np.size(P.B, 1)
np_ = np.size(P.C, 0)
out = sb10hd(n, m, np_, ncon, nmeas, P.A, P.B, P.C, P.D)
Ak = out[0]
Bk = out[1]
Ck = out[2]
Dk = out[3]
K = StateSpace(Ak, Bk, Ck, Dk)
return K
def hinfsyn(P, nmeas, ncon):
"""H_{inf} control synthesis for plant P.
Parameters
----------
P: partitioned lti plant
nmeas: number of measurements (input to controller)
ncon: number of control inputs (output from controller)
Returns
-------
K: controller to stabilize P (State-space sys)
CL: closed loop system (State-space sys)
gam: infinity norm of closed loop system
rcond: 4-vector, reciprocal condition estimates of:
1: control transformation matrix
2: measurement transformation matrix
3: X-Ricatti equation
4: Y-Ricatti equation
TODO: document significance of rcond
Raises
------
ImportError
if slycot routine sb10ad is not loaded
See Also
--------
StateSpace
Examples
--------
>>> K, CL, gam, rcond = hinfsyn(P,nmeas,ncon)
"""
# Check for ss system object, need a utility for this?
# TODO: Check for continous or discrete, only continuous supported right now
# if isCont():
# dico = 'C'
# elif isDisc():
# dico = 'D'
# else:
dico = 'C'
try:
from slycot import sb10ad
except ImportError:
raise ControlSlycot("can't find slycot subroutine sb10ad")
n = np.size(P.A, 0)
m = np.size(P.B, 1)
np_ = np.size(P.C, 0)
gamma = 1.e100
out = sb10ad(n, m, np_, ncon, nmeas, gamma, P.A, P.B, P.C, P.D)
gam = out[0]
Ak = out[1]
Bk = out[2]
Ck = out[3]
Dk = out[4]
Ac = out[5]
Bc = out[6]
Cc = out[7]
Dc = out[8]
rcond = out[9]
K = StateSpace(Ak, Bk, Ck, Dk)
CL = StateSpace(Ac, Bc, Cc, Dc)
return K, CL, gam, rcond
def _size_as_needed(w, wname, n):
"""Convert LTI object to appropriately sized StateSpace object.
Intended for use in .robust only
Parameters
----------
w: None, 1x1 LTI object, or mxn LTI object
wname: name of w, for error message
n: number of inputs to w
Returns
-------
w_: processed weighting function, a StateSpace object:
- if w is None, empty StateSpace object
- if w is scalar, w_ will be w * eye(n)
- otherwise, w as StateSpace object
Raises
------
ValueError
- if w is not None or scalar, and doesn't have n inputs
See Also
--------
augw
"""
from . import append, ss
if w is not None:
if not isinstance(w, StateSpace):
w = ss(w)
if 1 == w.inputs and 1 == w.outputs:
w = append(*(w,) * n)
else:
if w.inputs != n:
msg = ("{}: weighting function has {} inputs, expected {}".
format(wname, w.inputs, n))
raise ValueError(msg)
else:
w = ss([], [], [], [])
return w
def augw(g, w1=None, w2=None, w3=None):
"""Augment plant for mixed sensitivity problem.
Parameters
----------
g: LTI object, ny-by-nu
w1: weighting on S; None, scalar, or k1-by-ny LTI object
w2: weighting on KS; None, scalar, or k2-by-nu LTI object
w3: weighting on T; None, scalar, or k3-by-ny LTI object
p: augmented plant; StateSpace object
If a weighting is None, no augmentation is done for it. At least
one weighting must not be None.
If a weighting w is scalar, it will be replaced by I*w, where I is
ny-by-ny for w1 and w3, and nu-by-nu for w2.
Returns
-------
p: plant augmented with weightings, suitable for submission to hinfsyn or h2syn.
Raises
------
ValueError
- if all weightings are None
See Also
--------
h2syn, hinfsyn, mixsyn
"""
from . import append, ss, connect
if w1 is None and w2 is None and w3 is None:
raise ValueError("At least one weighting must not be None")
ny = g.outputs
nu = g.inputs
w1, w2, w3 = [_size_as_needed(w, wname, n)
for w, wname, n in zip((w1, w2, w3),
('w1', 'w2', 'w3'),
(ny, nu, ny))]
if not isinstance(g, StateSpace):
g = ss(g)
# w u
# z1 [ w1 | -w1*g ]
# z2 [ 0 | w2 ]
# z3 [ 0 | w3*g ]
# [------+--------- ]
# v [ I | -g ]
# error summer: inputs are -y and r=w
Ie = ss([], [], [], np.eye(ny))
# control: needed to "distribute" control input
Iu = ss([], [], [], np.eye(nu))
sysall = append(w1, w2, w3, Ie, g, Iu)
niw1 = w1.inputs
niw2 = w2.inputs
niw3 = w3.inputs
now1 = w1.outputs
now2 = w2.outputs
now3 = w3.outputs
q = np.zeros((niw1 + niw2 + niw3 + ny + nu, 2))
q[:, 0] = np.arange(1, q.shape[0] + 1)
# Ie -> w1
q[:niw1, 1] = np.arange(1 + now1 + now2 + now3,
1 + now1 + now2 + now3 + niw1)
# Iu -> w2
q[niw1:niw1 + niw2, 1] = np.arange(1 + now1 + now2 + now3 + 2 * ny,
1 + now1 + now2 + now3 + 2 * ny + niw2)
# y -> w3
q[niw1 + niw2:niw1 + niw2 + niw3, 1] = np.arange(1 + now1 + now2 + now3 + ny,
1 + now1 + now2 + now3 + ny + niw3)
# -y -> Iy; note the leading -
q[niw1 + niw2 + niw3:niw1 + niw2 + niw3 + ny, 1] = -np.arange(1 + now1 + now2 + now3 + ny,
1 + now1 + now2 + now3 + 2 * ny)
# Iu -> G
q[niw1 + niw2 + niw3 + ny:niw1 + niw2 + niw3 + ny + nu, 1] = np.arange(
1 + now1 + now2 + now3 + 2 * ny,
1 + now1 + now2 + now3 + 2 * ny + nu)
# input indices: to Ie and Iu
ii = np.hstack((np.arange(1 + now1 + now2 + now3,
1 + now1 + now2 + now3 + ny),
np.arange(1 + now1 + now2 + now3 + ny + nu,
1 + now1 + now2 + now3 + ny + nu + nu)))
# output indices
oi = np.arange(1, 1 + now1 + now2 + now3 + ny)
p = connect(sysall, q, ii, oi)
return p
def mixsyn(g, w1=None, w2=None, w3=None):
"""Mixed-sensitivity H-infinity synthesis.
mixsyn(g,w1,w2,w3) -> k,cl,info
Parameters
----------
g: LTI; the plant for which controller must be synthesized
w1: weighting on s = (1+g*k)**-1; None, or scalar or k1-by-ny LTI
w2: weighting on k*s; None, or scalar or k2-by-nu LTI
w3: weighting on t = g*k*(1+g*k)**-1; None, or scalar or k3-by-ny LTI
At least one of w1, w2, and w3 must not be None.
Returns
-------
k: synthesized controller; StateSpace object
cl: closed system mapping evaluation inputs to evaluation outputs; if
p is the augmented plant, with
[z] = [p11 p12] [w],
[y] [p21 g] [u]
then cl is the system from w->z with u=-k*y. StateSpace object.
info: tuple with entries, in order,
- gamma: scalar; H-infinity norm of cl
- rcond: array; estimates of reciprocal condition numbers
computed during synthesis. See hinfsyn for details
If a weighting w is scalar, it will be replaced by I*w, where I is
ny-by-ny for w1 and w3, and nu-by-nu for w2.
See Also
--------
hinfsyn, augw
"""
nmeas = g.outputs
ncon = g.inputs
p = augw(g, w1, w2, w3)
k, cl, gamma, rcond = hinfsyn(p, nmeas, ncon)
info = gamma, rcond
return k, cl, info