This is an automated email from the git hooks/post-receive script. yoh pushed a commit to tag 0.4 in repository python-mne.
commit f6cd0f3a5cb412bc4afe67dabf3c38c59197951f Author: Martin Luessi <[email protected]> Date: Fri Mar 2 15:02:29 2012 -0500 ENH: filtering and apply_function for Raw --- doc/source/whats_new.rst | 1 + mne/fiff/raw.py | 161 +++++++++++++++++++++++++++++++++++++++++++++ mne/fiff/tests/test_raw.py | 32 +++++++++ 3 files changed, 194 insertions(+) diff --git a/doc/source/whats_new.rst b/doc/source/whats_new.rst index 277c463..e52f39a 100644 --- a/doc/source/whats_new.rst +++ b/doc/source/whats_new.rst @@ -23,6 +23,7 @@ Changelog - Write BEM surfaces in Python by `Alex Gramfort`_. + - Filtering operations and apply_function interface for Raw object by `Martin Luessi`_. Version 0.2 ----------- diff --git a/mne/fiff/raw.py b/mne/fiff/raw.py index e835485..6b98063 100644 --- a/mne/fiff/raw.py +++ b/mne/fiff/raw.py @@ -6,6 +6,8 @@ from math import floor, ceil import copy +import types + import numpy as np from .constants import FIFF @@ -14,6 +16,9 @@ from .meas_info import read_meas_info, write_meas_info from .tree import dir_tree_find from .tag import read_tag +from ..filter import low_pass_filter, high_pass_filter, band_pass_filter +from ..parallel import parallel_func + class Raw(object): """Raw data @@ -224,6 +229,162 @@ class Raw(object): # set the data self._data[sel, start:stop] = value + def apply_function(self, fun, picks, n_jobs, verbose, *args, **kwargs): + """ Apply a function to a subset of channels. + + The function "fun" is applied to the channels defined in "picks". The + data of the Raw object is modified in-place. + + The Raw object has to be constructed using preload=True (or string). + + Parameters + ---------- + fun : function + A function to be applied to the channels. The first argument of + fun has to be a timeseries (numpy.ndarray). The function must + return an numpy.ndarray with the same size as the input. + + picks : list of int + Indices of channels to apply the function to. + + n_jobs: int + Number of jobs to run in parallel. + + verbose: int + Verbosity level. + + *args: + Additional positional arguments to pass to fun (first pos. argument + of fun is the timeseries of a channel). + + **kwargs: + Keyword arguments to pass to fun. + """ + + if not isinstance(fun, types.FunctionType): + raise ValueError('fun needs to be a function') + + if not self._preloaded: + raise RuntimeError('Raw data needs to be preloaded. Use ' + 'preload=True (or string) in the constructor.') + + # create parallel function + parallel, p_fun, _ = parallel_func(fun, n_jobs, verbose) + + # apply function to channels + data_picks = self._data[picks, :] + data_picks_new = np.array(parallel(p_fun(x, *args, **kwargs) + for x in data_picks)) + + if np.any(data_picks_new.shape != data_picks.shape): + raise ValueError('fun must return array with the same size as ' + 'input') + + self._data[picks, :] = data_picks_new + + def band_pass_filter(self, picks, Fp1, Fp2, filter_length=None, n_jobs=1, + verbose=5): + """Band-pass filter a subset of channels. + + Applies a zero-phase band-pass filter to the channels selected by + "picks". The data of the Raw object is modified in-place. + + The Raw object has to be constructed using preload=True (or string). + + Parameters + ---------- + picks : list of int + Indices of channels to filter. + + Fp1 : float + Low cut-off frequency in Hz. + + Fp2 : float + High cut-off frequency in Hz. + + filter_length : int (default: None) + Length of the filter to use. If None or "ntimes < filter_length", + (ntimes: number of timepoints in Raw object) the filter length + used is ntimes. Otherwise, overlap-add filtering with a + filter of the specified length is used (faster for long signals). + + n_jobs: int (default: 1) + Number of jobs to run in parallel. + + verbose: int (default: 5) + Verbosity level. + """ + Fs = float(self.info['sfreq']) + self.apply_function(band_pass_filter, picks, n_jobs, verbose, Fs, Fp1, + Fp2, filter_length=filter_length) + + def high_pass_filter(self, picks, Fp, filter_length=None, n_jobs=1, + verbose=5): + """High-pass filter a subset of channels. + + Applies a zero-phase high-pass filter to the channels selected by + "picks". The data of the Raw object is modified in-place. + + The Raw object has to be constructed using preload=True (or string). + + Parameters + ---------- + picks : list of int + Indices of channels to filter. + + Fp : float + Cut-off frequency in Hz. + + filter_length : int (default: None) + Length of the filter to use. If None or "ntimes < filter_length", + (ntimes: number of timepoints in Raw object) the filter length + used is ntimes. Otherwise, overlap-add filtering with a + filter of the specified length is used (faster for long signals). + + n_jobs: int (default: 1) + Number of jobs to run in parallel. + + verbose: int (default: 5) + Verbosity level. + """ + + Fs = float(self.info['sfreq']) + self.apply_function(high_pass_filter, picks, n_jobs, verbose, Fs, Fp, + filter_length=filter_length) + + def low_pass_filter(self, picks, Fp, filter_length=None, n_jobs=1, + verbose=5): + """Low-pass filter a subset of channels. + + Applies a zero-phase low-pass filter to the channels selected by + "picks". The data of the Raw object is modified in-place. + + The Raw object has to be constructed using preload=True (or string). + + Parameters + ---------- + picks : list of int + Indices of channels to filter. + + Fp : float + Cut-off frequency in Hz. + + filter_length : int (default: None) + Length of the filter to use. If None or "ntimes < filter_length", + (ntimes: number of timepoints in Raw object) the filter length + used is ntimes. Otherwise, overlap-add filtering with a + filter of the specified length is used (faster for long signals). + + n_jobs: int (default: 1) + Number of jobs to run in parallel. + + verbose: int (default: 5) + Verbosity level. + """ + Fs = float(self.info['sfreq']) + self.apply_function(low_pass_filter, picks, n_jobs, verbose, Fs, Fp, + filter_length=filter_length) + def save(self, fname, picks=None, tmin=0, tmax=None, buffer_size_sec=10, drop_small_buffer=False): """Save raw data to file diff --git a/mne/fiff/tests/test_raw.py b/mne/fiff/tests/test_raw.py index 35edb86..520e32b 100644 --- a/mne/fiff/tests/test_raw.py +++ b/mne/fiff/tests/test_raw.py @@ -1,4 +1,5 @@ import os.path as op +from copy import deepcopy import numpy as np from nose.tools import assert_true @@ -111,3 +112,34 @@ def test_preload_modify(): data_new, _ = raw_new[picks, :nsamp / 2] assert_array_almost_equal(data, data_new) + + +def test_filter(): + """ Test filtering and Raw.apply_function interface """ + + raw = Raw(fif_fname, preload=True) + picks_meg = pick_types(raw.info, meg=True) + picks = picks_meg[:4] + + raw_lp = deepcopy(raw) + raw_lp.low_pass_filter(picks, 4.0) + + raw_hp = deepcopy(raw) + raw_hp.high_pass_filter(picks, 8.0) + + raw_bp = deepcopy(raw) + raw_bp.band_pass_filter(picks, 4.0, 8.0) + + data, _ = raw[picks, :] + + lp_data, _ = raw_lp[picks, :] + hp_data, _ = raw_hp[picks, :] + bp_data, _ = raw_bp[picks, :] + + assert_array_almost_equal(data, lp_data + hp_data + bp_data) + + # make sure we didn't touch other channels + data, _ = raw[picks_meg[4:], :] + bp_data, _ = raw_bp[picks_meg[4:], :] + + assert_array_equal(data, bp_data) -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/python-mne.git _______________________________________________ debian-med-commit mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/debian-med-commit
