Exemple #1
0
def simplify_n_monic(tt):

    num, den = sp.fraction(sp.simplify(tt))

    num = sp.poly(num, s)
    den = sp.poly(den, s)

    lcnum = sp.LC(num)
    lcden = sp.LC(den)

    return (sp.simplify(lcnum / lcden) * (sp.monic(num) / sp.monic(den)))
def remove_leading_coeff(P):
    coeff = sympy.LC(P)
    if np.abs(coeff) < 1.e-7:
        print(f"P (before removing leading term): {P} {coeff}")
        P = P - coeff * sympy.LM(P)
        print(f"P (after removing leading term): {P}")

    return P
Exemple #3
0
def rearrange(e, n):
    """'e' is assumed to be a list of exponential polynomial terms"""
    pos, neg = [], []
    for t in e:
        poly = sp.poly(t[0], gens=n)
        lc = sp.LC(poly, gens=n)
        if lc > 0: pos.append(t)
        elif lc < 0: neg.append(t)
    return pos, neg
Exemple #4
0
    def _find_realization(self, G, s):
        """ Represenatation [A, B, C, D] of the state space model

        Returns the representation in state space of a given transfer sp.Function

        Parameters
        ==========

        G: sp.Matrix
            sp.Matrix valued transfer sp.Function G(s) in laplace space
        s: sp.Symbol
            variable s, where G is dependent from

        See Also
        ========

        Utils : some quick tools for sp.Matrix polynomials

        References
        ==========

        Joao P. Hespanha, Linear Systems Theory. 2009.
        """

        A, B, C, D = 4 * [None]

        try:
            m, k = G.shape

        except AttributeError:
            raise TypeError("G must be a sp.Matrix")

        # test if G is proper
        if not is_proper(G, s, strict=False):
            raise ValueError("G must be proper!")

        # define D as the limit of G for s to infinity
        D = G.limit(s, sp.oo)

        # define G_sp as the (stricly proper) difference of G and D
        G_sp = sp.simplify(G - D)

        # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
        # get the coefficients of the monic least common denominator of all entries of G_sp
        # compute a least common denominator using utl and sp.lcm
        fl = fraction_list(G_sp, only_denoms=True)
        lcd = sp.lcm(list(fl))

        # make it monic
        lcd = sp.simplify(lcd / sp.LC(lcd, s))

        # and get a coefficient list of its monic. The [1:] cuts the sp.LC away (thats a one)
        lcd_coeff = sp.Poly(lcd, s).all_coeffs()[1:]

        # get the sp.degree of the lcd
        lcd_deg = sp.degree(lcd, s)

        # get the sp.Matrix Valued Coeffs of G_sp in G_sp = 1/lcd * (N_1 * s**(n-1) + N_2 * s**(n-2) .. +N_n)
        G_sp_coeff = matrix_coeff(sp.simplify(G_sp * lcd), s)
        G_sp_coeff = [sp.zeros(m, k)
                      ] * (lcd_deg - len(G_sp_coeff)) + G_sp_coeff

        # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
        # now store A, B, C, D in terms of the coefficients of lcd and G_sp
        # define A
        A = (-1) * lcd_coeff[0] * sp.eye(k)

        for alpha in lcd_coeff[1:]:
            A = A.row_join((-1) * alpha * sp.eye(k))

        for i in range(lcd_deg - 1):
            if i == 0:
                tmp = sp.eye(k)
            else:
                tmp = sp.zeros(k)

            for j in range(lcd_deg)[1:]:
                if j == i:
                    tmp = tmp.row_join(sp.eye(k))
                else:
                    tmp = tmp.row_join(sp.zeros(k))
            if tmp is not None:
                A = A.col_join(tmp)

        # define B
        B = sp.eye(k)
        for i in range(lcd_deg - 1):
            B = B.col_join(sp.zeros(k))

        # define C
        C = G_sp_coeff[0]
        for i in range(lcd_deg)[1:]:
            C = C.row_join(G_sp_coeff[i])

        # return the state space representation
        return [sp.simplify(A), sp.simplify(B), sp.simplify(C), sp.simplify(D)]
