skills/neurokit2/references/bio_module.md
bio_processChecked 2026-07-23 against NeuroKit2 0.2.13 stable source/runtime and the official Bio API/examples.
bio_process() does—and does not doStable signature:
bio_process(
ecg=None, rsp=None, eda=None, emg=None,
ppg=None, eog=None, keep=None, sampling_rate=1000
)
It dispatches each non-None vector to the modality's *_process() function,
concatenates outputs by pandas index, adds keep, and computes continuous RSA when ECG
and RSP are both present.
It does not:
sampling_rate;Passing ECG at 1000 Hz and EDA at 100 Hz with sampling_rate=1000 falsely tells the
EDA processor that its samples are 1000 Hz. Unequal lengths are outer-concatenated by
index and can introduce NaN. Align first.
bio_signals, bio_info = nk.bio_process(
ecg=ecg_aligned,
rsp=rsp_aligned,
eda=eda_aligned,
sampling_rate=100,
)
bio_signals is one wide DataFrame. With pinned synthetic ECG+RSP+EDA, it contained
43 columns:
RSA_P2T, RSA_Gates.bio_info is one flat dict built with repeated dict.update(). The pinned run
contained prefixed ECG/RSP/SCR keys, method metadata, and one sampling_rate; it did
not support:
bio_info["ECG"]["ECG_R_Peaks"] # wrong for stable 0.2.13
Use:
rpeaks = bio_info["ECG_R_Peaks"]
rsp_troughs = bio_info["RSP_Troughs"]
Output columns depend on provided modalities, methods, optional dependencies, and
release. Save list(bio_signals.columns) and sorted(bio_info).
For each stream record:
Do not align only by truncating arrays to equal length.
Prefer:
Cross-correlation can support QC when signals share physiology, but a correlation peak can be ambiguous and physiologically lagged. It is not a replacement for a clock.
Apply modality-specific cleaning, peak detection, decomposition, and quality at the correct native rate. Preserve native event/peak timestamps.
Choose the target rate from the fastest retained continuous feature and analysis—not convenience. Anti-alias downsampling; report interpolation/filter method and edge validity. Map discrete peaks/triggers by time, using an explicit rounding/tolerance policy; never spline binary markers.
bio_process()The bundled validator accepts a strict JSON manifest:
{
"schema_version": "1.0",
"streams": [
{
"name": "ECG",
"path": "ecg.csv",
"value_column": "ECG",
"time_column": "time_s",
"sampling_rate_hz": 250,
"unit": "mV"
},
{
"name": "RSP",
"path": "rsp.csv",
"value_column": "RSP",
"time_column": "time_s",
"sampling_rate_hz": 50,
"unit": "a.u."
}
],
"alignment": {
"reference_stream": "ECG",
"synchronization": "shared_clock",
"max_start_offset_ms": 2,
"minimum_overlap_s": 60
}
}
python skills/neurokit2/scripts/validate_multimodal.py \
--manifest streams.json --root . --deidentified
The validator reports units, rates, timestamp order/jitter, missingness, starts, common
overlap, and whether streams can be passed directly to bio_process(). It does not
resample or modify data.
keepkeep must be a pandas Series or DataFrame and is concatenated after processed
modalities. It is useful for a pre-aligned trigger or covariate:
bio_signals, bio_info = nk.bio_process(
ecg=ecg,
rsp=rsp,
keep=aligned[["Trigger"]],
sampling_rate=100,
)
Verify equal index/length first. Do not use keep for participant identifiers or PHI.
The high-level Bio wrapper calls eog_process() without exposing an EOG method.
Stable EOG peak detection defaults to MNE, which is optional. A core-only environment
can therefore fail when eog is supplied. Process EOG explicitly with a chosen method
and merge after alignment, or add MNE at a reviewed exact version to the project lock.
When both ECG and RSP are present, stable bio_process() adds continuous:
RSA_P2T, RSA_Gates
This assumes the arrays already represent synchronized samples at the supplied rate. It does not check respiration polarity, sensor lag, clock drift, or R-peak validity. For summary RSA:
rsa = nk.hrv_rsa(
bio_signals,
bio_signals,
rpeaks=bio_info,
sampling_rate=100,
continuous=False,
)
Report the RSA method/output family, respiration behavior, usable cycles/windows, and
alignment uncertainty. See hrv.md.
bio_analyze()bio_analyze(
data, sampling_rate=1000, method="auto",
window_lengths="constant"
)
It detects available column prefixes and joins modality-specific analysis. With
interval-related data it can add summary RSA. method="auto" uses event-related mode
when mean duration is under 10 seconds; use explicit event-related or
interval-related for a prespecified design.
window_lengths can assign different epoch subwindows by modality. Prespecify them;
choosing each window after seeing effects multiplies researcher degrees of freedom.
There is no generic “multimodal arousal,” coherence, or cardiorespiratory-coupling score automatically produced by this wrapper. Any custom cross-modal statistic needs its own synchronization, lag, stationarity, null model, and multiplicity analysis.
Multimodal convergence does not prove a latent state, diagnosis, or causal mechanism.
Use bio_* for research/education only—not patient, worker, driver, athlete, or device
monitoring and not medical-device validation.