예제 #1
0
파일: cohere.py 프로젝트: agramfort/nitime
def coherency(time_series, csd_method=None):
    r"""
    Compute the coherency between the spectra of n-tuple of time series.
    Input to this function is in the time domain

    Parameters
    ----------

    time_series: n*t float array
       an array of n different time series of length t each

    csd_method: dict, optional.
       See :func:`get_spectra` documentation for details

    Returns
    -------

    f : float array
        The central frequencies for the frequency bands for which the spectra
        are estimated

    c : float array
        This is a symmetric matrix with the coherencys of the signals. The
        coherency of signal i and signal j is in f[i][j]. Note that f[i][j] =
        f[j][i].conj()

    Notes
    -----

    This is an implementation of equation (1) of Sun (2005):

    .. math::

        R_{xy} (\lambda) = \frac{f_{xy}(\lambda)}
        {\sqrt{f_{xx} (\lambda) \cdot f_{yy}(\lambda)}}

    F.T. Sun and L.M. Miller and M. D'Esposito (2005). Measuring temporal
    dynamics of functional networks using phase spectrum of fMRI
    data. Neuroimage, 28: 227-37.

    """
    if csd_method is None:
        csd_method = {'this_method': 'welch'}  # The default

    f, fxy = get_spectra(time_series, csd_method)

    #A container for the coherencys, with the size and shape of the expected
    #output:
    c = np.zeros((time_series.shape[0],
                  time_series.shape[0],
                  f.shape[0]), dtype=complex)  # Make sure it's complex

    for i in xrange(time_series.shape[0]):
        for j in xrange(i, time_series.shape[0]):
            c[i][j] = coherency_spec(fxy[i][j], fxy[i][i], fxy[j][j])

    idx = tril_indices(time_series.shape[0], -1)
    c[idx[0], idx[1], ...] = c[idx[1], idx[0], ...].conj()  # Make it symmetric

    return f, c
예제 #2
0
def coherency(time_series, csd_method=None):
    r"""
    Compute the coherency between the spectra of n-tuple of time series.
    Input to this function is in the time domain

    Parameters
    ----------

    time_series: n*t float array
       an array of n different time series of length t each

    csd_method: dict, optional.
       See :func:`get_spectra` documentation for details

    Returns
    -------

    f : float array
        The central frequencies for the frequency bands for which the spectra
        are estimated

    c : float array
        This is a symmetric matrix with the coherencys of the signals. The
        coherency of signal i and signal j is in f[i][j]. Note that f[i][j] =
        f[j][i].conj()

    Notes
    -----

    This is an implementation of equation (1) of Sun (2005):

    .. math::

        R_{xy} (\lambda) = \frac{f_{xy}(\lambda)}
        {\sqrt{f_{xx} (\lambda) \cdot f_{yy}(\lambda)}}

    F.T. Sun and L.M. Miller and M. D'Esposito (2005). Measuring temporal
    dynamics of functional networks using phase spectrum of fMRI
    data. Neuroimage, 28: 227-37.

    """
    if csd_method is None:
        csd_method = {'this_method': 'welch'}  # The default

    f, fxy = get_spectra(time_series, csd_method)

    #A container for the coherencys, with the size and shape of the expected
    #output:
    c = np.zeros((time_series.shape[0], time_series.shape[0], f.shape[0]),
                 dtype=complex)  # Make sure it's complex

    for i in xrange(time_series.shape[0]):
        for j in xrange(i, time_series.shape[0]):
            c[i][j] = coherency_spec(fxy[i][j], fxy[i][i], fxy[j][j])

    idx = tril_indices(time_series.shape[0], -1)
    c[idx[0], idx[1], ...] = c[idx[1], idx[0], ...].conj()  # Make it symmetric

    return f, c
