Exemple #1
0
def test_tridi_inverse_iteration():
    import scipy.linalg as la
    from scipy.sparse import spdiags
    # set up a spectral concentration eigenvalue problem for testing
    N = 2000
    NW = 4
    K = 8
    W = float(NW) / N
    nidx = np.arange(N, dtype='d')
    ab = np.zeros((2, N), 'd')
    # store this separately for tridisolve later
    sup_diag = np.zeros((N, ), 'd')
    sup_diag[:-1] = nidx[1:] * (N - nidx[1:]) / 2.
    ab[0, 1:] = sup_diag[:-1]
    ab[1] = ((N - 1 - 2 * nidx) / 2.)**2 * np.cos(2 * np.pi * W)
    # only calculate the highest Kmax-1 eigenvalues
    w = la.eigvals_banded(ab, select='i', select_range=(N - K, N - 1))
    w = w[::-1]
    E = np.zeros((K, N), 'd')
    t = np.linspace(0, np.pi, N)
    # make sparse tridiagonal matrix for eigenvector check
    sp_data = np.zeros((3, N), 'd')
    sp_data[0, :-1] = sup_diag[:-1]
    sp_data[1] = ab[1]
    sp_data[2, 1:] = sup_diag[:-1]
    A = spdiags(sp_data, [-1, 0, 1], N, N)
    E = np.zeros((K, N), 'd')
    for j in xrange(K):
        e = utils.tridi_inverse_iteration(ab[1],
                                          sup_diag,
                                          w[j],
                                          x0=np.sin((j + 1) * t))
        b = A * e
        nt.assert_true(
               np.linalg.norm(np.abs(b) - np.abs(w[j]*e)) < 1e-8,
               'Inverse iteration eigenvector solution is inconsistent with '\
               'given eigenvalue'
               )
        E[j] = e

    # also test orthonormality of the eigenvectors
    ident = np.dot(E, E.T)
    npt.assert_almost_equal(ident, np.eye(K))
Exemple #2
0
def test_tridi_inverse_iteration():
    import scipy.linalg as la
    from scipy.sparse import spdiags
    # set up a spectral concentration eigenvalue problem for testing
    N = 2000
    NW = 4
    K = 8
    W = float(NW) / N
    nidx = np.arange(N, dtype='d')
    ab = np.zeros((2, N), 'd')
    # store this separately for tridisolve later
    sup_diag = np.zeros((N,), 'd')
    sup_diag[:-1] = nidx[1:] * (N - nidx[1:]) / 2.
    ab[0, 1:] = sup_diag[:-1]
    ab[1] = ((N - 1 - 2 * nidx) / 2.) ** 2 * np.cos(2 * np.pi * W)
    # only calculate the highest Kmax-1 eigenvalues
    w = la.eigvals_banded(ab, select='i', select_range=(N - K, N - 1))
    w = w[::-1]
    E = np.zeros((K, N), 'd')
    t = np.linspace(0, np.pi, N)
    # make sparse tridiagonal matrix for eigenvector check
    sp_data = np.zeros((3,N), 'd')
    sp_data[0, :-1] = sup_diag[:-1]
    sp_data[1] = ab[1]
    sp_data[2, 1:] = sup_diag[:-1]
    A = spdiags(sp_data, [-1, 0, 1], N, N)
    E = np.zeros((K,N), 'd')
    for j in xrange(K):
        e = utils.tridi_inverse_iteration(
            ab[1], sup_diag, w[j], x0=np.sin((j+1)*t)
            )
        b = A*e
        nt.assert_true(
               np.linalg.norm(np.abs(b) - np.abs(w[j]*e)) < 1e-8,
               'Inverse iteration eigenvector solution is inconsistent with '\
               'given eigenvalue'
               )
        E[j] = e

    # also test orthonormality of the eigenvectors
    ident = np.dot(E, E.T)
    npt.assert_almost_equal(ident, np.eye(K))
