1+ """Signal processing utilities for PyEyesWeb.
2+
3+ This module provides signal processing functions including filtering,
4+ phase extraction, and smoothing operations used throughout the library.
5+ """
6+
17import numpy as np
28from scipy .signal import hilbert , butter , filtfilt
39
410
511def bandpass_filter (data , filter_params ):
6- """Apply a band-pass filter if filter_params is set."""
12+ """Apply a band-pass filter if filter_params is set.
13+
14+ Uses a 4th order Butterworth band-pass filter with zero-phase
15+ filtering (filtfilt) to avoid phase distortion.
16+
17+ Parameters
18+ ----------
19+ data : ndarray
20+ Signal data of shape (n_samples, n_channels).
21+ filter_params : tuple of (float, float, float) or None
22+ Filter parameters as (lowcut_hz, highcut_hz, sampling_rate_hz).
23+ If None, returns data unchanged.
24+
25+ Returns
26+ -------
27+ ndarray
28+ Filtered data with same shape as input.
29+ Returns original data if filter_params is None.
30+
31+ Examples
32+ --------
33+ >>> data = np.random.randn(1000, 2) # 2 channels, 1000 samples
34+ >>> filtered = bandpass_filter(data, (1.0, 10.0, 100.0)) # 1-10 Hz
35+ """
736 if filter_params is None :
837 return data
938
@@ -22,7 +51,28 @@ def bandpass_filter(data, filter_params):
2251
2352
2453def compute_hilbert_phases (sig ):
25- """Compute phase information from signals using Hilbert Transform."""
54+ """Compute phase information from signals using Hilbert Transform.
55+
56+ The Hilbert transform creates an analytic signal from which instantaneous
57+ phase can be extracted. Assumes input has exactly 2 channels.
58+
59+ Parameters
60+ ----------
61+ sig : ndarray
62+ Signal array of shape (n_samples, 2) with two channels.
63+
64+ Returns
65+ -------
66+ phase1 : ndarray
67+ Phase values for first channel in radians [-π, π].
68+ phase2 : ndarray
69+ Phase values for second channel in radians [-π, π].
70+
71+ Notes
72+ -----
73+ The Hilbert transform assumes the signal is narrowband or has been
74+ appropriately filtered for meaningful phase extraction.
75+ """
2676 analytic_signal1 = hilbert (sig [:, 0 ])
2777 analytic_signal2 = hilbert (sig [:, 1 ])
2878
@@ -33,7 +83,31 @@ def compute_hilbert_phases(sig):
3383
3484
3585def apply_savgol_filter (signal , rate_hz = 50.0 ):
36- """Apply Savitzky-Golay filter if enough data is available."""
86+ """Apply Savitzky-Golay filter if enough data is available.
87+
88+ Savitzky-Golay filtering smooths data while preserving features better
89+ than moving average filters. Uses polynomial order 3 and adaptive
90+ window length.
91+
92+ Parameters
93+ ----------
94+ signal : array-like
95+ 1D signal to filter.
96+ rate_hz : float, optional
97+ Sampling rate in Hz (currently unused but kept for API compatibility).
98+
99+ Returns
100+ -------
101+ ndarray
102+ Filtered signal if sufficient data (≥5 samples), otherwise original
103+ signal as array. Window length is min(n_samples, 11) and must be odd.
104+
105+ Notes
106+ -----
107+ - Requires at least 5 samples for filtering
108+ - Window length must exceed polynomial order (3)
109+ - Returns original signal if filtering fails
110+ """
37111 if len (signal ) < 5 :
38112 return np .array (signal )
39113
0 commit comments