예제 #3
0
파일: cohere.py 프로젝트: agramfort/nitime
def coherency_phase_spectrum(time_series, csd_method=None):
    r"""
    Compute the phase spectrum of the cross-spectrum between two time series.

    The parameters of this function are in the time domain.

    Parameters
    ----------

    time_series: n*t float array
    The time series, with t, time, as the last dimension

    Returns
    -------

    f: mid frequencies of the bands

    p: an array with the pairwise phase spectrum between the time
    series, where p[i][j] is the phase spectrum between time series[i] and
    time_series[j]

    Notes
    -----

    This is an implementation of equation (3) of Sun et al. (2005) [Sun2005]_:

    .. math::

        \phi(\lambda) = arg [R_{xy} (\lambda)] = arg [f_{xy} (\lambda)]

    F.T. Sun and L.M. Miller and M. D'Esposito (2005). Measuring temporal
    dynamics of functional networks using phase spectrum of fMRI data.
    Neuroimage, 28: 227-37.
    """
    if csd_method is None:
        csd_method = {'this_method': 'welch'}  # The default

    f, fxy = get_spectra(time_series, csd_method)

    p = np.zeros((time_series.shape[0],
                  time_series.shape[0],
                  f.shape[0]))

    for i in xrange(time_series.shape[0]):
        for j in xrange(i + 1, time_series.shape[0]):
            p[i][j] = np.angle(fxy[i][j])
            p[j][i] = np.angle(fxy[i][j].conjugate())

    return f, p
예제 #4
0
파일: cohere.py 프로젝트: agramfort/nitime
def coherence_bavg(time_series, lb=0, ub=None, csd_method=None):
    r"""
    Compute the band-averaged coherence between the spectra of two time series.

    Input to this function is in the time domain.

    Parameters
    ----------
    time_series : float array
       An array of time series, time as the last dimension.

    lb, ub: float, optional
       The upper and lower bound on the frequency band to be used in averaging
       defaults to 1,max(f)

    csd_method: dict, optional.
       See :func:`get_spectra` documentation for details

    Returns
    -------
    c : float
       This is an upper-diagonal array, where c[i][j] is the band-averaged
       coherency between time_series[i] and time_series[j]
    """

    if csd_method is None:
        csd_method = {'this_method': 'welch'}  # The default

    f, fxy = get_spectra(time_series, csd_method)

    lb_idx, ub_idx = utils.get_bounds(f, lb, ub)

    if lb == 0:
        lb_idx = 1  # The lowest frequency band should be f0

    c = np.zeros((time_series.shape[0],
                  time_series.shape[0]))

    for i in xrange(time_series.shape[0]):
        for j in xrange(i, time_series.shape[0]):
            c[i][j] = _coherence_bavg(fxy[i][j][lb_idx:ub_idx],
                                      fxy[i][i][lb_idx:ub_idx],
                                      fxy[j][j][lb_idx:ub_idx])

    idx = tril_indices(time_series.shape[0], -1)
    c[idx[0], idx[1], ...] = c[idx[1], idx[0], ...].conj()  # Make it symmetric

    return c
예제 #5
0
파일: cohere.py 프로젝트: agramfort/nitime
def coherency_phase_delay(time_series, lb=0, ub=None, csd_method=None):
    """
    The temporal delay calculated from the coherency phase spectrum.

    Parameters
    ----------

    time_series: float array
       The time-series data for which the delay is calculated.

    lb, ub: float
       Frequency boundaries (in Hz), for the domain over which the delays are
       calculated. Defaults to 0-max(f)

    csd_method : dict, optional.
       See :func:`get_spectra`

    Returns
    -------
    f : float array
       The mid-frequencies for the frequency bands over which the calculation
       is done.
    p : float array
       Pairwise temporal delays between time-series (in seconds).

    """
    if csd_method is None:
        csd_method = {'this_method': 'welch'}  # The default

    f, fxy = get_spectra(time_series, csd_method)

    lb_idx, ub_idx = utils.get_bounds(f, lb, ub)

    if lb_idx == 0:
        lb_idx = 1

    p = np.zeros((time_series.shape[0], time_series.shape[0],
                  f[lb_idx:ub_idx].shape[-1]))

    for i in xrange(time_series.shape[0]):
        for j in xrange(i, time_series.shape[0]):
            p[i][j] = _coherency_phase_delay(f[lb_idx:ub_idx],
                                             fxy[i][j][lb_idx:ub_idx])
            p[j][i] = _coherency_phase_delay(f[lb_idx:ub_idx],
                                    fxy[i][j][lb_idx:ub_idx].conjugate())

    return f[lb_idx:ub_idx], p
