Causal Filters for Streaming BCI: What Changes When You Go from Batch to Real-Time

If you have ever built a BCI pipeline offline, validated it on a public dataset, and then watched accuracy collapse the moment you wired it to a live EEG stream, you have probably already run into the causal filter problem — even if you did not know it by that name.
The issue is deceptively simple: the preprocessing chain that makes your offline numbers look great relies on filters that peek into the future. Zero-phase filtering (filtfilt) reads both past and future samples to eliminate phase distortion. It produces beautiful, aligned signals — and is completely impossible to run in real time, because future samples do not exist yet.
This guide explains the distinction clearly, walks through every affected node in a Nimbus Studio streaming pipeline, and gives you a concrete recipe for a deploy-safe causal preprocessing chain.
What Causal and Acausal Actually Mean
A causal filter computes each output sample using only present and past inputs. An infinite impulse response (IIR) filter applied forward through a signal with lfilter is causal. It introduces group delay — a constant phase shift across frequencies — but it is physically realizable: it can run one sample at a time, forever, without buffering the future.
An acausal filter uses future samples. The canonical example is filtfilt, which applies an IIR filter forward and then backward through the signal. The double pass cancels the phase shift, producing zero-phase output. The catch: the backward pass cannot begin until the entire signal is available. It is a batch operation by definition.
In offline analysis, this distinction does not matter. In a deployed BCI, it matters enormously. A filtfilt call inside a streaming chunk loop will either raise an error or silently produce wrong output — it does not have enough context to run correctly on short windows.
The less obvious consequence is group delay calibration. Causal IIR filters introduce frequency-dependent delay, and the exact group delay depends on the filter design (order, cutoff frequencies, and implementation). In practice, it is common to measure it (e.g., with grpdelay) and treat it as part of the end-to-end latency budget — especially when stacking multiple filter stages under a ~100 ms total latency target (including streaming-safe artifact handling like ICA / EOG removal).
The Affected Nodes in Nimbus Studio

Not every preprocessing node has a causal variant — and the ones that do require explicit configuration. Here is where it matters most in a Nimbus Studio deploy pipeline.
highpass_filter and bandpass_filter — Both nodes support IIR Butterworth implementations that run causally with lfilter. In a streaming deploy graph, you must ensure the filter is initialized with its state carried across chunks. Nimbus Studio manages this automatically when the node runs on the deploy path, but it is worth confirming that filter order is kept low (2nd or 4th order is usually sufficient) to minimize group delay accumulation.
eog_removal — This is where many pipelines silently break. The batch/offline method uses regression against EOG proxies computed over the entire recording — acausal by construction. For deploy, the node exposes an LMS (Least Mean Squares) adaptive filter option, which removes eye-movement artifacts causally by adapting its weights on each incoming chunk. The tradeoff: LMS convergence takes a few seconds at the start of a session. Build that warm-up period into your calibration protocol.
ica (Independent Component Analysis) — ICA decomposition itself is a batch algorithm. In a streaming context, the standard approach is to compute the ICA mixing matrix during an offline calibration session, then apply the fixed unmixing matrix to incoming chunks. Nimbus Studio supports this: the ica node in a deploy graph applies a pre-fitted set of weights rather than re-fitting. Confirm the mixing matrix is saved from your training graph and loaded correctly in your deploy bundle.
normalization — Z-scoring is straightforward to run causally, but only if the mean and variance used come from the training session rather than the current stream. The normalization node in evaluation mode uses training statistics for exactly this reason. Never use a normalization node that re-computes statistics on the live stream — this creates both a causality violation and a leakage problem (one way neural drift shows up in practice: your live distribution stops matching what the decoder was trained on).
data_augmentation and zuna — Both nodes are marked batch only in Nimbus Studio and should be excluded from deploy DAGs entirely. The same applies to cross_validation: it is an evaluation-only node. Including any of these in a deploy template will either fail at launch or produce undefined behavior.
Managing Group Delay in Your Latency Budget

Every causal IIR filter you add to your pipeline contributes group delay. For most BCI paradigms, latency is not just a comfort metric — it directly affects decoding quality and user experience. Here is how to think about the budget:
- Highpass filter (4th order, 0.5 Hz cutoff, 256 Hz): ~8 ms
- Bandpass filter (4th order, 8–30 Hz, 256 Hz): ~8 ms
- EOG LMS (adaptive, 1st order): ~2–4 ms convergence-dependent
- Epoching (1 second window): the window itself is a latency source — you cannot emit a prediction until the epoch is complete
- CSP / model inference: typically < 5 ms for linear decoders
decision_policydebounce: adds intentional smoothing delay (tune to your task)
A 1-second epoch with a 500 ms step already dominates the budget at paradigms like motor imagery. Keeping filter order at 2–4 rather than 8 saves tens of milliseconds that matter when stacking multiple stages. Use the spectral_features node for a quick sanity check: log-bandpower features from a short FFT window can achieve much lower latency than epoch-based pipelines when real-time responsiveness is the priority.
For SSVEP pipelines using the cca node, latency is less critical because the paradigm is inherently rate-locked to the stimulus frequency. For motor imagery and P300, every millisecond of unnecessary filter delay degrades perceived responsiveness and ITR.
Building a Causal-Safe Pipeline in Nimbus Studio
The practical recipe for a deploy-compatible preprocessing chain:
- Start from a deploy-capable template. Nimbus Studio's deploy-capable templates are pre-configured with causal preprocessing. Use the Deploy-capable view in the pipeline nodes database to confirm every node in your graph has the Deploy flag set.
- Set filter mode explicitly. For
highpass_filterandbandpass_filter, verify that the implementation is IIR (not FIR withfiltfilt). Prefer 2nd or 4th order. - Switch EOG removal to LMS mode. In the
eog_removalnode settings, select the adaptive LMS method and configure the step size. A step size of 0.01–0.05 is a reasonable starting range; tune it in a dry run session. - Pre-fit ICA offline, load weights in deploy. Run your calibration session with the
icanode in build mode. Confirm theica_resultartifact is saved and loaded by the deploy graph. Do not placeicain the deploy DAG without a pre-fitted artifact. - Use
normalizationin eval mode. Connect thenormalizationnode after your spatial filter and before the classifier. Verify it is using training-session statistics, not live-stream statistics. - Remove batch-only nodes. Check for
data_augmentation,zuna,cross_validation, and any other batch-only nodes. Remove them from the deploy graph. These belong only in your training template. - Add
decision_policyfor streaming stability. Causal filters can introduce transient artifacts at the boundaries of streaming windows. Thedecision_policynode smooths these out with temporal aggregation. Configure the debounce window based on your paradigm's expected decision cadence.
Conclusion
The offline-to-deploy gap in BCI engineering is real, and filtering is usually where it hides. Zero-phase filters are the right tool for batch analysis: they produce clean, unbiased signals and make downstream decoding easier. But they are incompatible with real-time streaming by construction — and using them in a deploy pipeline produces errors that are hard to diagnose because the data looks fine in offline validation.
The causal alternatives — IIR forward filtering, LMS adaptive EOG removal, pre-fitted ICA unmixing — are not degraded versions of the offline methods. They are the correct algorithms for the streaming context. Understanding the group delay each stage contributes, keeping filter orders low, and using Nimbus Studio's deploy-flagged nodes from the start gives you a pipeline that works the same way in a calibration session as it does in a live BCI session six months later — with room to add more advanced layers like REVE foundation-model preprocessing and a confidence/uncertainty-aware decision policy.