Source code for autoclean.functions.preprocessing.resampling

"""Resampling functions for EEG data.

This module provides standalone functions for changing the sampling frequency
of EEG data through resampling operations.
"""

from typing import Optional, Union

import mne


[docs] def resample_data( data: Union[mne.io.BaseRaw, mne.Epochs], sfreq: float, npad: str = "auto", window: str = "auto", n_jobs: int = 1, pad: str = "auto", verbose: Optional[bool] = None, ) -> Union[mne.io.BaseRaw, mne.Epochs]: """Resample EEG data to a new sampling frequency. This function changes the sampling frequency of continuous (Raw) or epoched EEG data using anti-aliasing filtering and interpolation. The function automatically applies appropriate anti-aliasing filters and handles edge effects to preserve data quality during resampling. The function automatically detects the input data type and preserves it, returning the same type (Raw or Epochs) with identical structure but modified sampling frequency and adjusted time points. Parameters ---------- data : mne.io.BaseRaw or mne.Epochs The EEG data to resample. Can be any MNE Raw object (e.g., RawFIF, RawEEGLAB, etc.) or Epochs object. sfreq : float The target sampling frequency in Hz. Must be positive and typically should follow the Nyquist criterion relative to the highest frequency content in the data. npad : str or int, default 'auto' Amount of padding to use. 'auto' uses a heuristic to determine optimal padding length. Can also be an integer specifying exact padding samples. window : str, default 'auto' Windowing function for resampling. 'auto' selects appropriate window based on resampling parameters. Other options include 'boxcar', 'triang', 'blackman', 'hamming', 'hann', 'bartlett', 'flattop', 'parzen', 'bohman'. n_jobs : int, default 1 Number of parallel jobs to run. Use -1 for all available cores. Parallel processing can speed up resampling for large datasets. pad : str, default 'auto' Padding mode. 'auto' selects appropriate padding. Other options include 'reflect_limited', 'zero', 'constant', 'edge', 'wrap'. verbose : bool or None, default None Control verbosity of output. If None, uses MNE default. Returns ------- resampled_data : mne.io.BaseRaw or mne.Epochs The resampled data object, same type as input. Contains identical structure and metadata but with modified sampling frequency and adjusted time axis. Raises ------ TypeError If data is not an MNE Raw or Epochs object. ValueError If target sampling frequency is not positive or is invalid. RuntimeError If resampling fails due to insufficient data or other processing errors. Notes ----- Resampling modifies the sampling frequency and time axis but preserves all metadata including channel information, events, and annotations. The resampling is applied in-place on a copy of the data to avoid modifying the original. When downsampling (reducing sampling frequency), anti-aliasing filtering is automatically applied to prevent aliasing artifacts. When upsampling (increasing sampling frequency), interpolation is used to estimate intermediate sample points. For continuous data (Raw), edge effects may occur at the beginning and end of the recording due to filtering operations. For epoched data, edge effects occur at epoch boundaries and may affect short epochs more severely. The function uses MNE's resampling implementation, which applies appropriate anti-aliasing filters and windowing to minimize artifacts. For very long recordings, consider processing in chunks to manage memory usage. Resampling can significantly affect subsequent processing steps: - Filtering parameters may need adjustment for new sampling frequency - Epoch length in samples will change proportionally - Event timing remains in seconds but sample indices will change Examples -------- Downsample to reduce file size and processing time: >>> from autoclean import resample_data >>> downsampled_raw = resample_data(raw, sfreq=250) # From 1000 Hz to 250 Hz Upsample for higher temporal resolution: >>> upsampled_epochs = resample_data(epochs, sfreq=500) # From 250 Hz to 500 Hz Resample with custom parameters for better quality: >>> resampled_data = resample_data( ... raw, ... sfreq=250, ... window='hamming', ... n_jobs=4 ... ) Check if resampling is needed before applying: >>> current_sfreq = raw.info['sfreq'] >>> if abs(current_sfreq - target_sfreq) > 0.01: ... resampled_raw = resample_data(raw, sfreq=target_sfreq) ... else: ... resampled_raw = raw.copy() # No resampling needed See Also -------- mne.io.Raw.resample : MNE's raw data resampling method mne.Epochs.resample : MNE's epochs resampling method """ # Input validation if not isinstance(data, (mne.io.BaseRaw, mne.Epochs)): raise TypeError( f"Data must be an MNE Raw or Epochs object, got {type(data).__name__}" ) if not isinstance(sfreq, (int, float)) or sfreq <= 0: raise ValueError(f"Target sampling frequency must be positive, got {sfreq}") # Check if resampling is actually needed current_sfreq = data.info["sfreq"] if abs(current_sfreq - sfreq) < 0.01: # Tolerance for floating point comparison # No resampling needed, return copy return data.copy() # Create a copy to avoid modifying the original resampled_data = data.copy() try: # Perform resampling using MNE's built-in method resampled_data.resample( sfreq=sfreq, npad=npad, window=window, n_jobs=n_jobs, pad=pad, verbose=verbose, ) return resampled_data except Exception as e: raise RuntimeError( f"Failed to resample data from {current_sfreq} Hz to {sfreq} Hz: {str(e)}" ) from e