예제 #6
0
def coherency_phase_delay(time_series, lb=0, ub=None, csd_method=None):
    """
    The temporal delay calculated from the coherency phase spectrum.

    Parameters
    ----------

    time_series: float array
       The time-series data for which the delay is calculated.

    lb, ub: float
       Frequency boundaries (in Hz), for the domain over which the delays are
       calculated. Defaults to 0-max(f)

    csd_method : dict, optional.
       See :func:`get_spectra`

    Returns
    -------
    f : float array
       The mid-frequencies for the frequency bands over which the calculation
       is done.
    p : float array
       Pairwise temporal delays between time-series (in seconds).

    """
    if csd_method is None:
        csd_method = {'this_method': 'welch'}  # The default

    f, fxy = get_spectra(time_series, csd_method)

    lb_idx, ub_idx = utils.get_bounds(f, lb, ub)

    if lb_idx == 0:
        lb_idx = 1

    p = np.zeros((time_series.shape[0], time_series.shape[0],
                  f[lb_idx:ub_idx].shape[-1]))

    for i in xrange(time_series.shape[0]):
        for j in xrange(i, time_series.shape[0]):
            p[i][j] = _coherency_phase_delay(f[lb_idx:ub_idx],
                                             fxy[i][j][lb_idx:ub_idx])
            p[j][i] = _coherency_phase_delay(
                f[lb_idx:ub_idx], fxy[i][j][lb_idx:ub_idx].conjugate())

    return f[lb_idx:ub_idx], p
예제 #7
0
def coherency_phase_spectrum(time_series, csd_method=None):
    r"""
    Compute the phase spectrum of the cross-spectrum between two time series.

    The parameters of this function are in the time domain.

    Parameters
    ----------

    time_series: n*t float array
    The time series, with t, time, as the last dimension

    Returns
    -------

    f: mid frequencies of the bands

    p: an array with the pairwise phase spectrum between the time
    series, where p[i][j] is the phase spectrum between time series[i] and
    time_series[j]

    Notes
    -----

    This is an implementation of equation (3) of Sun et al. (2005) [Sun2005]_:

    .. math::

        \phi(\lambda) = arg [R_{xy} (\lambda)] = arg [f_{xy} (\lambda)]

    F.T. Sun and L.M. Miller and M. D'Esposito (2005). Measuring temporal
    dynamics of functional networks using phase spectrum of fMRI data.
    Neuroimage, 28: 227-37.
    """
    if csd_method is None:
        csd_method = {'this_method': 'welch'}  # The default

    f, fxy = get_spectra(time_series, csd_method)

    p = np.zeros((time_series.shape[0], time_series.shape[0], f.shape[0]))

    for i in xrange(time_series.shape[0]):
        for j in xrange(i + 1, time_series.shape[0]):
            p[i][j] = np.angle(fxy[i][j])
            p[j][i] = np.angle(fxy[i][j].conjugate())

    return f, p
예제 #8
0
def coherence_bavg(time_series, lb=0, ub=None, csd_method=None):
    r"""
    Compute the band-averaged coherence between the spectra of two time series.

    Input to this function is in the time domain.

    Parameters
    ----------
    time_series : float array
       An array of time series, time as the last dimension.

    lb, ub: float, optional
       The upper and lower bound on the frequency band to be used in averaging
       defaults to 1,max(f)

    csd_method: dict, optional.
       See :func:`get_spectra` documentation for details

    Returns
    -------
    c : float
       This is an upper-diagonal array, where c[i][j] is the band-averaged
       coherency between time_series[i] and time_series[j]
    """

    if csd_method is None:
        csd_method = {'this_method': 'welch'}  # The default

    f, fxy = get_spectra(time_series, csd_method)

    lb_idx, ub_idx = utils.get_bounds(f, lb, ub)

    if lb == 0:
        lb_idx = 1  # The lowest frequency band should be f0

    c = np.zeros((time_series.shape[0], time_series.shape[0]))

    for i in xrange(time_series.shape[0]):
        for j in xrange(i, time_series.shape[0]):
            c[i][j] = _coherence_bavg(fxy[i][j][lb_idx:ub_idx],
                                      fxy[i][i][lb_idx:ub_idx],
                                      fxy[j][j][lb_idx:ub_idx])

    idx = tril_indices(time_series.shape[0], -1)
    c[idx[0], idx[1], ...] = c[idx[1], idx[0], ...].conj()  # Make it symmetric

    return c
예제 #9
0
파일: cohere.py 프로젝트: agramfort/nitime
def coherence_partial(time_series, r, csd_method=None):
    r"""
    Compute the band-specific partial coherence between the spectra of
    two time series.

    The partial coherence is the part of the coherence between x and
    y, which cannot be attributed to a common cause, r.

    Input to this function is in the time domain.

    Parameters
    ----------

    time_series: float array
       An array of time-series, with time as the last dimension.

    r: float array
        This array represents the temporal sequence of the common cause to be
        partialed out, sampled at the same rate as time_series

    csd_method: dict, optional
       See :func:`get_spectra` documentation for details


    Returns
    -------
    f: array,
        The mid-frequencies of the frequency bands in the spectral
        decomposition

    c: float array
       The frequency dependent partial coherence between time_series i and
       time_series j in c[i][j] and in c[j][i], with r partialed out


    Notes
    -----

    This is an implementation of equation (2) of Sun (2004):

    .. math::

        Coh_{xy|r} = \frac{|{R_{xy}(\lambda) - R_{xr}(\lambda)
        R_{ry}(\lambda)}|^2}{(1-|{R_{xr}}|^2)(1-|{R_{ry}}|^2)}

    F.T. Sun and L.M. Miller and M. D'Esposito (2004). Measuring interregional
    functional connectivity using coherence and partial coherence analyses of
    fMRI data Neuroimage, 21: 647-58.
    """

    if csd_method is None:
        csd_method = {'this_method': 'welch'}  # The default

    f, fxy = get_spectra(time_series, csd_method)

    # Initialize c according to the size of f:
    c = np.zeros((time_series.shape[0],
                  time_series.shape[0],
                  f.shape[0]), dtype=complex)

    for i in xrange(time_series.shape[0]):
        for j in xrange(i, time_series.shape[0]):
            f, fxx, frr, frx = get_spectra_bi(time_series[i], r, csd_method)
            f, fyy, frr, fry = get_spectra_bi(time_series[j], r, csd_method)
            c[i, j] = coherence_partial_spec(fxy[i][j], fxy[i][i],
                                                  fxy[j][j], frx, fry, frr)

    idx = tril_indices(time_series.shape[0], -1)
    c[idx[0], idx[1], ...] = c[idx[1], idx[0], ...].conj()  # Make it symmetric

    return f, c
