Repository: mne-tools/mne-python

Issue:
compute_raw_covariance vs compute_covariance
Looking at `compute_raw_covariance`, it is not as good as `compute_covariance` because it can't make use of the advanced regularization methods. Looking at the code, it seems like we could have `compute_raw_covariance` create an `Epochs` instance under the hood using `make_fixed_length_events` and then call `compute_covariance`. @dengemann I think we discussed doing this before, is there some reason we decided not to do it that way?



Discussion:
>  @dengemann I think we discussed doing this before, is there some reason we decided not to do it that way?

Cost-benefit analysis suggests that we won't win so much here, as regularization is less important for estimates from raw data. On the other hand in our PRNI paper we showed how our improved scaling defaults implement a second security layer by regularising via rank-estimation on the SVD.

Is there a function to split up a raw object into a series of evenly spaced, consecutive, possibly overlapping epochs? Because if no, and if you decide on implementing such functionality in the context of this, it would be good to make such a function.

> Is there a function to split up a raw object into a series of evenly spaced, consecutive, possibly overlapping epochs?

You are looking for `mne.event.make_fixed_length_events`

FYI we already had a darft for calling the cov epochs function under the hood, it was computationally not really tractable. 

I actually took a stab at implementing it, there is only one small detail that differs. For `raw`, the last window gets included even if it's too short. This seems more like a bug than a feature since not all the window lengths are the same. Do we really need to have it in there? I guess it makes the result identical to what the C code gives, but I'm not sure it's worth it.

> Cost-benefit analysis suggests that we won't win so much here, as regularization is less important for estimates from raw data.

That is true assuming you have a lot of raw data to use to compute the epochs, right? Seems like this would only be true for certain combinations of raw durations and `step` arguments. In other words, if you wanted to use long windows like ~10 seconds and ~5 minute file, you might actually want regularization. Or if you only had a minute of data and wanted to use 1 second windows, etc.

The code is also quite a bit simpler with the changes to using `make_fixed_length_events` and `Epochs`.


Resolving patch:
diff --git a/mne/cov.py b/mne/cov.py
--- a/mne/cov.py
+++ b/mne/cov.py
@@ -5,11 +5,10 @@
 # License: BSD (3-clause)
 
 import copy as cp
-import os
-from math import floor, ceil, log
-import itertools as itt
-from copy import deepcopy
 from distutils.version import LooseVersion
+import itertools as itt
+from math import log
+import os
 
 import numpy as np
 from scipy import linalg
@@ -18,8 +17,8 @@
 from .io.proj import (make_projector, _proj_equal, activate_proj,
                       _needs_eeg_average_ref_proj)
 from .io import fiff_open
-from .io.pick import (pick_types, channel_indices_by_type, pick_channels_cov,
-                      pick_channels, pick_info, _picks_by_type)
+from .io.pick import (pick_types, pick_channels_cov, pick_channels, pick_info,
+                      _picks_by_type)
 
 from .io.constants import FIFF
 from .io.meas_info import read_bad_channels
@@ -29,7 +28,8 @@
 from .io.write import (start_block, end_block, write_int, write_name_list,
                        write_double, write_float_matrix, write_string)
 from .defaults import _handle_default
-from .epochs import _is_good
+from .epochs import Epochs
+from .event import make_fixed_length_events
 from .utils import (check_fname, logger, verbose, estimate_rank,
                     _compute_row_norms, check_version, _time_mask, warn)
 
@@ -159,7 +159,7 @@ def copy(self):
         cov : instance of Covariance
             The copied object.
         """
-        return deepcopy(self)
+        return cp.deepcopy(self)
 
     def as_diag(self, copy=True):
         """Set covariance to be processed as being diagonal.
@@ -345,28 +345,45 @@ def _check_n_samples(n_samples, n_chan):
 
 
 @verbose
-def compute_raw_covariance(raw, tmin=None, tmax=None, tstep=0.2,
-                           reject=None, flat=None, picks=None,
-                           verbose=None):
+def compute_raw_covariance(raw, tmin=0, tmax=None, tstep=0.2, reject=None,
+                           flat=None, picks=None, method='empirical',
+                           method_params=None, cv=3, scalings=None, n_jobs=1,
+                           return_estimators=False, verbose=None):
     """Estimate noise covariance matrix from a continuous segment of raw data.
 
-    It is typically useful to estimate a noise covariance
-    from empty room data or time intervals before starting
-    the stimulation.
+    It is typically useful to estimate a noise covariance from empty room
+    data or time intervals before starting the stimulation.
 
-    Note: To speed up the computation you should consider preloading raw data
-    by setting preload=True when reading the Raw data.
+    .. note:: This function will:
+
+                  1. Partition the data into evenly spaced, equal-length
+                     epochs.
+                  2. Load them into memory.
+                  3. Subtract the mean across all time points and epochs
+                     for each channel.
+                  4. Process the :class:`Epochs` by
+                     :func:`compute_covariance`.
+
+              This will produce a slightly different result compared to
+              using :func:`make_fixed_length_events`, :class:`Epochs`, and
+              :func:`compute_covariance` directly, since that would (with
+              the recommended baseline correction) subtract the mean across
+              time *for each epoch* (instead of across epochs) for each
+              channel.
 
     Parameters
     ----------
     raw : instance of Raw
         Raw data
-    tmin : float | None (default None)
+    tmin : float
         Beginning of time interval in seconds
     tmax : float | None (default None)
         End of time interval in seconds
     tstep : float (default 0.2)
         Length of data chunks for artefact rejection in seconds.
+        Can also be None to use a single epoch of (tmax - tmin)
+        duration. This can use a lot of memory for large ``Raw``
+        instances.
     reject : dict | None (default None)
         Rejection parameters based on peak-to-peak amplitude.
         Valid keys are 'grad' | 'mag' | 'eeg' | 'eog' | 'ecg'.
@@ -386,66 +403,82 @@ def compute_raw_covariance(raw, tmin=None, tmax=None, tstep=0.2,
     picks : array-like of int | None (default None)
         Indices of channels to include (if None, all channels
         except bad channels are used).
+    method : str | list | None (default 'empirical')
+        The method used for covariance estimation.
+        See :func:`mne.compute_covariance`.
+
+        .. versionadded:: 0.12
+
+    method_params : dict | None (default None)
+        Additional parameters to the estimation procedure.
+        See :func:`mne.compute_covariance`.
+
+        .. versionadded:: 0.12
+
+    cv : int | sklearn cross_validation object (default 3)
+        The cross validation method. Defaults to 3, which will
+        internally trigger a default 3-fold shuffle split.
+
+        .. versionadded:: 0.12
+
+    scalings : dict | None (default None)
+        Defaults to ``dict(mag=1e15, grad=1e13, eeg=1e6)``.
+        These defaults will scale magnetometers and gradiometers
+        at the same unit.
+
+        .. versionadded:: 0.12
+
+    n_jobs : int (default 1)
+        Number of jobs to run in parallel.
+
+        .. versionadded:: 0.12
+
+    return_estimators : bool (default False)
+        Whether to return all estimators or the best. Only considered if
+        method equals 'auto' or is a list of str. Defaults to False
+
+        .. versionadded:: 0.12
+
     verbose : bool | str | int | None (default None)
         If not None, override default verbose level (see mne.verbose).
 
     Returns
     -------
-    cov : instance of Covariance
-        Noise covariance matrix.
+    cov : instance of Covariance | list
+        The computed covariance. If method equals 'auto' or is a list of str
+        and return_estimators equals True, a list of covariance estimators is
+        returned (sorted by log-likelihood, from high to low, i.e. from best
+        to worst).
 
     See Also
     --------
     compute_covariance : Estimate noise covariance matrix from epochs
     """
