def _check_non_simple(coeffs): r"""Checks that a polynomial has no non-simple roots. Does so by computing the companion matrix :math:`A` of :math:`f'` and then evaluating the rank of :math:`B = f(A)`. If :math:`B` is not full rank, then :math:`f` and :math:`f'` have a shared factor. See: https://dx.doi.org/10.1016/0024-3795(70)90023-6 .. note:: This assumes that :math:`f \neq 0`. Args: coeffs (numpy.ndarray): ``d + 1``-array of coefficients in monomial / power basis. Raises: NotImplementedError: If the polynomial has non-simple roots. """ coeffs = _strip_leading_zeros(coeffs) num_coeffs, = coeffs.shape if num_coeffs < 3: return deriv_poly = polynomial.polyder(coeffs) companion = polynomial.polycompanion(deriv_poly) # NOTE: `polycompanion()` returns a C-contiguous array. companion = companion.T # Use Horner's method to evaluate f(companion) num_companion, _ = companion.shape id_mat = _helpers.eye(num_companion) evaluated = coeffs[-1] * id_mat for index in six.moves.xrange(num_coeffs - 2, -1, -1): coeff = coeffs[index] evaluated = (_helpers.matrix_product(evaluated, companion) + coeff * id_mat) if num_companion == 1: # NOTE: This relies on the fact that coeffs is normalized. if np.abs(evaluated[0, 0]) > _NON_SIMPLE_THRESHOLD: rank = 1 else: rank = 0 else: rank = np.linalg.matrix_rank(evaluated) if rank < num_companion: raise NotImplementedError(_NON_SIMPLE_ERR, coeffs)
def tf2ss(sys_): """ Convert transfer function model to state space model. :param sys_: the system :type sys_: TransferFunction :return: corresponded transfer function model :rtype: StateSpace """ try: nump = np.poly1d(sys_.num) denp = np.poly1d(sys_.den) except AttributeError as e: raise TypeError(f'TransferFunction expected got {type(sys_)}') from e if not sys_.is_siso: raise ValueError('tf2ss only for siso system right now.') dt = sys_.dt if denp[denp.order] != 1: nump /= denp[denp.order] denp /= denp[denp.order] q, r = nump / denp num = r.coeffs bn = q.coeffs den = denp.coeffs D = np.atleast_2d(bn) if sys_.is_gain: A = np.array([[0]]) B = np.array([[0]]) C = np.array([[0]]) else: # generate matrix A n = den.shape[0] - 1 A = polycompanion(den[::-1]).T B = np.zeros((n, 1)) B[-1] = 1 C = np.zeros((1, n)) C[0, 0:num.shape[0]] = num[::-1] return StateSpace(A, B, C, D, dt=dt)
def _mi_place(A, B, poles): n = A.shape[0] p = B.shape[1] T = ctrb_trans_mat(A, B) Ac = T @ A @ inv(T) Bc = T @ B Ac_tilde = polycompanion(np.flip(np.poly(poles))).T r = -1 indices = ctrb_indices(A, B) Ar = np.empty((indices.shape[0], n)) Br = np.empty((p, p)) Ar_tilde = np.empty(Ar.shape) for i, mu in enumerate(indices): r += mu Ar[i] = Ac[r] Br[i] = Bc[r] Ar_tilde[i] = Ac_tilde[r] K = inv(Br) @ (Ar - Ar_tilde) return K @ T
def test_linear_root(self): assert_(poly.polycompanion([1, 2])[0, 0] == -.5)
def test_dimensions(self): for i in range(1, 5): coef = [0]*i + [1] assert_(poly.polycompanion(coef).shape == (i, i))
def test_dimensions(self): for i in range(1, 5): coef = [0] * i + [1] assert_(poly.polycompanion(coef).shape == (i, i))
def companion_from_eig(eigvals): """ Find companion matrix for given eigenvalue sequence. """ from numpy.polynomial.polynomial import polyfromroots, polycompanion return polycompanion(polyfromroots(eigvals)).real