コード例 #1
0
ファイル: test_model.py プロジェクト: FNNDSC/nipy
def test_run():
    ar1_fname = 'ar1_out.nii'
    funcim = load_image(funcfile)
    fmriims = FmriImageList.from_image(funcim, volume_start_times=2.)
    one_vol = fmriims[0]
    # Formula - with an intercept
    t = Term('t')
    f = Formula([t, t**2, t**3, 1])
    # Design matrix and contrasts
    time_vector = make_recarray(fmriims.volume_start_times, 't')
    con_defs = dict(c=t, c2=t+t**2)
    desmtx, cmatrices = f.design(time_vector, contrasts=con_defs)

    # Run with Image and ImageList
    for inp_img in (img_rollaxis(funcim, 't'), fmriims):
        with InTemporaryDirectory():
            # Run OLS model
            outputs = []
            outputs.append(model.output_AR1(ar1_fname, fmriims))
            outputs.append(model.output_resid('resid_OLS_out.nii', fmriims))
            ols = model.OLS(fmriims, f, outputs)
            ols.execute()
            # Run AR1 model
            outputs = []
            outputs.append(
                model.output_T('T_out.nii', cmatrices['c'], fmriims))
            outputs.append(
                model.output_F('F_out.nii', cmatrices['c2'], fmriims))
            outputs.append(
                model.output_resid('resid_AR_out.nii', fmriims))
            rho = load_image(ar1_fname)
            ar = model.AR1(fmriims, f, rho, outputs)
            ar.execute()
            f_img = load_image('F_out.nii')
            assert_equal(f_img.shape, one_vol.shape)
            f_data = f_img.get_data()
            assert_true(np.all((f_data>=0) & (f_data<30)))
            resid_img = load_image('resid_AR_out.nii')
            assert_equal(resid_img.shape, funcim.shape[3:] + one_vol.shape)
            assert_array_almost_equal(np.mean(resid_img.get_data()), 0, 3)
            e_img = load_image('T_out_effect.nii')
            sd_img = load_image('T_out_sd.nii')
            t_img = load_image('T_out_t.nii')
            t_data = t_img.get_data()
            assert_array_almost_equal(t_data,
                                      e_img.get_data() / sd_img.get_data())
            assert_true(np.all(np.abs(t_data) < 6))
            # Need to delete to help windows delete temporary files
            del rho, resid_img, f_img, e_img, sd_img, t_img, f_data, t_data
コード例 #2
0
def test_run():
    ar1_fname = 'ar1_out.nii'
    funcim = load_image(funcfile)
    fmriims = FmriImageList.from_image(funcim, volume_start_times=2.)
    one_vol = fmriims[0]
    # Formula - with an intercept
    t = Term('t')
    f = Formula([t, t**2, t**3, 1])
    # Design matrix and contrasts
    time_vector = make_recarray(fmriims.volume_start_times, 't')
    con_defs = dict(c=t, c2=t + t**2)
    desmtx, cmatrices = f.design(time_vector, contrasts=con_defs)

    # Run with Image and ImageList
    for inp_img in (rollimg(funcim, 't'), fmriims):
        with InTemporaryDirectory():
            # Run OLS model
            outputs = []
            outputs.append(model.output_AR1(ar1_fname, fmriims))
            outputs.append(model.output_resid('resid_OLS_out.nii', fmriims))
            ols = model.OLS(fmriims, f, outputs)
            ols.execute()
            # Run AR1 model
            outputs = []
            outputs.append(model.output_T('T_out.nii', cmatrices['c'],
                                          fmriims))
            outputs.append(
                model.output_F('F_out.nii', cmatrices['c2'], fmriims))
            outputs.append(model.output_resid('resid_AR_out.nii', fmriims))
            rho = load_image(ar1_fname)
            ar = model.AR1(fmriims, f, rho, outputs)
            ar.execute()
            f_img = load_image('F_out.nii')
            assert_equal(f_img.shape, one_vol.shape)
            f_data = f_img.get_data()
            assert_true(np.all((f_data >= 0) & (f_data < 30)))
            resid_img = load_image('resid_AR_out.nii')
            assert_equal(resid_img.shape, funcim.shape)
            assert_array_almost_equal(np.mean(resid_img.get_data()), 0, 3)
            e_img = load_image('T_out_effect.nii')
            sd_img = load_image('T_out_sd.nii')
            t_img = load_image('T_out_t.nii')
            t_data = t_img.get_data()
            assert_array_almost_equal(t_data,
                                      e_img.get_data() / sd_img.get_data())
            assert_true(np.all(np.abs(t_data) < 6))
            # Need to delete to help windows delete temporary files
            del rho, resid_img, f_img, e_img, sd_img, t_img, f_data, t_data
