Repository: sympy/sympy
File: sympy/physics/control/lti.py (Python)

Code before:
        >>> C = Matrix([[1, 2]])
        >>> D = Matrix([0])
        >>> ss = DiscreteStateSpace(A, B, C, D)
        >>> ss.rewrite(DiscreteTransferFunction)
        [[DiscreteTransferFunction(12*z + 59, z**2 + 6*z + 8, z, 1)]]

        """
        z = Symbol('z')
        n = self.A.shape[0]
        I = eye(n)
        G = self.C*(z*I - self.A).solve(self.B) + self.D
        G = G.simplify()
        to_tf = lambda expr: DiscreteTransferFunction.\
            from_rational_expression(expr, z, self.sampling_time)
        tf_mat = [[to_tf(expr) for expr in sublist] for sublist in G.tolist()]
        return tf_mat

    def _eval_rewrite_as_TransferFunction(self, *args):
        raise TypeError("""
            The discrete state space model cannot be rewritten as a
            continuous-time transfer function model.
            """)

    def get_asymptotic_stability_conditions(
        self, fast=False
    ) -> list[Union[Boolean, StrictGreaterThan]]:
        r"""
        See :func:`StateSpaceBase.get_asymptotic_stability_conditions`.

        Warning
        =======

        Due to precision issues, eigenvalues at -1 may be missed and the
        conditions could be incorrect. Consider checking if the state space has
        roots at -1 before using this method.

        """
        s = Symbol('s')

        domain = EXRAW if fast else None
        # if domain is None, to_DM will find the domain automatically
        _A = self.A.to_DM(domain = domain) # type: ignore
        charpoly = _A.charpoly()
        charpoly = Poly(charpoly, s, domain = _A.domain)

        return [c > 0 for c in charpoly.schur_conditions()]

    @property
    def sampling_time(self):
        return self._sampling_time


Review comment (suggestion):
It is possible to use `A | B` rather than `Union[A, B]` now but in this case it should just be Boolean.

Code after:
        >>> ss.rewrite(DiscreteTransferFunction)
        [[DiscreteTransferFunction(12*z + 59, z**2 + 6*z + 8, z, 1)]]

        """
        z = Symbol('z')
        n = self.A.shape[0]
        I = eye(n)
        G = self.C*(z*I - self.A).solve(self.B) + self.D
        G = G.simplify()
        to_tf = lambda expr: DiscreteTransferFunction.\
            from_rational_expression(expr, z, self.sampling_time)
        tf_mat = [[to_tf(expr) for expr in sublist] for sublist in G.tolist()]
        return tf_mat

    def _eval_rewrite_as_TransferFunction(self, *args):
        raise TypeError("""
            The discrete state space model cannot be rewritten as a
            continuous-time transfer function model.
            """)

    def get_asymptotic_stability_conditions(
        self, fast=False
    ) -> list[Boolean]:
        r"""
        See :func:`StateSpaceBase.get_asymptotic_stability_conditions`.

        """
        s = Symbol('s')

        domain = EXRAW if fast else None
        # if domain is None, to_DM will find the domain automatically
        _A = self.A.to_DM(domain = domain) # type: ignore
        charpoly = _A.charpoly()
        charpoly = Poly(charpoly, s, domain = _A.domain)

        return [c > 0 for c in charpoly.schur_conditions()]

    @property
    def sampling_time(self):
        return self._sampling_time

    _is_continuous = False