Skill Tracer
Skills › Scientific Agent Skills › neurokit2 › signal_processing.md

signal_processing.md

164 lines · skills/neurokit2/references/signal_processing.md at 5f2bc03

Open on GitHub

Most marks come from matching words in the file, so treat them as pointers.

1# General signal processing
2
3Checked **2026-10-01** against NeuroKit2 0.2.13, its stable wheel, tagged
4source, and the live signal API page (`0.2.13.dev214`).
5

General signal processing

Checked 2026-10-01 against NeuroKit2 0.2.13, its stable wheel, tagged source, and the live signal API page (0.2.13.dev214).

Raw lines 1 to 5
6## Start with a signal contract
7
8For every channel retain:
9
10- sensor/channel identity and physical unit;
11- native sampling rate and timestamps;
12- polarity, gain, acquisition filters, and ADC range;
13- missing/discontinuous intervals and artifact annotations;
14- expected physiological bandwidth; and
15- the exact NeuroKit2 function, method, parameters, and package version.
17`signal_sanitize()` does **not** clean artifacts or interpolate missing values. In
180.2.13 it resets an indexed pandas Series to a default index.

Start with a signal contract

For every channel retain:

  • sensor/channel identity and physical unit;
  • native sampling rate and timestamps;
  • polarity, gain, acquisition filters, and ADC range;
  • missing/discontinuous intervals and artifact annotations;
  • expected physiological bandwidth; and
  • the exact NeuroKit2 function, method, parameters, and package version.

signal_sanitize() does not clean artifacts or interpolate missing values. In 0.2.13 it resets an indexed pandas Series to a default index.

Raw lines 6 to 19
20## Safe preprocessing order
221. Preserve the original samples and time axis.
232. Check timestamp order, rate, clipping, flatlines, non-finite values, and gaps.
243. Split at long gaps. Interpolate only short, prespecified gaps and retain a mask.
254. Remove offsets/trends only when justified.
265. Apply a modality/method-specific filter at the native rate.
276. Trim or flag filter transients.
287. Detect/correct peaks or derive features.
298. Resample continuous outputs only when alignment or modeling requires it.
31Do not use a filter to “fix” clipping, sensor detachment, dropped packets, or motion.
32Do not interpolate event markers, quality flags, or peak indicator vectors as
33continuous amplitudes.

Safe preprocessing order

  1. Preserve the original samples and time axis.
  2. Check timestamp order, rate, clipping, flatlines, non-finite values, and gaps.
  3. Split at long gaps. Interpolate only short, prespecified gaps and retain a mask.
  4. Remove offsets/trends only when justified.
  5. Apply a modality/method-specific filter at the native rate.
  6. Trim or flag filter transients.
  7. Detect/correct peaks or derive features.
  8. Resample continuous outputs only when alignment or modeling requires it.

Do not use a filter to “fix” clipping, sensor detachment, dropped packets, or motion. Do not interpolate event markers, quality flags, or peak indicator vectors as continuous amplitudes.

Raw lines 20 to 34
35## Verified 0.2.13 interfaces
37| Function | Stable behavior relevant to schemas |
38|---|---|
39| `signal_filter()` | Returns one array. Default is order-2 Butterworth; available behavior depends on `method`, cutoffs, and sampling rate. |
40| `signal_sanitize()` | Resets pandas Series indexing; it is not a NaN/artifact cleaner. |
41| `signal_fillmissing()` | Forward, backward, or both-direction fill only (`method="forward"`, `"backward"`, or `"both"`). |
42| `signal_resample()` | Returns one array; accepts target length or source/target rates. Methods include interpolation, FFT, polyphase, NumPy, and pandas paths. |
43| `signal_interpolate()` | Returns interpolated values; explicitly provide source and target coordinates for irregular time. |
44| `signal_findpeaks()` | Returns a dict. The pinned default synthetic probe observed `Peaks`, `Height`, `Distance`, `Onsets`, `Offsets`, and `Width`; keys can change with input/method. |
45| `signal_fixpeaks()` | Returns `(info, corrected_peaks)` in stable source. Default Kubios `info` includes artifact categories and diagnostics. |
46| `signal_period()` | Takes peak locations and returns period in seconds, optionally interpolated to a requested sample length. |
47| `signal_rate()` | Takes peak locations and returns events/minute, optionally interpolated. |
48| `signal_psd()` | Returns a DataFrame; the pinned Welch probe observed `Frequency` and `Power`. |
49| `signal_power()` | Returns a one-row DataFrame with band-derived names such as `Hz_0.5_2`; names depend on requested bands. |
50| `signal_timefrequency()` | Returns `(frequency, time, representation)`; frequency is the first object. |
51| `signal_synchrony()` | Returns an array; supported methods are Hilbert phase synchrony and rolling correlation. |
52| `signal_decompose()` | Returns a component array; stable methods are EMD and SSA, not a component dictionary. |
53| `signal_changepoints()` | Implements PELT and returns change-point sample indices. |
55Never unpack `signal_psd()` into `(psd, frequencies)` in 0.2.13:
57```python
58psd = nk.signal_psd(
59 signal,
60 sampling_rate=250,
61 method="welch",
62 normalize=False,
63 show=False,
65frequency_hz = psd["Frequency"]
66power = psd["Power"]
67```
69`normalize=True` scales by maximum PSD power. It is not physical calibration. Use
70`normalize=False` when absolute spectral units are required and derive those units from
71the acquisition and estimator.