コード例 #3
0
ファイル: utils.py プロジェクト: mfkiwl/nipy
def fourier_basis(freq):
    """ sin and cos Formula for Fourier drift

    The Fourier basis consists of sine and cosine waves of given
    frequencies.

    Parameters
    ----------
    freq : sequence of float
        Frequencies for the terms in the Fourier basis.

    Returns
    -------
    f : Formula

    Examples
    --------
    >>> f=fourier_basis([1,2,3])
    >>> f.terms
    array([cos(2*pi*t), sin(2*pi*t), cos(4*pi*t), sin(4*pi*t), cos(6*pi*t),
           sin(6*pi*t)], dtype=object)
    >>> f.mean
    _b0*cos(2*pi*t) + _b1*sin(2*pi*t) + _b2*cos(4*pi*t) + _b3*sin(4*pi*t) + _b4*cos(6*pi*t) + _b5*sin(6*pi*t)
    """
    r = []
    for f in freq:
        r += [
            sympy.cos((2 * sympy.pi * f * T)),
            sympy.sin((2 * sympy.pi * f * T))
        ]
    return Formula(r)
コード例 #4
0
def event_design(event_spec,
                 t,
                 order=2,
                 hrfs=(glover, ),
                 level_contrasts=False):
    """ Create design matrix from event specification `event_spec`

    Create a design matrix for linear model based on an event specification
    `event_spec`, evaluating the design rows at a sequence of time values `t`.
    Each column in the design matrix will be convolved with each HRF in `hrfs`.

    Parameters
    ----------
    event_spec : np.recarray
       A recarray having at least a field named 'time' signifying the event
       time, and all other fields will be treated as factors in an ANOVA-type
       model.
    t : np.ndarray
       An array of np.float values at which to evaluate the design. Common
       examples would be the acquisition times of an fMRI image.
    order : int, optional
       The highest order interaction to be considered in constructing
       the contrast matrices.
    hrfs : sequence, optional
       A sequence of (symbolic) HRFs that will be convolved with each event.
       Default is ``(glover,)``.
    level_contrasts : bool, optional
       If True, generate contrasts for each individual level
       of each factor.

    Returns
    -------
    X : np.ndarray
       The design matrix with ``X.shape[0] == t.shape[0]``. The number of
       columns will depend on the other fields of `event_spec`.
    contrasts : dict
       Dictionary of contrasts that is expected to be of interest from the event
       specification. Each interaction / effect up to a given order will be
       returned. Also, a contrast is generated for each interaction / effect for
       each HRF specified in hrfs.
    """
    fields = list(event_spec.dtype.names)
    if 'time' not in fields:
        raise ValueError('expecting a field called "time"')
    fields.pop(fields.index('time'))
    e_factors = [Factor(n, np.unique(event_spec[n])) for n in fields]
    e_formula = np.product(e_factors)
    e_contrasts = {}

    if len(e_factors) > 1:
        for i in range(1, order + 1):
            for comb in combinations(zip(fields, e_factors), i):
                names = [c[0] for c in comb]
                fs = [c[1].main_effect for c in comb]
                e_contrasts[":".join(names)] = np.product(fs).design(
                    event_spec)

    e_contrasts['constant'] = formulae.I.design(event_spec)

    # Design and contrasts in event space
    # TODO: make it so I don't have to call design twice here
    # to get both the contrasts and the e_X matrix as a recarray

    e_X = e_formula.design(event_spec)
    e_dtype = e_formula.dtype

    # Now construct the design in time space
    t_terms = []
    t_contrasts = {}
    for l, h in enumerate(hrfs):
        for n in e_dtype.names:
            term = events(event_spec['time'], amplitudes=e_X[n], f=h)
            t_terms += [term]
            if level_contrasts:
                t_contrasts['%s_%d' % (n, l)] = Formula([term])
        for n, c in e_contrasts.items():
            t_contrasts["%s_%d" % (n, l)] = Formula([ \
                 events(event_spec['time'], amplitudes=c[nn], f=h)
                 for i, nn in enumerate(c.dtype.names)])
    t_formula = Formula(t_terms)

    tval = make_recarray(t, ['t'])
    X_t, c_t = t_formula.design(tval, contrasts=t_contrasts)
    return X_t, c_t
