Ejemplo n.º 1
0
def test_get_num_den():
    """Test function for _get_num_den()"""
    from scipy.signal import zpk2ss
    z = (.4, )
    p = (.9, .1 + .2j, .1 - .2j)
    k = .4
    num, den = zpk2tf(z, p, k)
    numt, dent = _get_num_den((num, den))  # num, den
    assert np.allclose(numt, num, atol=1e-8, rtol=1e-5)
    assert np.allclose(dent, den, atol=1e-8, rtol=1e-5)
    numt, dent = _get_num_den((z, p, k))  # zpk
    assert np.allclose(numt, num, atol=1e-8, rtol=1e-5)
    assert np.allclose(dent, den, atol=1e-8, rtol=1e-5)
    numt, dent = _get_num_den(lti(z, p, k))  # LTI
    assert np.allclose(numt, num, atol=1e-8, rtol=1e-5)
    assert np.allclose(dent, den, atol=1e-8, rtol=1e-5)
    assert len(numt.shape) == 1
    assert len(dent.shape) == 1
    A, B, C, D = zpk2ss(z, p, k)  # A,B,C,D
    D = np.atleast_2d(D)
    numt, dent = _get_num_den((A, B, C, D))  # A,B,C,D
    assert np.allclose(numt, num, atol=1e-8, rtol=1e-5)
    assert np.allclose(dent, den, atol=1e-8, rtol=1e-5)
    ABCD = np.vstack((np.hstack((A, B)), np.hstack((C, D))))
    numt, dent = _get_num_den(ABCD)  # A,B,C,D
    assert np.allclose(numt, num, atol=1e-8, rtol=1e-5)
    assert np.allclose(dent, den, atol=1e-8, rtol=1e-5)
    H = [[1], [2]]  # check no 0-length arrays are returned
    numt, dent = _get_num_den(H)
    assert np.allclose(numt, 1, atol=1e-8, rtol=1e-5)
    assert np.allclose(dent, 2, atol=1e-8, rtol=1e-5)
    assert len(numt.shape) == 1
    assert len(dent.shape) == 1
Ejemplo n.º 2
0
    def get_state_space(self):
        """Get a state space representation of this filter

        Returns:
          ss: a scipy.signal state space representation of the filter
        """
        zs, ps, k = self.get_zpk(Hz=False)
        return sig.StateSpace(*sig.zpk2ss(assertArr(zs), assertArr(ps), k))
Ejemplo n.º 3
0
def dcgain(*args):
    '''
    Compute the gain of the system in steady state.

    The function takes either 1, 2, 3, or 4 parameters:

    Parameters
    ----------
    A, B, C, D: array-like
        A linear system in state space form.
    Z, P, k: array-like, array-like, number
        A linear system in zero, pole, gain form.
    num, den: array-like
        A linear system in transfer function form.
    sys: Lti (StateSpace or TransferFunction)
        A linear system object.

    Returns
    -------
    gain: matrix
        The gain of each output versus each input:
        :math:`y = gain \cdot u`
    
    Notes
    -----
    This function is only useful for systems with invertible system 
    matrix ``A``. 
    
    All systems are first converted to state space form. The function then 
    computes:
    
    .. math:: gain = - C \cdot A^{-1} \cdot B + D
    '''
    #Convert the parameters to state space form
    if len(args) == 4:
        A, B, C, D = args
        sys = ss(A, B, C, D)
    elif len(args) == 3:
        Z, P, k = args
        A, B, C, D = zpk2ss(Z, P, k)
        sys = ss(A, B, C, D)
    elif len(args) == 2:
        num, den = args
        sys = tf2ss(num, den)
    elif len(args) == 1:
        sys, = args
        sys = ss(sys)
    else:
        raise ValueError("Function ``dcgain`` needs either 1, 2, 3 or 4 "
                         "arguments.")
    #gain = - C * A**-1 * B + D
    gain = sys.D - sys.C * sys.A.I * sys.B
    return gain