-    sfreq = raw.info['sfreq']
-
-    # Convert to samples
-    start = 0 if tmin is None else int(floor(tmin * sfreq))
-    if tmax is None:
-        stop = int(raw.last_samp - raw.first_samp)
-    else:
-        stop = int(ceil(tmax * sfreq))
-    step = int(ceil(tstep * raw.info['sfreq']))
+    tmin = 0. if tmin is None else float(tmin)
+    tmax = raw.times[-1] if tmax is None else float(tmax)
+    tstep = tmax - tmin if tstep is None else float(tstep)
+    tstep_m1 = tstep - 1. / raw.info['sfreq']  # inclusive!
+    events = make_fixed_length_events(raw, 1, tmin, tmax, tstep)
+    pl = 's' if len(events) != 1 else ''
+    logger.info('Using up to %s segment%s' % (len(events), pl))
 
     # don't exclude any bad channels, inverses expect all channels present
     if picks is None:
         picks = pick_types(raw.info, meg=True, eeg=True, eog=False,
                            ref_meg=False, exclude=[])
-
-    data = 0
-    n_samples = 0
-    mu = 0
-
-    info = pick_info(raw.info, picks)
-    idx_by_type = channel_indices_by_type(info)
-
-    # Read data in chunks
-    for first in range(start, stop, step):
-        last = first + step
-        if last >= stop:
-            last = stop
-        raw_segment, times = raw[picks, first:last]
-        if _is_good(raw_segment, info['ch_names'], idx_by_type, reject, flat,
-                    ignore_chs=info['bads']):
-            mu += raw_segment.sum(axis=1)
-            data += np.dot(raw_segment, raw_segment.T)
-            n_samples += raw_segment.shape[1]
-        else:
-            logger.info("Artefact detected in [%d, %d]" % (first, last))
-
-    _check_n_samples(n_samples, len(picks))
-    mu /= n_samples
-    data -= n_samples * mu[:, None] * mu[None, :]
-    data /= (n_samples - 1.0)
-    logger.info("Number of samples used : %d" % n_samples)
-    logger.info('[done]')
-
-    ch_names = [raw.info['ch_names'][k] for k in picks]
-    bads = [b for b in raw.info['bads'] if b in ch_names]
-    projs = cp.deepcopy(raw.info['projs'])
-    # XXX : do not compute eig and eigvec now (think it's better...)
-    return Covariance(data, ch_names, bads, projs, nfree=n_samples)
+    epochs = Epochs(raw, events, 1, 0, tstep_m1, baseline=None,
+                    picks=picks, reject=reject, flat=flat, verbose=False,
+                    preload=True, proj=False)
+    # This makes it equivalent to what we used to do, treating all epochs
+    # as if they were a single long one...
+    ch_means = epochs._data.mean(axis=0).mean(axis=1)
+    epochs._data -= ch_means[np.newaxis, :, np.newaxis]
+    # fake this value so there are no complaints from compute_covariance...
+    epochs.baseline = (None, None)
+    return compute_covariance(epochs, keep_sample_mean=True, method=method,
+                              method_params=method_params, cv=cv,
+                              scalings=scalings, n_jobs=n_jobs,
+                              return_estimators=return_estimators)
 
 
 @verbose
@@ -459,32 +492,34 @@ def compute_covariance(epochs, keep_sample_mean=True, tmin=None, tmax=None,
     when the stim onset is defined from events.
 
     If the covariance is computed for multiple event types (events
-    with different IDs), the following two options can be used and combined.
-    A) either an Epochs object for each event type is created and
-    a list of Epochs is passed to this function.
-    B) an Epochs object is created for multiple events and passed
-    to this function.
-
-    Note: Baseline correction should be used when creating the Epochs.
-          Otherwise the computed covariance matrix will be inaccurate.
-
-    Note: For multiple event types, it is also possible to create a
-          single Epochs object with events obtained using
-          merge_events(). However, the resulting covariance matrix
-          will only be correct if keep_sample_mean is True.
-
-    Note: The covariance can be unstable if the number of samples is not
-          sufficient. In that case it is common to regularize a covariance
-          estimate. The ``method`` parameter of this function allows to
-          regularize the covariance in an automated way. It also allows
-          to select between different alternative estimation algorithms which
-          themselves achieve regularization. Details are described in [1].
+    with different IDs), the following two options can be used and combined:
+
+        1. either an Epochs object for each event type is created and
+           a list of Epochs is passed to this function.
+        2. an Epochs object is created for multiple events and passed
+           to this function.
+
+    .. note:: Baseline correction should be used when creating the Epochs.
+              Otherwise the computed covariance matrix will be inaccurate.
+
+    .. note:: For multiple event types, it is also possible to create a
+              single Epochs object with events obtained using
+              merge_events(). However, the resulting covariance matrix
+              will only be correct if keep_sample_mean is True.
+
+    .. note:: The covariance can be unstable if the number of samples is
+              not sufficient. In that case it is common to regularize a
+              covariance estimate. The ``method`` parameter of this
+              function allows to regularize the covariance in an
+              automated way. It also allows to select between different
+              alternative estimation algorithms which themselves achieve
+              regularization. Details are described in [1]_.
 
     Parameters
     ----------
     epochs : instance of Epochs, or a list of Epochs objects
         The epochs.
-    keep_sample_mean : bool (default true)
+    keep_sample_mean : bool (default True)
         If False, the average response over epochs is computed for
         each event type and subtracted during the covariance
         computation. This is useful if the evoked response from a