コード例 #5
0
def block_design(block_spec,
                 t,
                 order=2,
                 hrfs=(glover, ),
                 convolution_padding=5.,
                 convolution_dt=0.02,
                 hrf_interval=(0., 30.),
                 level_contrasts=False):
    """ Create a design matrix from specification of blocks `block_spec`

    Create design matrix for linear model from a block specification
    `block_spec`,  evaluating design rows at a sequence of time values `t`.
    Each column in the design matrix will be convolved with each HRF in `hrfs`.

    Parameters
    ----------
    block_spec : np.recarray
       A recarray having at least a field named 'start' and a field named 'end'
       signifying the block time, and all other fields will be treated as
       factors in an ANOVA-type model.
    t : np.ndarray
       An array of np.float values at which to evaluate the design. Common
       examples would be the acquisition times of an fMRI image.
    order : int, optional
       The highest order interaction to be considered in constructing the
       contrast matrices.
    hrfs : sequence, optional
       A sequence of (symbolic) HRFs that will be convolved with each block.
       Default is ``(glover,)``.
    convolution_padding : float, optional
       A padding for the convolution with the HRF. The intervals
       used for the convolution are the smallest 'start' minus this
       padding to the largest 'end' plus this padding.
    convolution_dt : float, optional
       Time step for high-resolution time course for use in convolving the
       blocks with each HRF.
    hrf_interval: length 2 sequence of floats, optional
       Interval over which the HRF is assumed supported, used in the
       convolution.
    level_contrasts : bool, optional
       If true, generate contrasts for each individual level
       of each factor.

    Returns
    -------
    X : np.ndarray
       The design matrix with X.shape[0] == t.shape[0]. The number of
       columns will depend on the other fields of block_spec.
    contrasts : dict
       Dictionary of contrasts that is expected to be of interest from
       the block specification. For each interaction / effect up to a
       given order will be returned. Also, a contrast is generated for
       each interaction / effect for each HRF specified in hrfs.
    """
    fields = list(block_spec.dtype.names)
    if 'start' not in fields or 'end' not in fields:
        raise ValueError('expecting fields called "start" and "end"')
    fields.pop(fields.index('start'))
    fields.pop(fields.index('end'))
    e_factors = [Factor(n, np.unique(block_spec[n])) for n in fields]
    e_formula = np.product(e_factors)
    e_contrasts = {}
    if len(e_factors) > 1:
        for i in range(1, order + 1):
            for comb in combinations(zip(fields, e_factors), i):
                names = [c[0] for c in comb]
                fs = [c[1].main_effect for c in comb]
                e_contrasts[":".join(names)] = np.product(fs).design(
                    block_spec)

    e_contrasts['constant'] = formulae.I.design(block_spec)

    # Design and contrasts in block space
    # TODO: make it so I don't have to call design twice here
    # to get both the contrasts and the e_X matrix as a recarray

    e_X = e_formula.design(block_spec)
    e_dtype = e_formula.dtype

    # Now construct the design in time space

    block_times = np.array([
        (s, e) for s, e in zip(block_spec['start'], block_spec['end'])
    ])
    convolution_interval = (block_times.min() - convolution_padding,
                            block_times.max() + convolution_padding)

    t_terms = []
    t_names = []
    t_contrasts = {}
    for l, h in enumerate(hrfs):
        for n in e_dtype.names:
            B = blocks(block_times, amplitudes=e_X[n])
            term = convolve_functions(B, h(T), convolution_interval,
                                      hrf_interval, convolution_dt)
            t_terms += [term]
            if level_contrasts:
                t_contrasts['%s_%d' % (n, l)] = Formula([term])
        for n, c in e_contrasts.items():
            F = []
            for i, nn in enumerate(c.dtype.names):
                B = blocks(block_times, amplitudes=c[nn])
                F.append(
                    convolve_functions(B, h(T), convolution_interval,
                                       hrf_interval, convolution_dt))
            t_contrasts["%s_%d" % (n, l)] = Formula(F)
    t_formula = Formula(t_terms)

    tval = make_recarray(t, ['t'])
    X_t, c_t = t_formula.design(tval, contrasts=t_contrasts)
    return X_t, c_t
コード例 #6
0
def block_amplitudes(name,
                     block_spec,
                     t,
                     hrfs=(glover, ),
                     convolution_padding=5.,
                     convolution_dt=0.02,
                     hrf_interval=(0., 30.)):
    """ Design matrix at times `t` for blocks specification `block_spec`

    Create design matrix for linear model from a block specification
    `block_spec`,  evaluating design rows at a sequence of time values `t`.

    `block_spec` may specify amplitude of response for each event, if different
    (see description of `block_spec` parameter below).

    The on-off step function implied by `block_spec` will be convolved with
    each HRF in `hrfs` to form a design matrix shape ``(len(t), len(hrfs))``.

    Parameters
    ----------
    name : str
        Name of condition
    block_spec : np.recarray or array-like
       A recarray having fields ``start, end, amplitude``, or a 2D ndarray /
       array-like with three columns corresponding to start, end, amplitude.
    t : np.ndarray
       An array of np.float values at which to evaluate the design. Common
       examples would be the acquisition times of an fMRI image.
    hrfs : sequence, optional
       A sequence of (symbolic) HRFs that will be convolved with each block.
       Default is ``(glover,)``.
    convolution_padding : float, optional
       A padding for the convolution with the HRF. The intervals
       used for the convolution are the smallest 'start' minus this
       padding to the largest 'end' plus this padding.
    convolution_dt : float, optional
       Time step for high-resolution time course for use in convolving the
       blocks with each HRF.
    hrf_interval: length 2 sequence of floats, optional
       Interval over which the HRF is assumed supported, used in the
       convolution.

    Returns
    -------
    X : np.ndarray
       The design matrix with ``X.shape[0] == t.shape[0]``. The number of
       columns will be ``len(hrfs)``.
    contrasts : dict
       A contrast is generated for each HRF specified in `hrfs`.
    """
    block_spec = np.asarray(block_spec)
    if block_spec.dtype.names is not None:
        if block_spec.dtype.names not in (('start', 'end'), ('start', 'end',
                                                             'amplitude')):
            raise ValueError('expecting fields called "start", "end" and '
                             '(optionally) "amplitude"')
        block_spec = np.array(block_spec.tolist())
    block_times = block_spec[:, :2]
    amplitudes = block_spec[:, 2] if block_spec.shape[1] == 3 else None
    # Now construct the design in time space
    convolution_interval = (block_times.min() - convolution_padding,
                            block_times.max() + convolution_padding)
    B = blocks(block_times, amplitudes=amplitudes)
    t_terms = []
    c_t = {}
    n_hrfs = len(hrfs)
    for hrf_no in range(n_hrfs):
        t_terms.append(
            convolve_functions(B, hrfs[hrf_no](T), convolution_interval,
                               hrf_interval, convolution_dt))
        contrast = np.zeros(n_hrfs)
        contrast[hrf_no] = 1
        c_t['{0}_{1:d}'.format(name, hrf_no)] = contrast
    t_formula = Formula(t_terms)
    tval = make_recarray(t, ['t'])
    X_t = t_formula.design(tval, return_float=True)
    return X_t, c_t
コード例 #7
0
ファイル: design.py プロジェクト: alexis-roche/nipy
def event_design(event_spec, t, order=2, hrfs=(glover,),
                 level_contrasts=False):
    """ Create design matrix from event specification `event_spec`

    Create a design matrix for linear model based on an event specification
    `event_spec`, evaluating the design rows at a sequence of time values `t`.
    Each column in the design matrix will be convolved with each HRF in `hrfs`.

    Parameters
    ----------
    event_spec : np.recarray
       A recarray having at least a field named 'time' signifying the event
       time, and all other fields will be treated as factors in an ANOVA-type
       model.
    t : np.ndarray
       An array of np.float values at which to evaluate the design. Common
       examples would be the acquisition times of an fMRI image.
    order : int, optional
       The highest order interaction to be considered in constructing
       the contrast matrices.
    hrfs : sequence, optional
       A sequence of (symbolic) HRFs that will be convolved with each event.
       Default is ``(glover,)``.
    level_contrasts : bool, optional
       If True, generate contrasts for each individual level
       of each factor.

    Returns
    -------
    X : np.ndarray
       The design matrix with ``X.shape[0] == t.shape[0]``. The number of
       columns will depend on the other fields of `event_spec`.
    contrasts : dict
       Dictionary of contrasts that is expected to be of interest from the event
       specification. Each interaction / effect up to a given order will be
       returned. Also, a contrast is generated for each interaction / effect for
       each HRF specified in hrfs.
    """
    fields = list(event_spec.dtype.names)
    if 'time' not in fields:
        raise ValueError('expecting a field called "time"')
    fields.pop(fields.index('time'))
    e_factors = [Factor(n, np.unique(event_spec[n])) for n in fields]
    e_formula = np.product(e_factors)
    e_contrasts = {}

    if len(e_factors) > 1:
        for i in range(1, order+1):
            for comb in combinations(zip(fields, e_factors), i):
                names = [c[0] for c in comb]
                fs = [c[1].main_effect for c in comb]
                e_contrasts[":".join(names)] = np.product(fs).design(event_spec)

    e_contrasts['constant'] = formulae.I.design(event_spec)

    # Design and contrasts in event space
    # TODO: make it so I don't have to call design twice here
    # to get both the contrasts and the e_X matrix as a recarray

    e_X = e_formula.design(event_spec)
    e_dtype = e_formula.dtype

    # Now construct the design in time space
    t_terms = []
    t_contrasts = {}
    for l, h in enumerate(hrfs):
        for n in e_dtype.names:
            term = events(event_spec['time'], amplitudes=e_X[n], f=h)
            t_terms  += [term]
            if level_contrasts:
                t_contrasts['%s_%d' % (n, l)] = Formula([term])
        for n, c in e_contrasts.items():
            t_contrasts["%s_%d" % (n, l)] = Formula([ \
                 events(event_spec['time'], amplitudes=c[nn], f=h)
                 for i, nn in enumerate(c.dtype.names)])
    t_formula = Formula(t_terms)

    tval = make_recarray(t, ['t'])
    X_t, c_t = t_formula.design(tval, contrasts=t_contrasts)
    return X_t, c_t