Exemple #5
0
    def ratfun(self, expr, z, n, **kwargs):

        expr = expr / z

        # Handle special case 1 / (z**m * (z - 1)) since this becomes u[n - m]
        # The default method produces u[n] - delta[n] for u[n-1].  This is correct
        # but can be simplified.
        # In general, 1 / (z**m * (z - a)) becomes a**n * u[n - m]

        if (len(expr.args) == 2 and expr.args[1].is_Pow
                and expr.args[1].args[0].is_Add
                and expr.args[1].args[0].args[0] == -1
                and expr.args[1].args[0].args[1] == z):

            delay = None
            if expr.args[0] == z:
                delay = 1
            elif expr.args[0].is_Pow and expr.args[0].args[0] == z:
                a = expr.args[0].args[1]
                if a.is_positive:
                    warn('Dodgy z-transform 1.  Have advance of unit step.')
                elif not a.is_negative:
                    warn(
                        'Dodgy z-transform 2.  May have advance of unit step.')
                delay = -a
            elif (expr.args[0].is_Pow and expr.args[0].args[0].is_Pow
                  and expr.args[0].args[0].args[0] == z
                  and expr.args[0].args[0].args[1] == -1):
                a = expr.args[0].args[1]
                if a.is_negative:
                    warn('Dodgy z-transform 3.  Have advance of unit step.')
                elif not a.is_positive:
                    warn(
                        'Dodgy z-transform 4.  May have advance of unit step.')
                delay = a

            if delay is not None:
                return UnitStep(n - delay), sym.S.Zero

        zexpr = Ratfun(expr, z)

        Q, M, D, delay, undef = zexpr.as_QMA()

        cresult = sym.S.Zero
        uresult = sym.S.Zero

        if Q:
            Qpoly = sym.Poly(Q, z)
            C = Qpoly.all_coeffs()
            for m, c in enumerate(C):
                cresult += c * UnitImpulse(n - len(C) + m + 1)

        # There is problem with determining residues if
        # have 1/(z*(-a/z + 1)) instead of 1/(-a + z).  Hopefully,
        # simplify will fix things...
        expr = (M / D).simplify()
        # M and D may contain common factors before simplification, so redefine M and D
        M = sym.numer(expr)
        D = sym.denom(expr)
        for factor in expr.as_ordered_factors():
            if factor == sym.oo:
                return factor, factor

        zexpr = Ratfun(expr, z, **kwargs)
        poles = zexpr.poles(damping=kwargs.get('damping', None))
        poles_dict = {}
        for pole in poles:
            # Replace cos()**2-1 by sin()**2
            pole.expr = TR6(sym.expand(pole.expr))
            pole.expr = sym.simplify(pole.expr)
            # Remove abs value from sin()
            pole.expr = pole.expr.subs(sym.Abs, sym.Id)
            poles_dict[pole.expr] = pole.n

        # Juergen Weizenecker HsKa

        # Make two dictionaries in order to handle them differently and make
        # pretty expressions
        if kwargs.get('pairs', True):
            pole_pair_dict, pole_single_dict = pair_conjugates(poles_dict)
        else:
            pole_pair_dict, pole_single_dict = {}, poles_dict

        # Make n (=number of poles) different denominators to speed up
        # calculation and avoid sym.limit.  The different denominators are
        # due to shortening of poles after multiplying with (z-z1)**o
        if not (M.is_polynomial(z) and D.is_polynomial(z)):
            print("Numerator or denominator may contain 1/z terms: ", M, D)

        n_poles = len(poles)
        # Leading coefficient of denominator polynom
        a_0 = sym.LC(D, z)
        # The canceled denominator (for each (z-p)**o)
        shorten_denom = {}
        for i in range(n_poles):
            shorten_term = sym.prod([(z - poles[j].expr)**(poles[j].n)
                                     for j in range(n_poles) if j != i], a_0)
            shorten_denom[poles[i].expr] = shorten_term

        # Run through single poles real or complex, order 1 or higher
        for pole in pole_single_dict:

            p = pole

            # Number of occurrences of the pole.
            o = pole_single_dict[pole]

            # X(z)/z*(z-p)**o after shortening.
            expr2 = M / shorten_denom[p]

            if o == 0:
                continue

            if o == 1:
                r = sym.simplify(sym.expand(expr2.subs(z, p)))

                if p == 0:
                    cresult += r * UnitImpulse(n)
                else:
                    uresult += r * p**n
                continue

            # Handle repeated poles.
            all_derivatives = [expr2]
            for i in range(1, o):
                all_derivatives += [sym.diff(all_derivatives[i - 1], z)]

            bino = 1
            sum_p = 0
            for i in range(1, o + 1):
                m = o - i
                derivative = all_derivatives[m]
                # Derivative at z=p
                derivative = sym.expand(derivative.subs(z, p))
                r = sym.simplify(derivative) / sym.factorial(m)

                if p == 0:
                    cresult += r * UnitImpulse(n - i + 1)
                else:
                    sum_p += r * bino * p**(1 - i) / sym.factorial(i - 1)
                    bino *= n - i + 1

            uresult += sym.simplify(sum_p * p**n)

        # Run through complex pole pairs
        for pole in pole_pair_dict:

            p1 = pole[0]
            p2 = pole[1]

            # Number of occurrences of the pole pair
            o1 = pole_pair_dict[pole]
            # X(z)/z*(z-p)**o after shortening
            expr_1 = M / shorten_denom[p1]
            expr_2 = M / shorten_denom[p2]

            # Oscillation parameter
            lam = sym.sqrt(sym.simplify(p1 * p2))
            p1_n = sym.simplify(p1 / lam)
            # term is of form exp(j*arg())
            if len(p1_n.args
                   ) == 1 and p1_n.is_Function and p1_n.func == sym.exp:
                omega_0 = sym.im(p1_n.args[0])
            # term is of form cos() + j sin()
            elif p1_n.is_Add and sym.re(p1_n).is_Function and sym.re(
                    p1_n).func == sym.cos:
                p1_n = p1_n.rewrite(sym.exp)
                omega_0 = sym.im(p1_n.args[0])
            # general form
            else:
                omega_0 = sym.simplify(sym.arg(p1_n))

            if o1 == 1:
                r1 = expr_1.subs(z, p1)
                r2 = expr_2.subs(z, p2)

                r1_re = sym.re(r1).simplify()
                r1_im = sym.im(r1).simplify()

                # if pole pairs is selected, r1=r2*

                # Handle real part
                uresult += 2 * TR9(r1_re) * lam**n * sym.cos(omega_0 * n)
                uresult -= 2 * TR9(r1_im) * lam**n * sym.sin(omega_0 * n)

            else:
                bino = 1
                sum_b = 0
                # Compute first all derivatives needed
                all_derivatives_1 = [expr_1]
                for i in range(1, o1):
                    all_derivatives_1 += [
                        sym.diff(all_derivatives_1[i - 1], z)
                    ]

                # Loop through the binomial series
                for i in range(1, o1 + 1):
                    m = o1 - i

                    # m th derivative at z=p1
                    derivative = all_derivatives_1[m]
                    r1 = derivative.subs(z, p1) / sym.factorial(m)
                    # prefactors
                    prefac = bino * lam**(1 - i) / sym.factorial(i - 1)
                    # simplify r1
                    r1 = r1.rewrite(sym.exp).simplify()
                    # sum
                    sum_b += prefac * r1 * sym.exp(sym.I * omega_0 * (1 - i))
                    # binomial coefficient
                    bino *= n - i + 1

                # take result = lam**n * (sum_b*sum_b*exp(j*omega_0*n) + cc)
                aa = sym.simplify(sym.re(sum_b))
                bb = sym.simplify(sym.im(sum_b))
                uresult += 2 * (aa * sym.cos(omega_0 * n) -
                                bb * sym.sin(omega_0 * n)) * lam**n

        # cresult is a sum of Dirac deltas and its derivatives so is known
        # to be causal.

        return cresult, uresult
