From 08b6b5d749e2f2ba22eb37ab1a9dc93d01a9e8ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Pe=C3=B1aloza?= Date: Mon, 3 Feb 2025 10:46:24 -0500 Subject: [PATCH 1/2] Adding support for lowpass filter Adding lowpass filter class, useful for processing emg recordings. Copying the class from highpass filter and applying the require changes --- src/spikeinterface/preprocessing/filter.py | 38 +++++++++++++++++++--- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/src/spikeinterface/preprocessing/filter.py b/src/spikeinterface/preprocessing/filter.py index a67d163d3d..1b543a07b8 100644 --- a/src/spikeinterface/preprocessing/filter.py +++ b/src/spikeinterface/preprocessing/filter.py @@ -40,7 +40,7 @@ class FilterRecording(BasePreprocessor): band : float or list, default: [300.0, 6000.0] If float, cutoff frequency in Hz for "highpass" filter type If list. band (low, high) in Hz for "bandpass" filter type - btype : "bandpass" | "highpass", default: "bandpass" + btype : "bandpass" | "highpass" | "lowpass", default: "bandpass" Type of the filter margin_ms : float, default: 5.0 Margin in ms on border to avoid border effect @@ -89,7 +89,7 @@ def __init__( assert filter_mode in ("sos", "ba"), "'filter' mode must be 'sos' or 'ba'" fs = recording.get_sampling_frequency() if coeff is None: - assert btype in ("bandpass", "highpass"), "'bytpe' must be 'bandpass' or 'highpass'" + assert btype in ("bandpass", "highpass", "lowpass"), "'bytpe' must be 'bandpass' , 'highpass' or 'lowpass'" # coefficient # self.coeff is 'sos' or 'ab' style filter_coeff = scipy.signal.iirfilter( @@ -271,6 +271,36 @@ def __init__(self, recording, freq_min=300.0, margin_ms=5.0, dtype=None, **filte self._kwargs.update(filter_kwargs) +class LowpassFilterRecording(FilterRecording): + """ + Lowpass filter of a recording + + Parameters + ---------- + recording : Recording + The recording extractor to be re-referenced + freq_max : float + The lowpass cutoff frequency in Hz + margin_ms : float + Margin in ms on border to avoid border effect + dtype : dtype or None + The dtype of the returned traces. If None, the dtype of the parent recording is used + {} + + Returns + ------- + filter_recording : LowpassFilterRecording + The lowpass-filtered recording extractor object + """ + + def __init__(self, recording, freq_max=300.0, margin_ms=5.0, dtype=None, **filter_kwargs): + FilterRecording.__init__( + self, recording, band=freq_max, margin_ms=margin_ms, dtype=dtype, btype="lowpass", **filter_kwargs + ) + dtype = fix_dtype(recording, dtype) + self._kwargs = dict(recording=recording, freq_max=freq_max, margin_ms=margin_ms, dtype=dtype.str) + self._kwargs.update(filter_kwargs) + class NotchFilterRecording(BasePreprocessor): """ Parameters @@ -326,7 +356,7 @@ def __init__(self, recording, freq=3000, q=30, margin_ms=5.0, dtype=None): bandpass_filter = define_function_from_class(source_class=BandpassFilterRecording, name="bandpass_filter") notch_filter = define_function_from_class(source_class=NotchFilterRecording, name="notch_filter") highpass_filter = define_function_from_class(source_class=HighpassFilterRecording, name="highpass_filter") - +lowpass_filter = define_function_from_class(source_class=LowpassFilterRecording, name="lowpass_filter") def causal_filter( recording, @@ -396,7 +426,7 @@ def causal_filter( bandpass_filter.__doc__ = bandpass_filter.__doc__.format(_common_filter_docs) highpass_filter.__doc__ = highpass_filter.__doc__.format(_common_filter_docs) - +lowpass_filter.__doc__ = lowpass_filter.__doc__.format(_common_filter_docs) def fix_dtype(recording, dtype): if dtype is None: From 62057581d6347d5fbbca56dcce2612dea116307f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 3 Feb 2025 15:49:53 +0000 Subject: [PATCH 2/2] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/spikeinterface/preprocessing/filter.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/spikeinterface/preprocessing/filter.py b/src/spikeinterface/preprocessing/filter.py index 1b543a07b8..2e57bc4968 100644 --- a/src/spikeinterface/preprocessing/filter.py +++ b/src/spikeinterface/preprocessing/filter.py @@ -301,6 +301,7 @@ def __init__(self, recording, freq_max=300.0, margin_ms=5.0, dtype=None, **filte self._kwargs = dict(recording=recording, freq_max=freq_max, margin_ms=margin_ms, dtype=dtype.str) self._kwargs.update(filter_kwargs) + class NotchFilterRecording(BasePreprocessor): """ Parameters @@ -358,6 +359,7 @@ def __init__(self, recording, freq=3000, q=30, margin_ms=5.0, dtype=None): highpass_filter = define_function_from_class(source_class=HighpassFilterRecording, name="highpass_filter") lowpass_filter = define_function_from_class(source_class=LowpassFilterRecording, name="lowpass_filter") + def causal_filter( recording, direction="forward", @@ -428,6 +430,7 @@ def causal_filter( highpass_filter.__doc__ = highpass_filter.__doc__.format(_common_filter_docs) lowpass_filter.__doc__ = lowpass_filter.__doc__.format(_common_filter_docs) + def fix_dtype(recording, dtype): if dtype is None: dtype = recording.get_dtype()