コード例 #8
0
ファイル: design.py プロジェクト: alexis-roche/nipy
def block_design(block_spec, t, order=2, hrfs=(glover,),
                 convolution_padding=5.,
                 convolution_dt=0.02,
                 hrf_interval=(0.,30.),
                 level_contrasts=False):
    """ Create a design matrix from specification of blocks `block_spec`

    Create design matrix for linear model from a block specification
    `block_spec`,  evaluating design rows at a sequence of time values `t`.
    Each column in the design matrix will be convolved with each HRF in `hrfs`.

    Parameters
    ----------
    block_spec : np.recarray
       A recarray having at least a field named 'start' and a field named 'end'
       signifying the block time, and all other fields will be treated as
       factors in an ANOVA-type model.
    t : np.ndarray
       An array of np.float values at which to evaluate the design. Common
       examples would be the acquisition times of an fMRI image.
    order : int, optional
       The highest order interaction to be considered in constructing the
       contrast matrices.
    hrfs : sequence, optional
       A sequence of (symbolic) HRFs that will be convolved with each block.
       Default is ``(glover,)``.
    convolution_padding : float, optional
       A padding for the convolution with the HRF. The intervals
       used for the convolution are the smallest 'start' minus this
       padding to the largest 'end' plus this padding.
    convolution_dt : float, optional
       Time step for high-resolution time course for use in convolving the
       blocks with each HRF.
    hrf_interval: length 2 sequence of floats, optional
       Interval over which the HRF is assumed supported, used in the
       convolution.
    level_contrasts : bool, optional
       If true, generate contrasts for each individual level
       of each factor.

    Returns
    -------
    X : np.ndarray
       The design matrix with X.shape[0] == t.shape[0]. The number of
       columns will depend on the other fields of block_spec.
    contrasts : dict
       Dictionary of contrasts that is expected to be of interest from
       the block specification. For each interaction / effect up to a
       given order will be returned. Also, a contrast is generated for
       each interaction / effect for each HRF specified in hrfs.
    """
    fields = list(block_spec.dtype.names)
    if 'start' not in fields or 'end' not in fields:
        raise ValueError('expecting fields called "start" and "end"')
    fields.pop(fields.index('start'))
    fields.pop(fields.index('end'))
    e_factors = [Factor(n, np.unique(block_spec[n])) for n in fields]
    e_formula = np.product(e_factors)
    e_contrasts = {}
    if len(e_factors) > 1:
        for i in range(1, order+1):
            for comb in combinations(zip(fields, e_factors), i):
                names = [c[0] for c in comb]
                fs = [c[1].main_effect for c in comb]
                e_contrasts[":".join(names)] = np.product(fs).design(block_spec)

    e_contrasts['constant'] = formulae.I.design(block_spec)

    # Design and contrasts in block space
    # TODO: make it so I don't have to call design twice here
    # to get both the contrasts and the e_X matrix as a recarray

    e_X = e_formula.design(block_spec)
    e_dtype = e_formula.dtype

    # Now construct the design in time space

    block_times = np.array([(s,e) for s, e in zip(block_spec['start'], 
                                                  block_spec['end'])])
    convolution_interval = (block_times.min() - convolution_padding, 
                            block_times.max() + convolution_padding)

    t_terms = []
    t_names = []
    t_contrasts = {}
    for l, h in enumerate(hrfs):
        for n in e_dtype.names:
            B = blocks(block_times, amplitudes=e_X[n])
            term = convolve_functions(B, h(T), 
                                      convolution_interval,
                                      hrf_interval,
                                      convolution_dt)
            t_terms += [term]
            if level_contrasts:
                t_contrasts['%s_%d' % (n, l)] = Formula([term])
        for n, c in e_contrasts.items():
            F = []
            for i, nn in enumerate(c.dtype.names):
                B = blocks(block_times, amplitudes=c[nn])
                F.append(convolve_functions(B, h(T),
                                            convolution_interval,
                                            hrf_interval,
                                            convolution_dt))
            t_contrasts["%s_%d" % (n, l)] = Formula(F)
    t_formula = Formula(t_terms)

    tval = make_recarray(t, ['t'])
    X_t, c_t = t_formula.design(tval, contrasts=t_contrasts)
    return X_t, c_t