Ejemplo n.º 4
0
def dcgain(*args):
    '''
    Compute the gain of the system in steady state.

    The function takes either 1, 2, 3, or 4 parameters:

    Parameters
    ----------
    A, B, C, D: array-like
        A linear system in state space form.
    Z, P, k: array-like, array-like, number
        A linear system in zero, pole, gain form.
    num, den: array-like
        A linear system in transfer function form.
    sys: Lti (StateSpace or TransferFunction)
        A linear system object.

    Returns
    -------
    gain: matrix
        The gain of each output versus each input:
        :math:`y = gain \cdot u`

    Notes
    -----
    This function is only useful for systems with invertible system
    matrix ``A``.

    All systems are first converted to state space form. The function then
    computes:

    .. math:: gain = - C \cdot A^{-1} \cdot B + D
    '''
    #Convert the parameters to state space form
    if len(args) == 4:
        A, B, C, D = args
        sys = ss(A, B, C, D)
    elif len(args) == 3:
        Z, P, k = args
        A, B, C, D = zpk2ss(Z, P, k)
        sys = ss(A, B, C, D)
    elif len(args) == 2:
        num, den = args
        sys = tf2ss(num, den)
    elif len(args) == 1:
        sys, = args
        sys = ss(sys)
    else:
        raise ValueError("Function ``dcgain`` needs either 1, 2, 3 or 4 "
                         "arguments.")
    #gain = - C * A**-1 * B + D
    gain = sys.D - sys.C * sys.A.I * sys.B
    return gain
Ejemplo n.º 5
0
def test_get_zpk():
    """Test function for _get_zpk()"""
    from scipy.signal import zpk2ss
    z = (.4, )
    p = (.9, .1 + .2j, .1 - .2j)
    k = .4
    zt, pt, kt = _get_zpk(zpk2ss(z, p, k))
    assert np.allclose(zt, z, atol=1e-8, rtol=1e-5)
    assert np.allclose(pt, p, atol=1e-8, rtol=1e-5)
    assert np.allclose((kt, ), (k, ), atol=1e-8, rtol=1e-5)
    zt, pt, kt = _get_zpk(zpk2tf(z, p, k))
    assert np.allclose(zt, z, atol=1e-8, rtol=1e-5)
    assert np.allclose(pt, p, atol=1e-8, rtol=1e-5)
    assert np.allclose((kt, ), (k, ), atol=1e-8, rtol=1e-5)
    zt, pt, kt = _get_zpk(lti(z, p, k))
    assert np.allclose(zt, z, atol=1e-8, rtol=1e-5)
    assert np.allclose(pt, p, atol=1e-8, rtol=1e-5)
    assert np.allclose((kt, ), (k, ), atol=1e-8, rtol=1e-5)
Ejemplo n.º 6
0
def test_get_zpk():
    """Test function for _get_zpk()"""
    from scipy.signal import zpk2ss
    z = (.4,)
    p = (.9, .1 + .2j, .1 - .2j)
    k = .4
    zt, pt, kt = _get_zpk(zpk2ss(z, p, k))
    assert np.allclose(zt, z, atol=1e-8, rtol=1e-5)
    assert np.allclose(pt, p, atol=1e-8, rtol=1e-5)
    assert np.allclose((kt, ), (k, ), atol=1e-8, rtol=1e-5)
    zt, pt, kt = _get_zpk(zpk2tf(z, p, k))
    assert np.allclose(zt, z, atol=1e-8, rtol=1e-5)
    assert np.allclose(pt, p, atol=1e-8, rtol=1e-5)
    assert np.allclose((kt, ), (k, ), atol=1e-8, rtol=1e-5)
    zt, pt, kt = _get_zpk(lti(z, p, k))
    assert np.allclose(zt, z, atol=1e-8, rtol=1e-5)
    assert np.allclose(pt, p, atol=1e-8, rtol=1e-5)
    assert np.allclose((kt, ), (k, ), atol=1e-8, rtol=1e-5)
Ejemplo n.º 7
0
def test_minreal():
    """Test function for minreal()"""
    from scipy.signal import zpk2ss
    z = np.array([0, 1])
    p = np.array([1, .5 + .5j, .5 - .5j])
    k = 1
    zt = z[:-1]
    pt = p[1:]
    pt.sort()
    inobj = (z, p, k)
    ltiobj = minreal(inobj)
    zeros, poles, gain = _get_zpk(ltiobj)
    poles.sort()
    assert np.allclose(zeros, zt, atol=1e-8, rtol=1e-5)
    assert np.allclose(poles, poles, atol=1e-8, rtol=1e-5)
    assert np.allclose((k, ), (gain, ), atol=1e-8, rtol=1e-5)
    inobj = zpk2tf(z, p, k)
    ltiobj = minreal(inobj)
    zeros, poles, gain = _get_zpk(ltiobj)
    poles.sort()
    assert np.allclose(zeros, zt, atol=1e-8, rtol=1e-5)
    assert np.allclose(poles, poles, atol=1e-8, rtol=1e-5)
    assert np.allclose((k, ), (gain, ), atol=1e-8, rtol=1e-5)
    inobj = zpk2ss(z, p, k)
    ltiobj = minreal(inobj)
    zeros, poles, gain = _get_zpk(ltiobj)
    poles.sort()
    assert np.allclose(zeros, zt, atol=1e-8, rtol=1e-5)
    assert np.allclose(poles, poles, atol=1e-8, rtol=1e-5)
    assert np.allclose((k, ), (gain, ), atol=1e-8, rtol=1e-5)
    inobj = lti(z, p, k)
    ltiobj = minreal(inobj)
    zeros, poles, gain = _get_zpk(ltiobj)
    poles.sort()
    assert np.allclose(zeros, zt, atol=1e-8, rtol=1e-5)
    assert np.allclose(poles, poles, atol=1e-8, rtol=1e-5)
    assert np.allclose((k, ), (gain, ), atol=1e-8, rtol=1e-5)
