Skip to content

Improvement in mne.Epochs sampling  #6932

@christian-oreilly

Description

@christian-oreilly

Describe the problem

The function mne.Epochs(raw, events, event_id, tmin=0.0, tmax=1.0) with a sampling rate at 500 Hz loads epochs with 501 points, which actually covers the time window [0.0, 1.002] (i.e. 501 x 1/500 = 1.002). I would expect mne.Epochs to take 500 time points to cover [0.0, 1.0]. Arguably, the time point at 1.0 is a limit case because it is the time where a new sample is taken, but even more buggy, in my opinion, is that tmax=0.999 still gives 501 time samples. We get 500 times points with tmax=0.9989.

I see two defendable positions on this topic:
1 - A sample time is taken to be the value of a signal at the middle of a sampling period (I think it is more theoretically sound)
2 - A sample time is taken to be the beginning of a sampling period (I think it is more practical and that it is what is generally implicitly considered)

A figure can clarify the issue. Consider:

time_sampling

In this figure, a) and b) illustrate the positions 1 and 2, respectively. The returned epoch is shown in yellow. Panels a) and b) correspond to the current behavior of MNE. Panel c) show the behavior of EEGLAB. If MNE takes the position to be inclusive on tmax, the returned epoch in a) and b) are consistent regardless on whether you take position 1 (panel a) or 2 (panel b). EEGLAB would be said to be non-inclusive on tmax.

Now, consider what happens for tmax=0.999. Positions 1 and 2 applied to MNE behavior are shown in panels d) and e). The behavior of EEGLAB is shown in panel f). Again, for position 1 (panel d), considering tmax inclusive, we are at the limit case and, although a weird result to me, MNE behavior is coherent. If we were to take position 2 (panel e), then MNE behavior would be wrong. f) shows the behavior of EEGLAB.

So, based on that, it seems to me that the current behavior of MNE is only compatible with 1) sampling point at the middle of the sampling period and 2) an inclusive tmax.

Describe your solution

To allow compatibility with other libraries like EEGLAB, I propose adding "inclusive=True" to the signature of mne.Epochs.

  • With inclusive=True, the behavior would be as it currently is.
  • With inclusive=False, the behavior would be such that samples are included if and only if tmin <= t_sample < t_max. This behavior would be compatible with other libraries such as EEGLAB.

Describe possible alternatives

This proposed solution is to avoid non-backward-compatible changes. Note that, as mentioned before, this works only if we consider the sampling point as being in the middle of the sampling period. That means that conversion from samples to time is such that t_sample == (no_sample+0.5)/sampling_rate with no_sample being indexed from 0. Note however that this is not what is generally considered. Most people would rather do no_sample/sampling_rate... and that is what is currently done elsewhere in MNE like at line 258 of https://github.com/mne-tools/mne-python/blob/master/mne/io/base.py#L265-L1836 : index = (np.atleast_1d(times) - self.times[0]) * sfreq. If we rather want to consider that t_sample = no_sample/sampling_rate, then the behavior of MNE is plainly erroneous for the example given with tmax=0.999 (panel e) and the solution to correct that would require non-backward-compatible changes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions