Exemple #1
0
def tb05ad_example():
    """
    Example of calculating the frequency response using tb05ad
    on a second-order system with a natural frequency of 10 rad/s
    and damping ratio of 1.05.
    """
    import numpy as np
    A = np.array([[0.0, 1.0],
                  [-100.0,   -20.1]])
    B = np.array([[0.],[100]])
    C = np.array([[1., 0.]])
    n = np.shape(A)[0]
    m = np.shape(B)[1]
    p = np.shape(C)[0]

    jw_s = [1j*11, 1j*15]
    at, bt, ct, g_1, hinvb,info = slycot.tb05ad(n, m, p, jw_s[0],
                                               A, B, C, job='NG')
    g_2, hinv2, info = slycot.tb05ad(n, m, p, jw_s[1], at, bt, ct, job='NH')
    print('--- Example for tb05ad...')
    print('Frequency response for (A, B, C)')
    print('-------------------------')
    print('Frequency  |     Response')
    print('%s        | %s '%(jw_s[0], g_1[0, 0]))
    print('%s        | %s '%(jw_s[1], g_2[0, 0]))
Exemple #2
0
    def freqresp(self, omega):
        """Evaluate the system's transfer func. at a list of freqs, omega.

        mag, phase, omega = self.freqresp(omega)

        Reports the frequency response of the system,

             G(j*omega) = mag*exp(j*phase)

        for continuous time. For discrete time systems, the response is
        evaluated around the unit circle such that

             G(exp(j*omega*dt)) = mag*exp(j*phase).

        Inputs:
        ------
           omega: A list of frequencies in radians/sec at which the system
                    should be evaluated. The list can be either a python list
                    or a numpy array and will be sorted before evaluation.

        Returns:
        -------
           mag: The magnitude (absolute value, not dB or log10) of the system
                frequency response.

           phase: The wrapped phase in radians of the system frequency
                  response.

           omega: The list of sorted frequencies at which the response
                    was evaluated.

        """

        # In case omega is passed in as a list, rather than a proper array.
        omega = np.asarray(omega)

        numFreqs = len(omega)
        Gfrf = np.empty((self.outputs, self.inputs, numFreqs),
                        dtype=np.complex128)

        # Sort frequency and calculate complex frequencies on either imaginary
        # axis (continuous time) or unit circle (discrete time).
        omega.sort()
        if isdtime(self, strict=True):
            dt = timebase(self)
            cmplx_freqs = exp(1.j * omega * dt)
            if ((omega * dt).any() > pi):
                warn_message = ("evalfr: frequency evaluation"
                                " above Nyquist frequency")
                warnings.warn(warn_message)
        else:
            cmplx_freqs = omega * 1.j

        # Do the frequency response evaluation. Use TB05AD from Slycot
        # if it's available, otherwise use the built-in horners function.
        try:
            from slycot import tb05ad

            n = np.shape(self.A)[0]
            m = self.inputs
            p = self.outputs
            # The first call both evalates C(sI-A)^-1 B and also returns
            # hessenberg transformed matrices at, bt, ct.
            result = tb05ad(n,
                            m,
                            p,
                            cmplx_freqs[0],
                            self.A,
                            self.B,
                            self.C,
                            job='NG')
            # When job='NG', result = (at, bt, ct, g_i, hinvb, info)
            at = result[0]
            bt = result[1]
            ct = result[2]

            # TB05AD freqency evaluation does not include direct feedthrough.
            Gfrf[:, :, 0] = result[3] + self.D

            # Now, iterate through the remaining frequencies using the
            # transformed state matrices, at, bt, ct.

            # Start at the second frequency, already have the first.
            for kk, cmplx_freqs_kk in enumerate(cmplx_freqs[1:numFreqs]):
                result = tb05ad(n, m, p, cmplx_freqs_kk, at, bt, ct, job='NH')
                # When job='NH', result = (g_i, hinvb, info)

                # kk+1 because enumerate starts at kk = 0.
                # but zero-th spot is already filled.
                Gfrf[:, :, kk + 1] = result[0] + self.D

        except ImportError:  # Slycot unavailable. Fall back to horner.
            for kk, cmplx_freqs_kk in enumerate(cmplx_freqs):
                Gfrf[:, :, kk] = self.horner(cmplx_freqs_kk)

        #      mag           phase           omega
        return np.abs(Gfrf), np.angle(Gfrf), omega
Exemple #3
0
    def freqresp(self, omega):
        """
        Evaluate the system's transfer func. at a list of freqs, omega.

        mag, phase, omega = self.freqresp(omega)

        Reports the frequency response of the system,

             G(j*omega) = mag*exp(j*phase)

        for continuous time. For discrete time systems, the response is
        evaluated around the unit circle such that

             G(exp(j*omega*dt)) = mag*exp(j*phase).

        Inputs
        ------
        omega: A list of frequencies in radians/sec at which the system
            should be evaluated. The list can be either a python list
            or a numpy array and will be sorted before evaluation.

        Returns
        -------
        mag: The magnitude (absolute value, not dB or log10) of the system
            frequency response.

        phase: The wrapped phase in radians of the system frequency
            response.

        omega: The list of sorted frequencies at which the response
            was evaluated.

        """

        # In case omega is passed in as a list, rather than a proper array.
        omega = np.asarray(omega)

        numFreqs = len(omega)
        Gfrf = np.empty((self.outputs, self.inputs, numFreqs),
                        dtype=np.complex128)

        # Sort frequency and calculate complex frequencies on either imaginary
        # axis (continuous time) or unit circle (discrete time).
        omega.sort()
        if isdtime(self, strict=True):
            dt = timebase(self)
            cmplx_freqs = exp(1.j * omega * dt)
            if max(np.abs(omega)) * dt > math.pi:
                warn("freqresp: frequency evaluation above Nyquist frequency")
        else:
            cmplx_freqs = omega * 1.j

        # Do the frequency response evaluation. Use TB05AD from Slycot
        # if it's available, otherwise use the built-in horners function.
        try:
            from slycot import tb05ad

            n = np.shape(self.A)[0]
            m = self.inputs
            p = self.outputs
            # The first call both evaluates C(sI-A)^-1 B and also returns
            # Hessenberg transformed matrices at, bt, ct.
            result = tb05ad(n, m, p, cmplx_freqs[0], self.A,
                            self.B, self.C, job='NG')
            # When job='NG', result = (at, bt, ct, g_i, hinvb, info)
            at = result[0]
            bt = result[1]
            ct = result[2]

            # TB05AD frequency evaluation does not include direct feedthrough.
            Gfrf[:, :, 0] = result[3] + self.D

            # Now, iterate through the remaining frequencies using the
            # transformed state matrices, at, bt, ct.

            # Start at the second frequency, already have the first.
            for kk, cmplx_freqs_kk in enumerate(cmplx_freqs[1:numFreqs]):
                result = tb05ad(n, m, p, cmplx_freqs_kk, at,
                                bt, ct, job='NH')
                # When job='NH', result = (g_i, hinvb, info)

                # kk+1 because enumerate starts at kk = 0.
                # but zero-th spot is already filled.
                Gfrf[:, :, kk+1] = result[0] + self.D

        except ImportError:  # Slycot unavailable. Fall back to horner.
            for kk, cmplx_freqs_kk in enumerate(cmplx_freqs):
                Gfrf[:, :, kk] = self.horner(cmplx_freqs_kk)

        #      mag           phase           omega
        return np.abs(Gfrf), np.angle(Gfrf), omega