Ejemplo n.º 8
0
def test_minreal():
    """Test function for minreal()"""
    from scipy.signal import zpk2ss
    z = np.array([0, 1])
    p = np.array([1, .5 + .5j, .5 - .5j])
    k = 1
    zt = z[:-1]
    pt = p[1:]
    pt.sort()
    inobj = (z, p, k)
    ltiobj = minreal(inobj)
    zeros, poles, gain = _get_zpk(ltiobj)
    poles.sort()
    assert np.allclose(zeros, zt, atol=1e-8, rtol=1e-5)
    assert np.allclose(poles, poles, atol=1e-8, rtol=1e-5)
    assert np.allclose((k,), (gain,), atol=1e-8, rtol=1e-5)
    inobj = zpk2tf(z, p, k)
    ltiobj = minreal(inobj)
    zeros, poles, gain = _get_zpk(ltiobj)
    poles.sort()
    assert np.allclose(zeros, zt, atol=1e-8, rtol=1e-5)
    assert np.allclose(poles, poles, atol=1e-8, rtol=1e-5)
    assert np.allclose((k,), (gain,), atol=1e-8, rtol=1e-5)
    inobj = zpk2ss(z, p, k)
    ltiobj = minreal(inobj)
    zeros, poles, gain = _get_zpk(ltiobj)
    poles.sort()
    assert np.allclose(zeros, zt, atol=1e-8, rtol=1e-5)
    assert np.allclose(poles, poles, atol=1e-8, rtol=1e-5)
    assert np.allclose((k,), (gain,), atol=1e-8, rtol=1e-5)
    inobj = lti(z, p, k)
    ltiobj = minreal(inobj)
    zeros, poles, gain = _get_zpk(ltiobj)
    poles.sort()
    assert np.allclose(zeros, zt, atol=1e-8, rtol=1e-5)
    assert np.allclose(poles, poles, atol=1e-8, rtol=1e-5)
    assert np.allclose((k,), (gain,), atol=1e-8, rtol=1e-5)
Ejemplo n.º 9
0
def test_get_num_den():
    """Test function for _get_num_den()"""
    from scipy.signal import zpk2ss
    z = (.4,)
    p = (.9, .1 + .2j, .1 - .2j)
    k = .4
    num, den = zpk2tf(z, p, k)
    numt, dent = _get_num_den((num, den))  # num, den
    assert np.allclose(numt, num, atol=1e-8, rtol=1e-5)
    assert np.allclose(dent, den, atol=1e-8, rtol=1e-5)
    numt, dent = _get_num_den((z, p, k))  # zpk
    assert np.allclose(numt, num, atol=1e-8, rtol=1e-5)
    assert np.allclose(dent, den, atol=1e-8, rtol=1e-5)
    numt, dent = _get_num_den(lti(z, p, k))  # LTI
    assert np.allclose(numt, num, atol=1e-8, rtol=1e-5)
    assert np.allclose(dent, den, atol=1e-8, rtol=1e-5)
    assert len(numt.shape) == 1
    assert len(dent.shape) == 1
    A, B, C, D = zpk2ss(z, p, k)  # A,B,C,D
    D = np.atleast_2d(D)
    numt, dent = _get_num_den((A, B, C, D))  # A,B,C,D
    assert np.allclose(numt, num, atol=1e-8, rtol=1e-5)
    assert np.allclose(dent, den, atol=1e-8, rtol=1e-5)
    ABCD = np.vstack((
                     np.hstack((A, B)),
                     np.hstack((C, D))
                     ))
    numt, dent = _get_num_den(ABCD)  # A,B,C,D
    assert np.allclose(numt, num, atol=1e-8, rtol=1e-5)
    assert np.allclose(dent, den, atol=1e-8, rtol=1e-5)
    H = [[1],[2]] # check no 0-length arrays are returned
    numt, dent = _get_num_den(H)
    assert np.allclose(numt, 1, atol=1e-8, rtol=1e-5)
    assert np.allclose(dent, 2, atol=1e-8, rtol=1e-5)
    assert len(numt.shape) == 1
    assert len(dent.shape) == 1
