Ejemplo n.º 1
0
def _futrig(e, **kwargs):
    """Helper for futrig."""
    from sympy.simplify.fu import (
        TR1, TR2, TR3, TR2i, TR10, L, TR10i,
        TR8, TR6, TR15, TR16, TR111, TR5, TRmorrie, TR11, TR14, TR22,
        TR12)
    from sympy.core.compatibility import _nodes

    if not e.has(TrigonometricFunction):
        return e

    if e.is_Mul:
        coeff, e = e.as_independent(TrigonometricFunction)
    else:
        coeff = S.One

    Lops = lambda x: (L(x), x.count_ops(), _nodes(x), len(x.args), x.is_Add)
    trigs = lambda x: x.has(TrigonometricFunction)

    tree = [identity,
        (
        TR3,  # canonical angles
        TR1,  # sec-csc -> cos-sin
        TR12,  # expand tan of sum
        lambda x: _eapply(factor, x, trigs),
        TR2,  # tan-cot -> sin-cos
        [identity, lambda x: _eapply(_mexpand, x, trigs)],
        TR2i,  # sin-cos ratio -> tan
        lambda x: _eapply(lambda i: factor(i.normal()), x, trigs),
        TR14,  # factored identities
        TR5,  # sin-pow -> cos_pow
        TR10,  # sin-cos of sums -> sin-cos prod
        TR11, TR6, # reduce double angles and rewrite cos pows
        lambda x: _eapply(factor, x, trigs),
        TR14,  # factored powers of identities
        [identity, lambda x: _eapply(_mexpand, x, trigs)],
        TRmorrie,
        TR10i,  # sin-cos products > sin-cos of sums
        [identity, TR8],  # sin-cos products -> sin-cos of sums
        [identity, lambda x: TR2i(TR2(x))],  # tan -> sin-cos -> tan
        [
            lambda x: _eapply(expand_mul, TR5(x), trigs),
            lambda x: _eapply(
                expand_mul, TR15(x), trigs)], # pos/neg powers of sin
        [
            lambda x:  _eapply(expand_mul, TR6(x), trigs),
            lambda x:  _eapply(
                expand_mul, TR16(x), trigs)], # pos/neg powers of cos
        TR111,  # tan, sin, cos to neg power -> cot, csc, sec
        [identity, TR2i],  # sin-cos ratio to tan
        [identity, lambda x: _eapply(
            expand_mul, TR22(x), trigs)],  # tan-cot to sec-csc
        TR1, TR2, TR2i,
        [identity, lambda x: _eapply(
            factor_terms, TR12(x), trigs)],  # expand tan of sum
        )]
    e = greedy(tree, objective=Lops)(e)

    return coeff*e
Ejemplo n.º 2
0
def test_TR6():
    assert TR6(cos(x)**2) == -sin(x)**2 + 1
    assert TR6(cos(x)**-2) == cos(x)**(-2)
    assert TR6(cos(x)**4) == (-sin(x)**2 + 1)**2
Ejemplo n.º 3
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