@@ -504,22 +539,30 @@ def compute_covariance(epochs, keep_sample_mean=True, tmin=None, tmax=None,
         set of the different methods.
         If 'auto' or a list of methods, the best estimator will be determined
         based on log-likelihood and cross-validation on unseen data as
-        described in ref. [1]. Valid methods are:
-        'empirical', the empirical or sample covariance,
-        'diagonal_fixed', a diagonal regularization as in mne.cov.regularize
-        (see MNE manual), 'ledoit_wolf', the Ledoit-Wolf estimator (see [2]),
-        'shrunk' like 'ledoit_wolf' with cross-validation for optimal alpha
-        (see scikit-learn documentation on covariance estimation), 'pca',
-        probabilistic PCA with low rank
-        (see [3]), and, 'factor_analysis', Factor Analysis with low rank
-        (see [4]). If 'auto', expands to::
+        described in [1]_. Valid methods are:
+
+            * ``'empirical'``: the empirical or sample covariance
+            * ``'diagonal_fixed'``: a diagonal regularization as in
+              mne.cov.regularize (see MNE manual)
+            * ``'ledoit_wolf'``: the Ledoit-Wolf estimator [2]_
+            * ``'shrunk'``: like 'ledoit_wolf' with cross-validation for
+              optimal alpha (see scikit-learn documentation on covariance
+              estimation)
+            * ``'pca'``: probabilistic PCA with low rank [3]_
+            * ``'factor_analysis'``: Factor Analysis with low rank [4]_
+
+        If ``'auto'``, this expands to::
 
              ['shrunk', 'diagonal_fixed', 'empirical', 'factor_analysis']
 
-        Note. 'ledoit_wolf' and 'pca' are similar to 'shrunk' and
-        'factor_analysis', respectively. They are not included to avoid
-        redundancy. In most cases 'shrunk' and 'factor_analysis' represent
-        more appropriate default choices.
+        .. note:: ``'ledoit_wolf'`` and ``'pca'`` are similar to
+           ``'shrunk'`` and ``'factor_analysis'``, respectively. They are not
+           included to avoid redundancy. In most cases ``'shrunk'`` and
+           ``'factor_analysis'`` represent more appropriate default
+           choices.
+
+        The ``'auto'`` mode is not recommended if there are many
+        segments of data, since computation can take a long time.
 
         .. versionadded:: 0.9.0
 
@@ -567,17 +610,17 @@ def compute_covariance(epochs, keep_sample_mean=True, tmin=None, tmax=None,
 
     References
     ----------
-    [1] Engemann D. and Gramfort A. (2015) Automated model selection in
-        covariance estimation and spatial whitening of MEG and EEG signals,
-        vol. 108, 328-342, NeuroImage.
-    [2] Ledoit, O., Wolf, M., (2004). A well-conditioned estimator for
-        large-dimensional covariance matrices. Journal of Multivariate
-        Analysis 88 (2), 365 - 411.
-    [3] Tipping, M. E., Bishop, C. M., (1999). Probabilistic principal
-        component analysis. Journal of the Royal Statistical Society: Series
-        B (Statistical Methodology) 61 (3), 611 - 622.
-    [4] Barber, D., (2012). Bayesian reasoning and machine learning.
-        Cambridge University Press., Algorithm 21.1
+    .. [1] Engemann D. and Gramfort A. (2015) Automated model selection in
+           covariance estimation and spatial whitening of MEG and EEG
+           signals, vol. 108, 328-342, NeuroImage.
+    .. [2] Ledoit, O., Wolf, M., (2004). A well-conditioned estimator for
+           large-dimensional covariance matrices. Journal of Multivariate
+           Analysis 88 (2), 365 - 411.
+    .. [3] Tipping, M. E., Bishop, C. M., (1999). Probabilistic principal
+           component analysis. Journal of the Royal Statistical Society:
+           Series B (Statistical Methodology) 61 (3), 611 - 622.
+    .. [4] Barber, D., (2012). Bayesian reasoning and machine learning.
+           Cambridge University Press., Algorithm 21.1
     """
     accepted_methods = ('auto', 'empirical', 'diagonal_fixed', 'ledoit_wolf',
                         'shrunk', 'pca', 'factor_analysis',)
@@ -627,7 +670,8 @@ def _unpack_epochs(epochs):
 
     # check for baseline correction
     for epochs_t in epochs:
-        if epochs_t.baseline is None and epochs_t.info['highpass'] < 0.5:
+        if epochs_t.baseline is None and epochs_t.info['highpass'] < 0.5 and \
+                keep_sample_mean:
             warn('Epochs are not baseline corrected, covariance '
                  'matrix may be inaccurate')
 
@@ -680,7 +724,7 @@ def _unpack_epochs(epochs):
                                  ' if `keep_sample_mean` is False')
         # prepare mean covs
         n_epoch_types = len(epochs)
-        data_mean = list(np.zeros(n_epoch_types))
+        data_mean = [0] * n_epoch_types
         n_samples = np.zeros(n_epoch_types, dtype=np.int)
         n_epochs = np.zeros(n_epoch_types, dtype=np.int)
 
diff --git a/mne/event.py b/mne/event.py
--- a/mne/event.py
+++ b/mne/event.py
@@ -720,7 +720,8 @@ def make_fixed_length_events(raw, id, start=0, stop=None, duration=1.):
         raise ValueError('id must be an integer')
     # Make sure we don't go out the end of the file:
     stop -= int(np.ceil(raw.info['sfreq'] * duration))
-    ts = np.arange(start, stop, raw.info['sfreq'] * duration).astype(int)
+    # This should be inclusive due to how we generally use start and stop...
+    ts = np.arange(start, stop + 1, raw.info['sfreq'] * duration).astype(int)
     n_events = len(ts)
     events = np.c_[ts, np.zeros(n_events, dtype=int),
                    id * np.ones(n_events, dtype=int)]


Test patch:
diff --git a/mne/tests/common.py b/mne/tests/common.py
--- a/mne/tests/common.py
+++ b/mne/tests/common.py
@@ -5,6 +5,8 @@
 import numpy as np
 from numpy.testing import assert_allclose, assert_equal, assert_array_equal
 
+from scipy import linalg
+
 from .. import pick_types, Evoked
 from ..io import _BaseRaw
 from ..io.constants import FIFF
@@ -70,6 +72,14 @@ def assert_meg_snr(actual, desired, min_tol, med_tol=500., chpi_med_tol=500.,
         _check_snr(actual, desired, chpis, 0., chpi_med_tol, msg, kind='cHPI')
 
 
+def assert_snr(actual, desired, tol):
+    """Assert actual and desired arrays are within some SNR tolerance"""
+    from nose.tools import assert_true
+    snr = (linalg.norm(desired, ord='fro') /
+           linalg.norm(desired - actual, ord='fro'))
+    assert_true(snr >= tol, msg='%f < %f' % (snr, tol))
+
+
 def _dig_sort_key(dig):
     """Helper for sorting"""
     return 10000 * dig['kind'] + dig['ident']
diff --git a/mne/tests/test_cov.py b/mne/tests/test_cov.py
--- a/mne/tests/test_cov.py
+++ b/mne/tests/test_cov.py
@@ -5,8 +5,9 @@
 
 import os.path as op
 
-from nose.tools import assert_true, assert_equal
-from numpy.testing import assert_array_almost_equal, assert_array_equal
+from nose.tools import assert_true
+from numpy.testing import (assert_array_almost_equal, assert_array_equal,
+                           assert_equal)
 from nose.tools import assert_raises
 import numpy as np
 from scipy import linalg
@@ -22,8 +23,8 @@
                  compute_covariance, read_evokeds, compute_proj_raw,
                  pick_channels_cov, pick_channels, pick_types, pick_info,
                  make_ad_hoc_cov)
-from mne.io import Raw
-from mne.tests.common import assert_naming
+from mne.io import Raw, RawArray
+from mne.tests.common import assert_naming, assert_snr
 from mne.utils import (_TempDir, slow_test, requires_sklearn_0_15,
                        run_tests_if_main)
 from mne.io.proc_history import _get_sss_rank
@@ -54,8 +55,7 @@ def test_ad_hoc_cov():
 
 
 def test_io_cov():
-    """Test IO for noise covariance matrices
-    """
+    """Test IO for noise covariance matrices"""
     tempdir = _TempDir()
     cov = read_cov(cov_fname)
     cov['method'] = 'empirical'
@@ -94,16 +94,20 @@ def test_io_cov():
     assert_naming(w, 'test_cov.py', 2)
 
 
-def test_cov_estimation_on_raw_segment():
-    """Test estimation from raw on continuous recordings (typically empty room)
-    """
+def test_cov_estimation_on_raw():
+    """Test estimation from raw (typically empty room)"""
     tempdir = _TempDir()
     raw = Raw(raw_fname, preload=False)
-    cov = compute_raw_covariance(raw)
     cov_mne = read_cov(erm_cov_fname)
-    assert_true(cov_mne.ch_names == cov.ch_names)
-    assert_true(linalg.norm(cov.data - cov_mne.data, ord='fro') /
-                linalg.norm(cov.data, ord='fro') < 1e-4)
+
+    cov = compute_raw_covariance(raw, tstep=None)
+    assert_equal(cov.ch_names, cov_mne.ch_names)
+    assert_equal(cov.nfree, cov_mne.nfree)
+    assert_snr(cov.data, cov_mne.data, 1e4)
+
+    cov = compute_raw_covariance(raw)  # tstep=0.2 (default)
+    assert_equal(cov.nfree, cov_mne.nfree - 119)  # cutoff some samples
+    assert_snr(cov.data, cov_mne.data, 1e2)
 
     # test IO when computation done in Python
     cov.save(op.join(tempdir, 'test-cov.fif'))  # test saving
@@ -114,22 +118,38 @@ def test_cov_estimation_on_raw_segment():
 
     # test with a subset of channels
     picks = pick_channels(raw.ch_names, include=raw.ch_names[:5])
-    cov = compute_raw_covariance(raw, picks=picks)
+    cov = compute_raw_covariance(raw, picks=picks, tstep=None)
     assert_true(cov_mne.ch_names[:5] == cov.ch_names)
-    assert_true(linalg.norm(cov.data - cov_mne.data[picks][:, picks],
-                ord='fro') / linalg.norm(cov.data, ord='fro') < 1e-4)
+    assert_snr(cov.data, cov_mne.data[picks][:, picks], 1e4)
+    cov = compute_raw_covariance(raw, picks=picks)
+    assert_snr(cov.data, cov_mne.data[picks][:, picks], 90)  # cutoff samps
     # make sure we get a warning with too short a segment
     raw_2 = raw.crop(0, 1)
     with warnings.catch_warnings(record=True) as w:
         warnings.simplefilter('always')
         cov = compute_raw_covariance(raw_2)
-    assert_true(len(w) == 1)
+    assert_true(any('Too few samples' in str(ww.message) for ww in w))
+
+
+@slow_test
+@requires_sklearn_0_15
+def test_cov_estimation_on_raw_reg():
+    """Test estimation from raw with regularization"""
+    raw = Raw(raw_fname, preload=True)
+    raw.info['sfreq'] /= 10.
+    raw = RawArray(raw._data[:, ::10].copy(), raw.info)  # decimate for speed
+    cov_mne = read_cov(erm_cov_fname)
+    with warnings.catch_warnings(record=True):  # too few samples
+        warnings.simplefilter('always')
+        # XXX don't use "shrunk" here, for some reason it makes Travis 2.7
+        # hang... "diagonal_fixed" is much faster. Use long epochs for speed.
+        cov = compute_raw_covariance(raw, tstep=5., method='diagonal_fixed')
+    assert_snr(cov.data, cov_mne.data, 5)
 
 
 @slow_test
 def test_cov_estimation_with_triggers():
-    """Test estimation from raw with triggers
-    """
+    """Test estimation from raw with triggers"""
     tempdir = _TempDir()
     raw = Raw(raw_fname, preload=False)
     events = find_events(raw, stim_channel='STI 014')
@@ -207,8 +227,7 @@ def test_cov_estimation_with_triggers():
 
 
 def test_arithmetic_cov():
-    """Test arithmetic with noise covariance matrices
-    """
+    """Test arithmetic with noise covariance matrices"""
     cov = read_cov(cov_fname)
     cov_sum = cov + cov
     assert_array_almost_equal(2 * cov.nfree, cov_sum.nfree)
@@ -222,8 +241,7 @@ def test_arithmetic_cov():
 
 
 def test_regularize_cov():
-    """Test cov regularization
-    """
+    """Test cov regularization"""
     raw = Raw(raw_fname, preload=False)
     raw.info['bads'].append(raw.ch_names[0])  # test with bad channels
     noise_cov = read_cov(cov_fname)
@@ -429,7 +447,8 @@ def get_data(n_samples, n_features, rank, sigma):
 def test_compute_covariance_auto_reg():
     """Test automated regularization"""
 
-    raw = Raw(raw_fname, preload=False)
+    raw = Raw(raw_fname, preload=True)
+    raw.resample(100)  # much faster estimation
     events = find_events(raw, stim_channel='STI 014')
     event_ids = [1, 2, 3, 4]
     reject = dict(mag=4e-12)
diff --git a/mne/tests/test_event.py b/mne/tests/test_event.py
--- a/mne/tests/test_event.py
+++ b/mne/tests/test_event.py
@@ -3,7 +3,8 @@
 
 from nose.tools import assert_true, assert_raises
 import numpy as np
-from numpy.testing import assert_array_almost_equal, assert_array_equal
+from numpy.testing import (assert_array_almost_equal, assert_array_equal,
+                           assert_equal)
 import warnings
 
 from mne import (read_events, write_events, make_fixed_length_events,
@@ -304,6 +305,10 @@ def test_make_fixed_length_events():
     raw = io.Raw(raw_fname)
     events = make_fixed_length_events(raw, id=1)
     assert_true(events.shape[1], 3)
+    tmin, tmax = raw.times[[0, -1]]
+    duration = tmax - tmin
+    events = make_fixed_length_events(raw, 1, tmin, tmax, duration)
+    assert_equal(events.shape[0], 1)
 
 
 def test_define_events():