Ejemplo n.º 10
0
def bb_c2d(sys, Ts, method='zoh'):
    """Continous to discrete conversion with ZOH method

    Call:
    sysd=c2d(sys,Ts,method='zoh')

    Parameters
    ----------
    sys :   System in statespace or Tf form 
    Ts:     Sampling Time
    method: 'zoh', 'bi' or 'matched'

    Returns
    -------
    sysd: ss or Tf system
    Discrete system

    """
    flag = 0
    if isinstance(sys, TransferFunction):
        sys = tf2ss(sys)
        flag = 1

    a = sys.A
    b = sys.B
    c = sys.C
    d = sys.D
    n = shape(a)[0]
    nb = shape(b)[1]
    nc = shape(c)[0]

    if method == 'zoh':
        ztmp = zeros((nb, n + nb))
        tmp = hstack((a, b))
        tmp = vstack((tmp, ztmp))
        tmp = expm(tmp * Ts)
        A = tmp[0:n, 0:n]
        B = tmp[0:n, n:n + nb]
        C = c
        D = d
    elif method == 'bi':
        a = mat(a)
        b = mat(b)
        c = mat(c)
        d = mat(d)
        IT = mat(2 / Ts * eye(n, n))
        A = (IT + a) * inv(IT - a)
        iab = inv(IT - a) * b
        tk = 2 / sqrt(Ts)
        B = tk * iab
        C = tk * (c * inv(IT - a))
        D = d + c * iab
    elif method == 'matched':
        if nb != 1 and nc != 1:
            print "System is not SISO"
            return
        p = exp(sys.poles * Ts)
        z = exp(sys.zeros * Ts)
        infinite_zeros = len(sys.poles) - len(sys.zeros) - 1
        for i in range(0, infinite_zeros):
            z = hstack((z, -1))
        [A, B, C, D] = zpk2ss(z, p, 1)
        sysd = StateSpace(A, B, C, D, Ts)
        cg = dcgain(sys)
        dg = dcgain(sysd)
        [A, B, C, D] = zpk2ss(z, p, cg / dg)
    else:
        print "Method not supported"
        return

    sysd = StateSpace(A, B, C, D, Ts)
    if flag == 1:
        sysd = ss2tf(sysd)
    return sysd