예제 #10
0
파일: cohere.py 프로젝트: agramfort/nitime
def coherency_bavg(time_series, lb=0, ub=None, csd_method=None):
    r"""
    Compute the band-averaged coherency between the spectra of two time series.

    Input to this function is in the time domain.

    Parameters
    ----------
    time_series: n*t float array
       an array of n different time series of length t each

    lb, ub: float, optional
       the upper and lower bound on the frequency band to be used in averaging
       defaults to 1,max(f)

    csd_method: dict, optional.
       See :func:`get_spectra` documentation for details

    Returns
    -------
    c: float array
        This is an upper-diagonal array, where c[i][j] is the band-averaged
        coherency between time_series[i] and time_series[j]

    Notes
    -----

    This is an implementation of equation (A4) of Sun(2005):

    .. math::

        \bar{Coh_{xy}} (\bar{\lambda}) =
        \frac{\left|{\sum_\lambda{\hat{f_{xy}}}}\right|^2}
        {\sum_\lambda{\hat{f_{xx}}}\cdot sum_\lambda{\hat{f_{yy}}}}

    F.T. Sun and L.M. Miller and M. D'Esposito (2005). Measuring
    temporal dynamics of functional networks using phase spectrum of fMRI
    data. Neuroimage, 28: 227-37.
    """
    if csd_method is None:
        csd_method = {'this_method': 'welch'}  # The default

    f, fxy = get_spectra(time_series, csd_method)

    lb_idx, ub_idx = utils.get_bounds(f, lb, ub)

    if lb == 0:
        lb_idx = 1  # The lowest frequency band should be f0

    c = np.zeros((time_series.shape[0],
                  time_series.shape[0]), dtype=complex)

    for i in xrange(time_series.shape[0]):
        for j in xrange(i, time_series.shape[0]):
            c[i][j] = _coherency_bavg(fxy[i][j][lb_idx:ub_idx],
                                      fxy[i][i][lb_idx:ub_idx],
                                      fxy[j][j][lb_idx:ub_idx])

    idx = tril_indices(time_series.shape[0], -1)
    c[idx[0], idx[1], ...] = c[idx[1], idx[0], ...].conj()  # Make it symmetric

    return c
예제 #11
0
파일: cohere.py 프로젝트: agramfort/nitime
def coherence_regularized(time_series, epsilon, alpha, csd_method=None):
    r"""
    Same as coherence, except regularized in order to overcome numerical
    imprecisions

    Parameters
    ----------

    time_series: n-d float array
       The time series data for which the regularized coherence is calculated

    epsilon: float
       Small regularization parameter. Should be much smaller than any
       meaningful value of coherence you might encounter

    alpha: float
       large regularization parameter. Should be much larger than any
       meaningful value of coherence you might encounter (preferably much
       larger than 1).

    csd_method: dict, optional.
       See :func:`get_spectra` documentation for details

    Returns
    -------
    f: float array
       The central frequencies for the frequency bands for which the spectra
       are estimated

    c: n-d array
       This is a symmetric matrix with the coherencys of the signals. The
       coherency of signal i and signal j is in f[i][j].

    Returns
    -------
    frequencies, coherence

    Notes
    -----
    The regularization scheme is as follows:

    .. math::

        C_{x,y} = \frac{(\alpha f_{xx} + \epsilon)^2}
        {\alpha^{2}((f_{xx}+\epsilon)(f_{yy}+\epsilon))}

    """
    if csd_method is None:
        csd_method = {'this_method': 'welch'}  # The default

    f, fxy = get_spectra(time_series, csd_method)

    #A container for the coherences, with the size and shape of the expected
    #output:
    c = np.zeros((time_series.shape[0],
                  time_series.shape[0],
                  f.shape[0]), complex)

    for i in xrange(time_series.shape[0]):
        for j in xrange(i, time_series.shape[0]):
            c[i][j] = _coherence_reqularized(fxy[i][j], fxy[i][i],
                                             fxy[j][j], epsilon, alpha)

    idx = tril_indices(time_series.shape[0], -1)
    c[idx[0], idx[1], ...] = c[idx[1], idx[0], ...].conj()  # Make it symmetric

    return f, c
예제 #12
0
def coherence_partial(time_series, r, csd_method=None):
    r"""
    Compute the band-specific partial coherence between the spectra of
    two time series.

    The partial coherence is the part of the coherence between x and
    y, which cannot be attributed to a common cause, r.

    Input to this function is in the time domain.

    Parameters
    ----------

    time_series: float array
       An array of time-series, with time as the last dimension.

    r: float array
        This array represents the temporal sequence of the common cause to be
        partialed out, sampled at the same rate as time_series

    csd_method: dict, optional
       See :func:`get_spectra` documentation for details


    Returns
    -------
    f: array,
        The mid-frequencies of the frequency bands in the spectral
        decomposition

    c: float array
       The frequency dependent partial coherence between time_series i and
       time_series j in c[i][j] and in c[j][i], with r partialed out


    Notes
    -----

    This is an implementation of equation (2) of Sun (2004):

    .. math::

        Coh_{xy|r} = \frac{|{R_{xy}(\lambda) - R_{xr}(\lambda)
        R_{ry}(\lambda)}|^2}{(1-|{R_{xr}}|^2)(1-|{R_{ry}}|^2)}

    F.T. Sun and L.M. Miller and M. D'Esposito (2004). Measuring interregional
    functional connectivity using coherence and partial coherence analyses of
    fMRI data Neuroimage, 21: 647-58.
    """

    if csd_method is None:
        csd_method = {'this_method': 'welch'}  # The default

    f, fxy = get_spectra(time_series, csd_method)

    # Initialize c according to the size of f:
    c = np.zeros((time_series.shape[0], time_series.shape[0], f.shape[0]),
                 dtype=complex)

    for i in xrange(time_series.shape[0]):
        for j in xrange(i, time_series.shape[0]):
            f, fxx, frr, frx = get_spectra_bi(time_series[i], r, csd_method)
            f, fyy, frr, fry = get_spectra_bi(time_series[j], r, csd_method)
            c[i, j] = coherence_partial_spec(fxy[i][j], fxy[i][i], fxy[j][j],
                                             frx, fry, frr)

    idx = tril_indices(time_series.shape[0], -1)
    c[idx[0], idx[1], ...] = c[idx[1], idx[0], ...].conj()  # Make it symmetric

    return f, c
예제 #13
0
def coherency_bavg(time_series, lb=0, ub=None, csd_method=None):
    r"""
    Compute the band-averaged coherency between the spectra of two time series.

    Input to this function is in the time domain.

    Parameters
    ----------
    time_series: n*t float array
       an array of n different time series of length t each

    lb, ub: float, optional
       the upper and lower bound on the frequency band to be used in averaging
       defaults to 1,max(f)

    csd_method: dict, optional.
       See :func:`get_spectra` documentation for details

    Returns
    -------
    c: float array
        This is an upper-diagonal array, where c[i][j] is the band-averaged
        coherency between time_series[i] and time_series[j]

    Notes
    -----

    This is an implementation of equation (A4) of Sun(2005):

    .. math::

        \bar{Coh_{xy}} (\bar{\lambda}) =
        \frac{\left|{\sum_\lambda{\hat{f_{xy}}}}\right|^2}
        {\sum_\lambda{\hat{f_{xx}}}\cdot sum_\lambda{\hat{f_{yy}}}}

    F.T. Sun and L.M. Miller and M. D'Esposito (2005). Measuring
    temporal dynamics of functional networks using phase spectrum of fMRI
    data. Neuroimage, 28: 227-37.
    """
    if csd_method is None:
        csd_method = {'this_method': 'welch'}  # The default

    f, fxy = get_spectra(time_series, csd_method)

    lb_idx, ub_idx = utils.get_bounds(f, lb, ub)

    if lb == 0:
        lb_idx = 1  # The lowest frequency band should be f0

    c = np.zeros((time_series.shape[0], time_series.shape[0]), dtype=complex)

    for i in xrange(time_series.shape[0]):
        for j in xrange(i, time_series.shape[0]):
            c[i][j] = _coherency_bavg(fxy[i][j][lb_idx:ub_idx],
                                      fxy[i][i][lb_idx:ub_idx],
                                      fxy[j][j][lb_idx:ub_idx])

    idx = tril_indices(time_series.shape[0], -1)
    c[idx[0], idx[1], ...] = c[idx[1], idx[0], ...].conj()  # Make it symmetric

    return c
예제 #14
0
def coherence_regularized(time_series, epsilon, alpha, csd_method=None):
    r"""
    Same as coherence, except regularized in order to overcome numerical
    imprecisions

    Parameters
    ----------

    time_series: n-d float array
       The time series data for which the regularized coherence is calculated

    epsilon: float
       Small regularization parameter. Should be much smaller than any
       meaningful value of coherence you might encounter

    alpha: float
       large regularization parameter. Should be much larger than any
       meaningful value of coherence you might encounter (preferably much
       larger than 1).

    csd_method: dict, optional.
       See :func:`get_spectra` documentation for details

    Returns
    -------
    f: float array
       The central frequencies for the frequency bands for which the spectra
       are estimated

    c: n-d array
       This is a symmetric matrix with the coherencys of the signals. The
       coherency of signal i and signal j is in f[i][j].

    Returns
    -------
    frequencies, coherence

    Notes
    -----
    The regularization scheme is as follows:

    .. math::

        C_{x,y} = \frac{(\alpha f_{xx} + \epsilon)^2}
        {\alpha^{2}((f_{xx}+\epsilon)(f_{yy}+\epsilon))}

    """
    if csd_method is None:
        csd_method = {'this_method': 'welch'}  # The default

    f, fxy = get_spectra(time_series, csd_method)

    #A container for the coherences, with the size and shape of the expected
    #output:
    c = np.zeros((time_series.shape[0], time_series.shape[0], f.shape[0]),
                 complex)

    for i in xrange(time_series.shape[0]):
        for j in xrange(i, time_series.shape[0]):
            c[i][j] = _coherence_reqularized(fxy[i][j], fxy[i][i], fxy[j][j],
                                             epsilon, alpha)

    idx = tril_indices(time_series.shape[0], -1)
    c[idx[0], idx[1], ...] = c[idx[1], idx[0], ...].conj()  # Make it symmetric

    return f, c
예제 #15
0
파일: cohere.py 프로젝트: mwaskom/nitime
def coherence(time_series, csd_method=None):
    r"""Compute the coherence between the spectra of an n-tuple of time_series.

    Parameters of this function are in the time domain.

    Parameters
    ----------
    time_series: float array
       an array of different time series with time as the last dimension

    csd_method: dict, optional
       See :func:`get_spectra` documentation for details

    Returns
    -------
    f : float array
        The central frequencies for the frequency bands for which the spectra
        are estimated

    c : float array
        This is a symmetric matrix with the coherencys of the signals. The
        coherency of signal i and signal j is in f[i][j].

    Notes
    -----

    This is an implementation of equation (2) of [Sun2005]_:

    .. math::

        Coh_{xy}(\lambda) = |{R_{xy}(\lambda)}|^2 =
        \frac{|{f_{xy}(\lambda)}|^2}{f_{xx}(\lambda) \cdot f_{yy}(\lambda)}

    .. [Sun2005] F.T. Sun and L.M. Miller and M. D'Esposito(2005). Measuring
        temporal dynamics of functional networks using phase spectrum of fMRI
        data.  Neuroimage, 28: 227-37.

    See also
    --------
    :func:`coherence_spec`

    """
    if csd_method is None:
        csd_method = {'this_method': 'welch'}  # The default

    f, fxy = get_spectra(time_series, csd_method)

    #A container for the coherences, with the size and shape of the expected
    #output:
    c = np.zeros((time_series.shape[0],
                  time_series.shape[0],
                  f.shape[0]))

    for i in xrange(time_series.shape[0]):
        for j in xrange(i, time_series.shape[0]):
            c[i][j] = coherence_spec(fxy[i][j], fxy[i][i], fxy[j][j])

    idx = np.tril_indices(time_series.shape[0], -1)
    c[idx[0], idx[1], ...] = c[idx[1], idx[0], ...].conj()  # Make it symmetric

    return f, c