Exemple #3
0
def dpss_windows(N, NW, Kmax, interp_from=None, interp_kind='linear'):
    """
    Returns the Discrete Prolate Spheroidal Sequences of orders [0,Kmax-1]
    for a given frequency-spacing multiple NW and sequence length N.

    Paramters
    ---------
    N : int
        sequence length
    NW : float, unitless
        standardized half bandwidth corresponding to 2NW = BW*f0 = BW*N/dt
        but with dt taken as 1
    Kmax : int
        number of DPSS windows to return is Kmax (orders 0 through Kmax-1)
    interp_from: int (optional)
        The dpss will can calculated using interpolation from a set of dpss
        with the same NW and Kmax, but shorter N. This is the length of this
        shorter set of dpss windows.
    interp_kind: str (optional)
        This input variable is passed to scipy.interpolate.interp1d and
        specifies the kind of interpolation as a string ('linear', 'nearest',
        'zero', 'slinear', 'quadratic, 'cubic') or as an integer specifying the
        order of the spline interpolator to use.


    Returns
    -------
    v, e : tuple,
        v is an array of DPSS windows shaped (Kmax, N)
        e are the eigenvalues

    Notes
    -----
    Tridiagonal form of DPSS calculation from:

    Slepian, D. Prolate spheroidal wave functions, Fourier analysis, and
    uncertainty V: The discrete case. Bell System Technical Journal,
    Volume 57 (1978), 1371430
    """
    Kmax = int(Kmax)
    W = float(NW) / N
    nidx = np.arange(N, dtype='d')

    # In this case, we create the dpss windows of the smaller size
    # (interp_from) and then interpolate to the larger size (N)
    if interp_from is not None:
        if interp_from > N:
            e_s = 'In dpss_windows, interp_from is: %s ' % interp_from
            e_s += 'and N is: %s. ' % N
            e_s += 'Please enter interp_from smaller than N.'
            raise ValueError(e_s)
        dpss = []
        d, e = dpss_windows(interp_from, NW, Kmax)
        for this_d in d:
            x = np.arange(this_d.shape[-1])
            I = interpolate.interp1d(x, this_d, kind=interp_kind)
            d_temp = I(np.arange(0, this_d.shape[-1] - 1,
                                 float(this_d.shape[-1] - 1) / N))

            # Rescale:
            d_temp = d_temp / np.sqrt(np.sum(d_temp ** 2))

            dpss.append(d_temp)

        dpss = np.array(dpss)

    else:
        # here we want to set up an optimization problem to find a sequence
        # whose energy is maximally concentrated within band [-W,W].
        # Thus, the measure lambda(T,W) is the ratio between the energy within
        # that band, and the total energy. This leads to the eigen-system
        # (A - (l1)I)v = 0, where the eigenvector corresponding to the largest
        # eigenvalue is the sequence with maximally concentrated energy. The
        # collection of eigenvectors of this system are called Slepian
        # sequences, or discrete prolate spheroidal sequences (DPSS). Only the
        # first K, K = 2NW/dt orders of DPSS will exhibit good spectral
        # concentration
        # [see http://en.wikipedia.org/wiki/Spectral_concentration_problem]

        # Here I set up an alternative symmetric tri-diagonal eigenvalue
        # problem such that
        # (B - (l2)I)v = 0, and v are our DPSS (but eigenvalues l2 != l1)
        # the main diagonal = ([N-1-2*t]/2)**2 cos(2PIW), t=[0,1,2,...,N-1]
        # and the first off-diagonal = t(N-t)/2, t=[1,2,...,N-1]
        # [see Percival and Walden, 1993]
        diagonal = ((N - 1 - 2 * nidx) / 2.) ** 2 * np.cos(2 * np.pi * W)
        off_diag = np.zeros_like(nidx)
        off_diag[:-1] = nidx[1:] * (N - nidx[1:]) / 2.
        # put the diagonals in LAPACK "packed" storage
        ab = np.zeros((2, N), 'd')
        ab[1] = diagonal
        ab[0, 1:] = off_diag[:-1]
        # only calculate the highest Kmax eigenvalues
        w = linalg.eigvals_banded(ab, select='i',
                                  select_range=(N - Kmax, N - 1))
        w = w[::-1]

        # find the corresponding eigenvectors via inverse iteration
        t = np.linspace(0, np.pi, N)
        dpss = np.zeros((Kmax, N), 'd')
        for k in xrange(Kmax):
            dpss[k] = utils.tridi_inverse_iteration(
                diagonal, off_diag, w[k], x0=np.sin((k + 1) * t)
                )

    # By convention (Percival and Walden, 1993 pg 379)
    # * symmetric tapers (k=0,2,4,...) should have a positive average.
    # * antisymmetric tapers should begin with a positive lobe
    fix_symmetric = (dpss[0::2].sum(axis=1) < 0)
    for i, f in enumerate(fix_symmetric):
        if f:
            dpss[2 * i] *= -1
    fix_skew = (dpss[1::2, 1] < 0)
    for i, f in enumerate(fix_skew):
        if f:
            dpss[2 * i + 1] *= -1

    # Now find the eigenvalues of the original spectral concentration problem
    # Use the autocorr sequence technique from Percival and Walden, 1993 pg 390
    dpss_rxx = utils.autocorr(dpss) * N
    r = 4 * W * np.sinc(2 * W * nidx)
    r[0] = 2 * W
    eigvals = np.dot(dpss_rxx, r)

    return dpss, eigvals