Exemple #6
0
#Compute trace according to ChaosBook v14 eq. 20.13
for i in range(Ncycle):
    ni = rpos[i][0]
    Ti = rpos[i][1]
    Lambda = rpos[i][2]
    Sum = 0
    r = 1
    while ni*r <= Nexpansion:
        Sum = Sum + (z**(ni*r))/np.abs(1-Lambda**r)
        r += 1
    
    Trace = Trace + Ti * Sum
#Extract coefficients of the expansion:
C = []
for i in range(Nexpansion):
    C.insert(0, sympy.LC(Trace))
    Trace = Trace - sympy.LT(Trace)
#Compute Coefficients of the determinant expansion according to ChaosBook v14 eq. 20.15    
Q = [C[0]]
SpectDetPoly = np.array([-Q[0], 1], float)
F00 = [1 - sum(Q)]
for n in range(2, Nexpansion+1):
    Qn = C[n-1]
    for k in range(1,n):
        #print n,k
        Qn = Qn - C[n - k - 1]*Q[k - 1] 
    Qn = Qn / float(n)
    Q.append(Qn)
    F00.append(1 - sum(Q))    
    SpectDetPoly = np.insert(SpectDetPoly, 0, -Qn)
Exemple #7
0
def ep_ge_0(e, n, strict=False):
    transformed = to_exponential_polynomial(e)
    inf_bnd = 9999999999999999999999999999999
    e = my_simplify(e, n)
    if isinstance(e, int) or isinstance(e, float) or e.is_number:
        res = e > 0 if strict else e >= 0
        if res:
            return res, -1
        else:
            return res, 0
    p = e.as_poly(n)
    if p is not None:
        if p.degree() <= 4:
            if strict:
                solution = sp.solveset(e > 0, domain=sp.S.Reals)
            else:
                solution = sp.solveset(e >= 0, domain=sp.S.Reals)
            non_negative = sp.Interval(0, sp.oo, left_open=False)
            rounded_solution = round_interval(solution)
            intersect = rounded_solution.intersection(non_negative)
            # print(intersect)
            if intersect.is_empty:
                return False, 0
            if intersect == non_negative:
                return True, -1
            elif sp.LC(p) > 0:
                j = intersect.left + 1 if intersect.left_open else intersect.left
                return False, 0
            else:
                j = intersect.right if intersect.right_open else intersect.right + 1
                return False, j

    if any(t[1] < 0 for t in transformed):
        even = ep_ge_0(e.subs(n, 2*n), n)
        odd = ep_ge_0(e.subs(n, 2*n + 1), n)
        if not even[0] and not odd[0]:
            return False, min(2*even[0], 2*odd[0] + 1)
        if not even[0]:
            return even
        if not odd[0]:
            return odd
        return True, -1
        # return ep_ge_0(e.subs(n, sp.Integer(2)*n), n) and ep_ge_0(e.subs(n, sp.Integer(2)*n + sp.Integer(1)), n)
    if any(t[1] < 1 for t in transformed):
        return ep_ge_0(10**n*e, n)
    if len(transformed) == 0:
        return True, -1
    pos, neg = rearrange(transformed, n)
    if len(pos) == 0 and len(neg) > 0:
        return ep_ge_0_finite(e, n, inf_bnd, strict=strict)
    u = max(cauchy_bnd(t[0], n) for t in transformed)
    if len(pos) > 0 and len(neg) == 0:
        return ep_ge_0_finite(e, n, u, strict=strict)
    b_pos = max(t[1] for t in pos)
    pos_index = [t[1] for t in pos].index(b_pos)
    b_neg = max(t[1] for t in neg)
    if b_pos < b_neg:
        return ep_ge_0_finite(e, n, inf_bnd, strict=strict)
    r = sum(sp.Poly(t[0], gens=n) for t in neg).degree()
    if r is sp.S.NegativeInfinity:
        r = 0
    mac = sp.series((b_pos/b_neg)**n, x=n, x0=0, n=r+2)
    mac = mac.removeO()
    u_p = cauchy_bnd(pos[pos_index][0].subs(n, u)*mac + len(neg)*sum(t[0] for t in neg), n)
    return ep_ge_0_finite(e, n, max(u, u_p), strict=strict)