def simulateDSM(u, arg2, nlev=2, x0=0.):
    """Simulate a Delta Sigma modulator

    **Syntax:**

     * [v, xn, xmax, y] = simulateDSM(u, ABCD, nlev=2, x0=0)
     * [v, xn, xmax, y] = simulateDSM(u, ntf, nlev=2, x0=0)

    Compute the output of a general delta-sigma modulator with input u,
    a structure described by ABCD, an initial state x0 (default zero) and
    a quantizer with a number of levels specified by nlev.
    Multiple quantizers are implied by making nlev an array,
    and multiple inputs are implied by the number of rows in u.

    Alternatively, the modulator may be described by an NTF.
    The NTF is zpk object. (And the STF is assumed to be 1.)
    The structure that is simulated is the block-diagonal structure used by
    ``zpk2ss()``.

    **Example:**

    Simulate a 5th-order binary modulator with a half-scale sine-wave input and
    plot its output in the time and frequency domains.::

        import numpy as np
        from deltasigma import *
        OSR = 32
        H = synthesizeNTF(5, OSR, 1)
        N = 8192 
        fB = np.ceil(N/(2*OSR))
        f = 85
        u = 0.5*np.sin(2*np.pi*f/N*np.arange(N))
        v = simulateDSM(u, H)[0]

    Graphical display of the results:

    .. plot::

        import numpy as np
        import pylab as plt
        from numpy.fft import fft
        from deltasigma import *
        OSR = 32
        H = synthesizeNTF(5, OSR, 1)
        N = 8192 
        fB = np.ceil(N/(2*OSR))
        f = 85
        u = 0.5*np.sin(2*np.pi*f/N*np.arange(N))
        v = simulateDSM(u, H)[0]
        plt.figure(figsize=(10, 7))
        plt.subplot(2, 1, 1)
        t = np.arange(85)
        # the equivalent of MATLAB 'stairs' is step in matplotlib
        plt.step(t, u[t], 'g', label='u(n)')
        plt.hold(True)
        plt.step(t, v[t], 'b', label='v(n)')
        plt.axis([0, 85, -1.2, 1.2]);
        plt.ylabel('u, v');
        plt.xlabel('sample')
        plt.legend()
        plt.subplot(2, 1, 2)
        spec = fft(v*ds_hann(N))/(N/4)
        plt.plot(np.linspace(0, 0.5, N/2 + 1), dbv(spec[:N/2 + 1]))
        plt.axis([0, 0.5, -120, 0])
        plt.grid(True)
        plt.ylabel('dBFS/NBW')
        snr = calculateSNR(spec[:fB], f)
        s = 'SNR = %4.1fdB' % snr
        plt.text(0.25, -90, s)
        s =  'NBW = %7.5f' % (1.5/N)
        plt.text(0.25, -110, s)
        plt.xlabel("frequency $1 \\\\rightarrow f_s$")

    Click on "Source" above to see the source code.
    """

    #fprintf(1,'Warning: You are running the non-mex version of simulateDSM.\n');
    #fprintf(1,'Please compile the mex version with "mex simulateDSM.c"\n');

    nlev = carray(nlev)
    u = np.array(u) if not hasattr(u, 'ndim') else u
    if not max(u.shape) == np.prod(u.shape):
        warn("Multiple input delta sigma structures have had little testing.")
    if u.ndim == 1:
        u = u.reshape((1, -1))
    nu = u.shape[0]
    nq = 1 if np.isscalar(nlev) else nlev.shape[0]
    # extract poles and zeros
    if (hasattr(arg2, 'inputs') and not arg2.inputs == 1) or \
       (hasattr(arg2, 'outputs') and not arg2.outputs == 1):
            raise TypeError("The supplied TF isn't a SISO transfer function.")
    if isinstance(arg2, np.ndarray):
        ABCD = np.asarray(arg2, dtype=np.float64)
        if ABCD.shape[1] != ABCD.shape[0] + nu:
            raise ValueError('The ABCD argument does not have proper dimensions.')
        form = 1
    else:
        zeros, poles, k = _get_zpk(arg2)
        form = 2
    #raise TypeError('%s: Unknown transfer function %s' % (__name__, str(arg2)))
        
    # need to set order and form now.
    order = carray(zeros).shape[0] if form == 2 else ABCD.shape[0] - nq
    
    if not isinstance(x0, collections.Iterable):
        x0 = x0*np.ones((order,), dtype=np.float64)
    else:
        x0 = np.array(x0).reshape((-1,))
    
    if form == 1:
        A = ABCD[:order, :order]
        B = ABCD[:order, order:order+nu+nq]
        C = ABCD[order:order+nq, :order]
        D1 = ABCD[order:order+nq, order:order+nu]
    else:
        A, B2, C, D2 = zpk2ss(poles, zeros, -1)    # A realization of 1/H
        # Transform the realization so that C = [1 0 0 ...]
        C, D2 = np.real_if_close(C), np.real_if_close(D2)
        Sinv = orth(np.hstack((np.transpose(C), np.eye(order)))) / norm(C)
        S = inv(Sinv)
        C = np.dot(C, Sinv)
        if C[0, 0] < 0:
            S = -S
            Sinv = -Sinv
        A = np.dot(np.dot(S, A), Sinv) 
        B2 = np.dot(S, B2) 
        C = np.hstack((np.ones((1, 1)), np.zeros((1, order-1)))) # C=C*Sinv; 
        D2 = np.zeros((0,))
        # !!!! Assume stf=1
        B1 = -B2
        D1 = 1
        B = np.hstack((B1, B2))

    N = u.shape[1]
    v = np.empty((nq, N), dtype=np.float64)
    y = np.empty((nq, N), dtype=np.float64)     # to store the quantizer input
    xn = np.empty((order, N), dtype=np.float64) # to store the state information
    xmax = np.abs(x0) # to keep track of the state maxima

    for i in range(N):
        # y0 needs to be cast to real because ds_quantize needs real
        # inputs. If quantization were defined for complex numbers,
        # this cast could be removed
        y0 = np.real(np.dot(C, x0) + np.dot(D1, u[:, i]))
        y[:, i] = y0
        v[:, i] = ds_quantize(y0, nlev)
        x0 = np.dot(A, x0) + np.dot(B, np.concatenate((u[:, i], v[:, i])))
        xn[:, i] = np.real_if_close(x0.T)
        xmax = np.max(np.hstack((np.abs(x0).reshape((-1, 1)), xmax.reshape((-1, 1)))),
                      axis=1, keepdims=True)

    return v.squeeze(), xn.squeeze(), xmax, y.squeeze()