コード例 #9
0
ファイル: design.py プロジェクト: alexsavio/nipy
def block_amplitudes(name, block_spec, t, hrfs=(glover,),
                     convolution_padding=5.,
                     convolution_dt=0.02,
                     hrf_interval=(0.,30.)):
    """ Design matrix at times `t` for blocks specification `block_spec`

    Create design matrix for linear model from a block specification
    `block_spec`,  evaluating design rows at a sequence of time values `t`.

    `block_spec` may specify amplitude of response for each event, if different
    (see description of `block_spec` parameter below).

    The on-off step function implied by `block_spec` will be convolved with
    each HRF in `hrfs` to form a design matrix shape ``(len(t), len(hrfs))``.

    Parameters
    ----------
    name : str
        Name of condition
    block_spec : np.recarray or array-like
       A recarray having fields ``start, end, amplitude``, or a 2D ndarray /
       array-like with three columns corresponding to start, end, amplitude.
    t : np.ndarray
       An array of np.float values at which to evaluate the design. Common
       examples would be the acquisition times of an fMRI image.
    hrfs : sequence, optional
       A sequence of (symbolic) HRFs that will be convolved with each block.
       Default is ``(glover,)``.
    convolution_padding : float, optional
       A padding for the convolution with the HRF. The intervals
       used for the convolution are the smallest 'start' minus this
       padding to the largest 'end' plus this padding.
    convolution_dt : float, optional
       Time step for high-resolution time course for use in convolving the
       blocks with each HRF.
    hrf_interval: length 2 sequence of floats, optional
       Interval over which the HRF is assumed supported, used in the
       convolution.

    Returns
    -------
    X : np.ndarray
       The design matrix with ``X.shape[0] == t.shape[0]``. The number of
       columns will be ``len(hrfs)``.
    contrasts : dict
       A contrast is generated for each HRF specified in `hrfs`.
    """
    block_spec = np.asarray(block_spec)
    if block_spec.dtype.names is not None:
        if block_spec.dtype.names not in (('start', 'end'),
                                          ('start', 'end', 'amplitude')):
            raise ValueError('expecting fields called "start", "end" and '
                             '(optionally) "amplitude"')
        block_spec = np.array(block_spec.tolist())
    block_times = block_spec[:, :2]
    amplitudes = block_spec[:, 2] if block_spec.shape[1] == 3 else None
    # Now construct the design in time space
    convolution_interval = (block_times.min() - convolution_padding,
                            block_times.max() + convolution_padding)
    B = blocks(block_times, amplitudes=amplitudes)
    t_terms = []
    c_t = {}
    n_hrfs = len(hrfs)
    for hrf_no in range(n_hrfs):
        t_terms.append(convolve_functions(B, hrfs[hrf_no](T),
                                          convolution_interval,
                                          hrf_interval,
                                          convolution_dt))
        contrast = np.zeros(n_hrfs)
        contrast[hrf_no] = 1
        c_t['{0}_{1:d}'.format(name, hrf_no)] = contrast
    t_formula = Formula(t_terms)
    tval = make_recarray(t, ['t'])
    X_t = t_formula.design(tval, return_float=True)
    return X_t, c_t