Verified 0.2.13 interfaces

FunctionStable behavior relevant to schemas
signal_filter()Returns one array. Default is order-2 Butterworth; available behavior depends on method, cutoffs, and sampling rate.
signal_sanitize()Resets pandas Series indexing; it is not a NaN/artifact cleaner.
signal_fillmissing()Forward, backward, or both-direction fill only (method="forward", "backward", or "both").
signal_resample()Returns one array; accepts target length or source/target rates. Methods include interpolation, FFT, polyphase, NumPy, and pandas paths.
signal_interpolate()Returns interpolated values; explicitly provide source and target coordinates for irregular time.
signal_findpeaks()Returns a dict. The pinned default synthetic probe observed Peaks, Height, Distance, Onsets, Offsets, and Width; keys can change with input/method.
signal_fixpeaks()Returns (info, corrected_peaks) in stable source. Default Kubios info includes artifact categories and diagnostics.
signal_period()Takes peak locations and returns period in seconds, optionally interpolated to a requested sample length.
signal_rate()Takes peak locations and returns events/minute, optionally interpolated.
signal_psd()Returns a DataFrame; the pinned Welch probe observed Frequency and Power.
signal_power()Returns a one-row DataFrame with band-derived names such as Hz_0.5_2; names depend on requested bands.
signal_timefrequency()Returns (frequency, time, representation); frequency is the first object.
signal_synchrony()Returns an array; supported methods are Hilbert phase synchrony and rolling correlation.
signal_decompose()Returns a component array; stable methods are EMD and SSA, not a component dictionary.
signal_changepoints()Implements PELT and returns change-point sample indices.

Never unpack signal_psd() into (psd, frequencies) in 0.2.13:

psd = nk.signal_psd(
    signal,
    sampling_rate=250,
    method="welch",
    normalize=False,
    show=False,
)
frequency_hz = psd["Frequency"]
power = psd["Power"]

normalize=True scales by maximum PSD power. It is not physical calibration. Use normalize=False when absolute spectral units are required and derive those units from the acquisition and estimator.

Raw lines 35 to 72
73## Filtering and resampling
75Cutoffs are in Hz and must lie below Nyquist. Report:
77- filter family and implementation (`butterworth`, FIR, Savitzky–Golay, powerline);
78- order, low/high cutoff, notch frequency, and whether processing is zero phase;
79- padding/edge handling and samples discarded; and
80- source and target sampling rates plus resampling method.
82Example:
84```python
85filtered = nk.signal_filter(
86 signal,
87 sampling_rate=250,
88 lowcut=0.5,
89 highcut=40,
90 method="butterworth",
91 order=2,
93resampled = nk.signal_resample(
94 filtered,
95 sampling_rate=250,
96 desired_sampling_rate=100,
97 method="poly",
99```
101Downsampling requires anti-alias filtering. In 0.2.13 the default `interpolation`
102method uses spline interpolation (`scipy.ndimage.zoom`), not an anti-alias low-pass
103filter. Use a suitable explicit filter before decimation or a validated filtered
104resampler such as `poly`; check attenuation above the new Nyquist frequency.
105Resampling cannot recover timing precision or
106bandwidth absent from the acquisition. For multimodal data, preserve native processing
107and timestamps first; choose a common grid only after clock alignment.

Filtering and resampling

Cutoffs are in Hz and must lie below Nyquist. Report:

  • filter family and implementation (butterworth, FIR, Savitzky–Golay, powerline);
  • order, low/high cutoff, notch frequency, and whether processing is zero phase;
  • padding/edge handling and samples discarded; and
  • source and target sampling rates plus resampling method.

Example:

filtered = nk.signal_filter(
    signal,
    sampling_rate=250,
    lowcut=0.5,
    highcut=40,
    method="butterworth",
    order=2,
)
resampled = nk.signal_resample(
    filtered,
    sampling_rate=250,
    desired_sampling_rate=100,
    method="poly",
)

Downsampling requires anti-alias filtering. In 0.2.13 the default interpolation method uses spline interpolation (scipy.ndimage.zoom), not an anti-alias low-pass filter. Use a suitable explicit filter before decimation or a validated filtered resampler such as poly; check attenuation above the new Nyquist frequency. Resampling cannot recover timing precision or bandwidth absent from the acquisition. For multimodal data, preserve native processing and timestamps first; choose a common grid only after clock alignment.

Raw lines 73 to 108
109## Missing data
111Forward/backward fill can create artificial constant segments. Generic interpolation can
112create smooth but fictional morphology and peaks. Record:
114- count and maximum run of missing samples;
115- gap durations in seconds;
116- whether each gap was segmented, excluded, padded, or interpolated;
117- interpolation method and maximum allowed gap; and
118- whether downstream quality and uncertainty include the imputed mask.
120Most modality pipelines may warn and internally forward-fill some missing samples. That
121convenience is not a study-level missing-data policy.

Missing data

Forward/backward fill can create artificial constant segments. Generic interpolation can create smooth but fictional morphology and peaks. Record:

  • count and maximum run of missing samples;
  • gap durations in seconds;
  • whether each gap was segmented, excluded, padded, or interpolated;
  • interpolation method and maximum allowed gap; and
  • whether downstream quality and uncertainty include the imputed mask.

Most modality pipelines may warn and internally forward-fill some missing samples. That convenience is not a study-level missing-data policy.

Raw lines 109 to 122
123## Peak correction
125```python
126info, corrected = nk.signal_fixpeaks(
127 peaks,
128 sampling_rate=250,
129 method="Kubios",
130 iterative=True,
132```
134The Kubios/Lipponen–Tarvainen path is intended for ECG/PPG beats. `method="neurokit"`
135supports explicit interval limits and can be used more generically. Always retain raw
136and corrected peaks, counts by artifact category, affected time ranges, and results with
137and without correction. Do not call corrected beat intervals “normal-to-normal” unless
138the study actually identifies non-sinus/ectopic beats.

Peak correction

info, corrected = nk.signal_fixpeaks(
    peaks,
    sampling_rate=250,
    method="Kubios",
    iterative=True,
)

The Kubios/Lipponen–Tarvainen path is intended for ECG/PPG beats. method="neurokit" supports explicit interval limits and can be used more generically. Always retain raw and corrected peaks, counts by artifact category, affected time ranges, and results with and without correction. Do not call corrected beat intervals “normal-to-normal” unless the study actually identifies non-sinus/ectopic beats.

Raw lines 123 to 139
140## Quality and reproducibility
142Useful QC is multimodal and method-specific:
144- raw/clean overlays and filter-edge review;
145- missing, flatline, clipping, and saturation fractions;
146- peak/onset overlays and interval distributions;
147- quality values with their method-specific direction and scale;
148- sensitivity to plausible filter/detector settings; and
149- synthetic fixtures plus labeled empirical validation data.
151The bundled inspector is dependency-free:
153```bash
154python skills/neurokit2/scripts/inspect_signal.py \
155 --input signal.csv --root . --deidentified \
156 --columns ECG --time-column time_s --units ECG=mV
157```

Quality and reproducibility

Useful QC is multimodal and method-specific:

  • raw/clean overlays and filter-edge review;
  • missing, flatline, clipping, and saturation fractions;
  • peak/onset overlays and interval distributions;
  • quality values with their method-specific direction and scale;
  • sensitivity to plausible filter/detector settings; and
  • synthetic fixtures plus labeled empirical validation data.

The bundled inspector is dependency-free:

python skills/neurokit2/scripts/inspect_signal.py \
  --input signal.csv --root . --deidentified \
  --columns ECG --time-column time_s --units ECG=mV
Raw lines 140 to 158
Runs code python skills/neurokit2/scripts/inspect_signal.py :154
159## Sources checked 2026-10-01
161- [Official signal API](https://neuropsychology.github.io/NeuroKit/functions/signal.html)
162- [Stable v0.2.13 source tag](https://github.com/neuropsychology/NeuroKit/tree/v0.2.13/neurokit2/signal)
163- [NeuroKit2 main paper](https://doi.org/10.3758/s13428-020-01516-y)
164- [Lipponen & Tarvainen (2019), peak correction](https://doi.org/10.1080/03091902.2019.1640306)