Ejemplo n.º 12
0
def simulateDSM(u, arg2, nlev=2, x0=0.):
    """Simulate a Delta Sigma modulator

    **Syntax:**

     * [v, xn, xmax, y] = simulateDSM(u, ABCD, nlev=2, x0=0)
     * [v, xn, xmax, y] = simulateDSM(u, ntf, nlev=2, x0=0)

    Compute the output of a general delta-sigma modulator with input u,
    a structure described by ABCD, an initial state x0 (default zero) and
    a quantizer with a number of levels specified by nlev.
    Multiple quantizers are implied by making nlev an array,
    and multiple inputs are implied by the number of rows in u.

    Alternatively, the modulator may be described by an NTF.
    The NTF is zpk object. (And the STF is assumed to be 1.)
    The structure that is simulated is the block-diagonal structure used by
    ``zpk2ss()``.

    **Example:**

    Simulate a 5th-order binary modulator with a half-scale sine-wave input and
    plot its output in the time and frequency domains.::

        import numpy as np
        from deltasigma import *
        OSR = 32
        H = synthesizeNTF(5, OSR, 1)
        N = 8192 
        fB = np.ceil(N/(2*OSR))
        f = 85
        u = 0.5*np.sin(2*np.pi*f/N*np.arange(N))
        v = simulateDSM(u, H)[0]

    Graphical display of the results:

    .. plot::

        import numpy as np
        import pylab as plt
        from numpy.fft import fft
        from deltasigma import *
        OSR = 32
        H = synthesizeNTF(5, OSR, 1)
        N = 8192 
        fB = np.ceil(N/(2*OSR))
        f = 85
        u = 0.5*np.sin(2*np.pi*f/N*np.arange(N))
        v = simulateDSM(u, H)[0]
        plt.figure(figsize=(10, 7))
        plt.subplot(2, 1, 1)
        t = np.arange(85)
        # the equivalent of MATLAB 'stairs' is step in matplotlib
        plt.step(t, u[t], 'g', label='u(n)')
        plt.hold(True)
        plt.step(t, v[t], 'b', label='v(n)')
        plt.axis([0, 85, -1.2, 1.2]);
        plt.ylabel('u, v');
        plt.xlabel('sample')
        plt.legend()
        plt.subplot(2, 1, 2)
        spec = fft(v*ds_hann(N))/(N/4)
        plt.plot(np.linspace(0, 0.5, N/2 + 1), dbv(spec[:N/2 + 1]))
        plt.axis([0, 0.5, -120, 0])
        plt.grid(True)
        plt.ylabel('dBFS/NBW')
        snr = calculateSNR(spec[:fB], f)
        s = 'SNR = %4.1fdB' % snr
        plt.text(0.25, -90, s)
        s =  'NBW = %7.5f' % (1.5/N)
        plt.text(0.25, -110, s)
        plt.xlabel("frequency $1 \\\\rightarrow f_s$")

    Click on "Source" above to see the source code.
    """

    #fprintf(1,'Warning: You are running the non-mex version of simulateDSM.\n');
    #fprintf(1,'Please compile the mex version with "mex simulateDSM.c"\n');

    nlev = carray(nlev)
    u = np.array(u) if not hasattr(u, 'ndim') else u
    if not max(u.shape) == np.prod(u.shape):
        warn("Multiple input delta sigma structures have had little testing.")
    if u.ndim == 1:
        u = u.reshape((1, -1))
    nu = u.shape[0]
    nq = 1 if np.isscalar(nlev) else nlev.shape[0]
    # extract poles and zeros
    if (hasattr(arg2, 'inputs') and not arg2.inputs == 1) or \
       (hasattr(arg2, 'outputs') and not arg2.outputs == 1):
        raise TypeError("The supplied TF isn't a SISO transfer function.")
    if isinstance(arg2, np.ndarray):
        ABCD = np.asarray(arg2, dtype=np.float64)
        if ABCD.shape[1] != ABCD.shape[0] + nu:
            raise ValueError(
                'The ABCD argument does not have proper dimensions.')
        form = 1
    else:
        zeros, poles, k = _get_zpk(arg2)
        form = 2
    #raise TypeError('%s: Unknown transfer function %s' % (__name__, str(arg2)))

    # need to set order and form now.
    order = carray(zeros).shape[0] if form == 2 else ABCD.shape[0] - nq

    if not isinstance(x0, collections.abc.Iterable):
        x0 = x0 * np.ones((order, ), dtype=np.float64)
    else:
        x0 = np.array(x0).reshape((-1, ))

    if form == 1:
        A = ABCD[:order, :order]
        B = ABCD[:order, order:order + nu + nq]
        C = ABCD[order:order + nq, :order]
        D1 = ABCD[order:order + nq, order:order + nu]
    else:
        A, B2, C, D2 = zpk2ss(poles, zeros, -1)  # A realization of 1/H
        # Transform the realization so that C = [1 0 0 ...]
        C, D2 = np.real_if_close(C), np.real_if_close(D2)
        Sinv = orth(np.hstack((np.transpose(C), np.eye(order)))) / norm(C)
        S = inv(Sinv)
        C = np.dot(C, Sinv)
        if C[0, 0] < 0:
            S = -S
            Sinv = -Sinv
        A = np.dot(np.dot(S, A), Sinv)
        B2 = np.dot(S, B2)
        C = np.hstack((np.ones((1, 1)), np.zeros((1, order - 1))))  # C=C*Sinv;
        D2 = np.zeros((0, ))
        # !!!! Assume stf=1
        B1 = -B2
        D1 = 1
        B = np.hstack((B1, B2))

    #N = u.shape[1]
    N = np.max(np.shape(u))  # Return max dimension

    #empty -> zeros
    v = np.zeros((nq, N), dtype=np.float64)
    y = np.zeros((nq, N), dtype=np.float64)  # to store the quantizer input
    xn = np.zeros((order, N),
                  dtype=np.float64)  # to store the state information
    xmax = np.abs(x0)  # to keep track of the state maxima

    for i in range(N):
        # y0 needs to be cast to real because ds_quantize needs real
        # inputs. If quantization were defined for complex numbers,
        # this cast could be removed
        y0 = np.real(np.dot(C, x0) + np.dot(D1, u[:, i]))
        y[:, i] = y0
        v[:, i] = ds_quantize(y0, nlev)
        x0 = np.dot(A, x0) + np.dot(B, np.concatenate((u[:, i], v[:, i])))
        xn[:, i] = np.real_if_close(x0.T)
        xmax = np.max(np.hstack((np.abs(x0).reshape(
            (-1, 1)), xmax.reshape((-1, 1)))),
                      axis=1,
                      keepdims=True)

    return v.squeeze(), xn.squeeze(), xmax, y.squeeze()
def simulateDSM(u, arg2, nlev=2, x0=0,
                store_xn=False, store_xmax=False, store_y=False):

    warn('Running the slow version of simulateDSM.',
         PyDsmSlowPathWarning)

    # Make sure that nlev is an array
    nlev = np.asarray(nlev).reshape(1)

    # Make sure that input is a matrix
    u = np.asarray(u)
    if u.ndim == 1:
        u = u.reshape(1, -1)

    nu = u.shape[0]
    nq = np.size(nlev)

    if type(arg2) == tuple and len(arg2) == 3:
        # Assume ntf in zpk form
        (ntf_z, ntf_p, ntf_k) = arg2
        form = 2
        order = len(ntf_z)
    else:
        # Assume ABCD form
        ABCD = np.asarray(arg2)
        if ABCD.shape[1] == nu+ABCD.shape[0]:
            # ABCD dimensions OK
            form = 1
            order = ABCD.shape[0]-nq
        else:
            raise ValueError('Incorrect modulator specification')

    # Assure that the state is a column vector
    if np.isscalar(x0) and x0 == 0:
        x0 = np.zeros((order, 1))
    else:
        x0 = np.array(x0, dtype=float).reshape(-1, 1)

    if form == 1:
        A = ABCD[0:order, 0:order]
        B = ABCD[0:order, order:order+nu+nq]
        C = ABCD[order:order+nq, 0:order]
        D1 = ABCD[order:order+nq, order:order+nu]
    else:
        # Seek a realization of -1/H
        A, B2, C, D2 = zpk2ss(ntf_p, ntf_z, -1)
        # Transform the realization so that C = [1 0 0 ...]
        Sinv = (linalg.orth(np.hstack((np.transpose(C), np.eye(order)))) /
                np.linalg.norm(C))
        S = linalg.inv(Sinv)
        C = np.dot(C, Sinv)
        if C[0, 0] < 0:
            S = -S
            Sinv = -Sinv
        A = np.dot(np.dot(S, A), Sinv)
        B2 = np.dot(S, B2)
        C = np.hstack(([[1]], np.zeros((1, order-1))))
        # C=C*Sinv;
        # D2 = 0;
        # !!!! Assume stf=1
        B1 = -B2
        D1 = 1
        B = np.hstack((B1, B2))

    N = u.shape[1]
    v = np.empty((nq, N))
    if store_y:
        # Need to store the quantizer input
        y = np.empty((nq, N))
    else:
        y = np.empty((0, 0))
    if store_xn:
        # Need to store the state information
        xn = np.empty((order, N))
    if store_xmax:
        # Need to keep track of the state maxima
        xmax = np.abs(x0)
    else:
        xmax = np.empty(0)

    for i in range(N):
        # I guess the coefficients in A, B, C, D should be real...
        y0 = np.real(np.dot(C, x0) + np.dot(D1, u[:, i]))
        if store_y:
            y[:, i] = y0
        v[:, i] = ds_quantize(y0, nlev)
        x0 = np.dot(A, x0) + np.dot(B, np.vstack((u[:, i], v[:, i])))
        if store_xn:
            # Save the next state
            xn[:, i] = x0
        if store_xmax:
            # Keep track of the state maxima
            xmax = np.max((np.abs(x0), xmax), 0)
    if not store_xn:
        xn = x0
    return v.squeeze(), xn.squeeze(), xmax, y.squeeze()
Ejemplo n.º 14
0
    nums, den = ss2tf(A, B, C, D)
    if len(nums) != 1:
        # TODO: support MIMO/SIMO/MISO systems
        # https://github.com/scipy/scipy/issues/5753
        raise NotImplementedError("System (%s, %s, %s, %s) must be SISO to "
                                  "convert to transfer function" %
                                  (A, B, C, D))
    return nums[0], den


_sys2ss = {
    _LSYS: lambda sys: _ss(sys.ss),
    _LFILT: lambda sys: _ss(tf2ss(sys.num, sys.den)),
    _NUM: lambda sys: _ss(tf2ss(sys, 1)),
    _TF: lambda sys: _ss(tf2ss(*sys)),
    _ZPK: lambda sys: _ss(zpk2ss(*sys)),
    _SS: lambda sys: _ss(sys),
}

_sys2zpk = {
    _LSYS: lambda sys: sys.zpk,
    _LFILT: lambda sys: tf2zpk(sys.num, sys.den),
    _NUM: lambda sys: tf2zpk(sys, 1),
    _TF: lambda sys: tf2zpk(*sys),
    _ZPK: lambda sys: sys,
    _SS: lambda sys: ss2zpk(*sys),
}

_sys2tf = {
    _LSYS: lambda sys: sys.tf,
    _LFILT: lambda sys: _tf(sys.num, sys.den),
Ejemplo n.º 15
0
            raise ValueError("D must be scalar for zero-order models")
        return (D[0], 1.)  # pragma: no cover; solved in scipy>=0.18rc2
    nums, den = ss2tf(A, B, C, D)
    if len(nums) != 1:
        # TODO: support MIMO systems
        # https://github.com/scipy/scipy/issues/5753
        raise NotImplementedError("System must be SISO")
    return nums[0], den


_sys2ss = {
    _LSYS: lambda sys: sys.ss,
    _LFILT: lambda sys: tf2ss(sys.num, sys.den),
    _NUM: lambda sys: tf2ss(sys, 1),
    _TF: lambda sys: tf2ss(*sys),
    _ZPK: lambda sys: zpk2ss(*sys),
    _SS: lambda sys: sys,
}

_sys2zpk = {
    _LSYS: lambda sys: sys.zpk,
    _LFILT: lambda sys: tf2zpk(sys.num, sys.den),
    _NUM: lambda sys: tf2zpk(sys, 1),
    _TF: lambda sys: tf2zpk(*sys),
    _ZPK: lambda sys: sys,
    _SS: lambda sys: ss2zpk(*sys),
}

_sys2tf = {
    _LSYS: lambda sys: sys.tf,
    _LFILT: lambda sys: _tf(sys.num, sys.den),