NIRWizard

Keeps thereceipts.

An fNIRS analysis workbench — from a SNIRF file to a cortex map, with the provenance to show for it.

Adam Askeworkshop
part · ~5 min

Why NIRWizard

Five minutes on the problem before a single screen.

the problem

A recording is a .snirf — a good, open standard. Everything after it is not.

the problem

fNIRS analysis today is a patchwork

  • Preprocessing lives in one toolbox, the GLM in a second, the group statistics in a third — each a scripting language, each with its own opinion on the data layout.
  • The result is a folder of scripts and intermediate files whose provenance is a memory: which filter, which cutoff, which channels were dropped, on which version.
  • Six months later the reviewer asks. The answer is a ‘probably’.
The reproducibility gap is a tooling gap. The methods are published and well understood; what is missing is one place that runs them and keeps the receipts.
what it is

One window for the whole chain

One desktop application

Windows and Linux. No MATLAB licence, no notebook, no cluster.

SNIRF in, SNIRF out

A recording opens as it is; every derived block writes back to the same format, stamped.

Published methods

Cedalion and MNE as engines, SPM's HRF and drift basis, AR-IRLS, BH-FDR, random-effects group models — the literature, not a reinvention.

Every result is born with a record

Sources, parameters, exclusions, statistics — one provenance schema, every panel.

The whole chain

QC → preprocessing → GLM, block average, connectivity → group → cortex image → export. Plus the head: anatomy, forward and inverse model.

Before the analysis, too

Design the montage, run the experiment, then analyse — all in the same window.

the design

Three ideas the whole application is built on

1

Data blocks are first class

A pipeline never overwrites the recording; it writes a derived block beside it, with a lineage. Switch, compare, freeze, delete.

2

Every result carries its provenance

Sources read, parameters used, channels excluded, statistical posture taken — stamped at creation, exported beside the numbers.

3

A project restores the state

.nirw and .nwstudy hash the inputs and cache every result with its record. Reopen and the analysis is where you left it — refused by name if an input changed.

if you remember one thing

Nothing in NIRWizard happens without a record of it happening.

today

What we will do

1

The tour

One or two slides per workspace. Enough to know what exists and when to reach for it.

2

One workflow, end to end

A motor task, one participant: open, preprocess, block-average, fit a GLM, look at the cortex. The path you can repeat on your own data tomorrow.

the example recording · 2025-05-19_004.snirf
51
channels
2 wavelengths
5.09Hz
sampling rate
approximately
316s
duration
one block, three stim groups
3
conditions
Rest (10), Left hand (4), Right hand (4) — expect contralateral HbO ↑ HbR ↓
part · every workspace

The tour

Every workspace, one or two slides each. Skip freely.

the tour · map

The map

Workspaces, grouped the way the Pipeline panel groups them.

Session

Info · Channels · QC · Preprocessing · Plots

Analysis

GLM · Block average · Connectivity · Laterality · ROI

Imaging

Anatomy · Projection · Forward · Inverse · Image · Display

Group

Study: subjects, runs, cohort analyses

Before the data

Montage Creator · Conductor

Everywhere

Export · Provenance · Projects · Log

the tour · shell

The shell

A dock: panels you arrange, layouts you keep.

  • Pipeline panel — the workspace list. Each row's light says whether it has run, is stale or has failed.
  • Every panel docks, splits and tabs. View ▸ Layout ships five presets; your working layout autosaves.
  • Info — the file's metadata cards and the block manager: select, rename, duplicate, freeze, delete.
  • Log — the backend's log, streamed live. When something refuses, the reason is here.
the tour · channels and qc

Channels and quality control

Selection is a probe map; judgement is a record.

  • Channels — the 2-D probe map. Click, drag, select all. Short and long split at one session-wide threshold.
  • QC — six native metrics (SCI, PSP, SNR, amplitude, S–D distance, GVTD), your thresholds, a windows view over time.
  • Apply writes the bad-channel record: who judged — QC, a step or you — with what, and when.
  • One record. Every analysis downstream reads it and names what it skipped.
the tour · preprocessing

Preprocessing

One pipeline, two engines, a derived block as the result.

  • Engines: Cedalion (default, reference) and MNE (compatibility). One catalog, one panel.
  • Optical density · motion (TDDR, wavelet, spline, PCA) · band-pass · short-channel regression · Beer–Lambert with a DPF vector · resample · crop.
  • The kind chain is checked as you build: raw → OD → concentration. A step that cannot follow is refused, not skipped.
  • Apply writes the live derived block beside the source. Freeze keeps it. Raw is never touched.
the tour · preprocessing

What the record keeps

  • The as-executed echo: what the engine ran, step by step, kept apart from what was configured.
  • The conversion record: DPF, extinction table, units.
  • Two shipped recommended pipelines, identified by content — ‘the recommended pipeline’ means one thing.
  • Warn-only sanity rules: a transient across a seam, a cutoff above Nyquist, a DPF that looks like a typo.
Switch the active block and the pipeline re-targets and re-applies. It follows the block.
the tour · plots

Looking at the signal

On the selected channels of the active block.

Time series

Stacked or overlaid, event markers, a time cursor shared with the 3-D view.

Spectrogram

CWT or STFT; where the cardiac band goes when you filter.

Frequency

FFT or Welch; the fastest way to see whether a filter did what you asked.

the tour · glm

The GLM

SPM's basis, a pre-whitened solver, and a posture it states out loud.

  • Canonical HRF (spm_hrf) with optional derivatives, or FIR. DCT drift (spm_dctmtx). Short-channel regressors.
  • Solver: AR-IRLS (Barker et al.) or OLS.
  • Contrasts per condition and chromophore; BH-FDR per condition × chromophore; ROI aggregation by precision weighting.
  • Reads the active block — and refuses a non-haemoglobin block by name.
the tour · glm

Posture, and the cortex

  • Every result states its posture: inferential when the correction family and the solver allow it, descriptive when they do not. Mechanically, not by mood.
  • Multi-run: run intercepts, per-run drift, one pooled AR restarting at each seam — and a session-confound statement where conditions come from disjoint runs.
  • Show on cortex paints the t-map on the head. The image domain proper comes with DOT.
the tour · block average

Block average

The model-free view of the same response.

  • Epochs per condition, a pre/post window, baseline correction.
  • Amplitude-range trial rejection; the surviving n reported per channel.
  • Mean ± SEM or CI bands, stacked or per channel.
  • Source: channels, or the vertices of an ROI in the image domain.
  • Channels in the bad-channel record are skipped — and the result says so.
the tour · connectivity

Connectivity and laterality

connectivity
  • Pairwise Pearson over a panel-owned band-pass; a regime label says what kind of estimate you have.
  • Bartlett-corrected inference with BH-FDR behind a mechanical gate. Below it the matrix is descriptive, and says so.
  • Import a nirconn result with its provenance, or run over image-domain ROI vertices.
laterality
  • Seghier's LI over ROI pairs; group t with BH-FDR across pairs.
the tour · roi

Regions of interest

Defined once, read by the GLM, laterality and the image domain.

  • An ROI is a named channel set; a hemisphere seed helps you start it.
  • The GLM aggregates a contrast over an ROI by precision weighting.
  • Laterality wants pairs — left and right of the same region.
  • In the image domain an ROI bounds the cortex vertices that get materialised — which keeps that computation affordable.
the tour · diffuse optical tomography

The head, the light and the inverse

  1. Anatomy. The bundled colin27 atlas at startup; your subject's FreeSurfer surfaces when there is an MRI.
  2. Projection. Optodes onto the scalp, channels onto the cortex.
  3. Forward. A four-layer analytic slab by default, or MCX through the head. One arm per wavelength; engine and medium reported.
  4. Inverse. Per-wavelength operators, NeuroDOT regularisation with an L-curve, unmixed to HbO / HbR.
  5. Quality. PSF, CNR/CBR, adequacy rules.
the tour · diffuse optical tomography

The image domain is an analysis domain

  • Once W exists, the GLM, block average and connectivity run on cortex vertices — the same kernels, a different unit.
  • Project a channel β through W, or materialise W·Y over an ROI-bounded node set.
  • The rank ceiling — never above the channel count — is reported, and the result labelled descriptive.
The image is only as good as the forward model — and that is only as good as the optode positions.
the tour · display

The 3-D viewport and Display

An analysis panel decides what a result is; Display decides how it looks.

  • Layers: Cortex, Edges, Probe, Head, Camera — one stack, one transport.
  • Every Show on cortex lands here: live decay, a GLM t-map, the image, a group map, a connectivity graph.
  • Colormap, range and channel-to-cortex blur — set once, shared.
  • Capture: a PNG plus a sidecar naming what was painted. Animation: a block-average movie to MP4.
the tour · study

The Study

A cohort is subjects; a subject is a never-empty list of runs.

  • Import a cohort from a folder — subjects by subfolder, prefix or pattern; drag runs between them; commit.
  • One run policy: fit each run and combine (the default), or concatenate and fit once. Either way a participant enters the group model once.
  • Group GLM (RFX + BH-FDR), group block average, group laterality — each with an exclusion manifest and a hard stop on unit mismatch.
  • Open a subject into the session under a study banner; adopt its pipeline back.
the tour · study

What the study file holds

  • .nwstudy — the cohort, the policy, the per-subject pipelines, and every group result with its record.
  • Inputs are content-hashed; a run that changed on disk drops the results that read it, naming the subject and the run.
  • Batch first level: one folder per run fit, one per subject estimate, subjects.csv on top.
The multi-run design is deliberate: session is stated as a confound in every record, never quietly modelled away.
the tour · montage creator

The Montage Creator

Design the probe on the head before anyone is wearing it.

  • A top view over the loaded head's 10-5 grid: labelled sites plus free scalp points.
  • Place optodes; a channel rule derives the channels; short-separation bundles are explicit.
  • NIRSport2 accounting: one to five units, cumulative ports, what fits.
  • Mirror through the fitted mid-sagittal plane; auto-fill a region at a spacing; undo and redo.
  • Your own S/D numbers — conflicts marked, never silently renumbered.
the tour · montage creator

Montages, in and out

exports
  • The NIRSite folder Aurora loads: probeInfo.mat in ICBM152 space, byte-equal to NIRx's own, accepted by Aurora 2025.2.
  • probeInfo.json, a probe-only SNIRF, .nirwmontage.
imports
  • probeInfo.mat, a recorded SNIRF's probe, a piano-spec text. 35 of 36 NIRSite montages round-trip exactly.
Eight templates ship; New from template… opens one unsaved.
the tour · conductor

The Conductor

Run the experiment from the same window you will analyse it in.

  • A .nwparadigm: markers, a timeline of timed and self-paced blocks, seeded jitter, cue keys 1–9, LSL outlets.
  • The schedule expands per seed before Start; dry-run it at 10×.
  • Every marker to every outlet with one explicit LSL timestamp; a minimum gap enforced.
  • A crash-safe session log: every marker on both clocks, per-outlet outcomes, planned vs actual. Marker TSV export.
the tour · export

Export, provenance, projects

What leaves the application, and what comes back.

canonical exports a–n
  • CSV/TSV parts plus a JSON sidecar with the ProvenanceRecord: GeneratedBy, Sources, Parameters, Exclusions, Statistics.
snirf
  • A complete file tagged NIRWizard_*: the block set, the pipeline, the runs. Never over the original.
projects
  • .nirw: hashed inputs, every config, every cached result. Derived blocks replayed on open.
part · ~10 min

One workflow, end to end

One participant, one motor task. Open, preprocess, average, fit, look at the cortex, save.

act 1 of 7

Open and look

  1. File ▸ Open · 2025-05-19_004.snirf
  2. Info: 51 channels, 2 wavelengths, ~5.09 Hz, 316.5 s, one block, three stim groups.
  3. Channels: select all.
  4. Time series: raw intensity with the event markers.
  5. Frequency: cardiac at ~1 Hz, an LF hump at ~0.1 Hz.
Know what you have first: the sampling rate sets every filter, the stim table every design.
act 2 of 7

Preprocess

  1. Preprocessing: Cedalion, load cedalion-recommended.
  2. Optical density → TDDR → band-pass 0.01–0.5 Hz → Beer–Lambert (DPF from age).
  3. Check the kind badges: raw → OD → OD → OD → HbO / HbR.
  4. Apply. A derived block appears beside raw and becomes active.
  5. Frequency again: the cardiac peak is gone.
Raw is still there. Switch back any time.
act 3 of 7

Name the conditions, check the channels

  1. Conditions: 0 → Rest, 1 → Left hand, 2 → Right hand. Colour them.
  2. QC: run the metrics on the raw block, look at SCI and SNR, apply the verdicts.
  3. The bad-channel record now excludes those channels from everything downstream — and says so in every result.
Judgement is a record, not a deletion. The channels stay in the file; the analyses skip them and write down that they did.
act 4 of 7

Block average

  1. Block average: Left and Right checked, pre 5 s, post 20 s, baseline on.
  2. Run. Look at the overlay: HbO up, HbR down, contralateral.
  3. Unstack and find one contralateral sensorimotor channel with a clean evoked response.
  4. Note the per-channel n after trial rejection.
act 5 of 7

Fit the GLM

  1. GLM: canonical HRF, drift on, AR-IRLS. Contrasts: Left, Right, Left > Right.
  2. Run. The heatmap: t per channel × condition, FDR-marked.
  3. Show on cortex with the Left-hand contrast: the right hemisphere lights.
  4. Swap to Right-hand: the left hemisphere.
  5. Read the posture line: inferential or descriptive, and why.
act 6 of 7 · optional

Onto the head

  1. DOT: projection runs itself on the colin27 head.
  2. Forward model, analytic engine — under a minute.
  3. Inverse model, default regularisation.
  4. Image: the block-average peak as a reconstructed image, PSF resolution beside it.
  5. Display: export the Left-vs-Right movie.
An atlas head, and the record says so. Still the right way to look.
act 7 of 7

Save it, all of it

  1. Export ▸ GLM: CSV parts and the JSON sidecar — the record.
  2. Export ▸ SNIRF: the derived block written back, tagged.
  3. File ▸ Save project: motor_case_study.nirw.
  4. Close. Reopen. Every panel is where you left it.
the workflow

Seven acts, one window, zero scripts.

And the reviewer's question has an answer in a file.

part · ~2 min

Getting started

Install it, read further, and ask.

getting started · install

Install and run

Get the application

  • Windows installer and Linux packages from the releases page.
  • Free to use, source available.

Preprocessing engines

  • Python ≥ 3.11 with Cedalion (pinned tag) — the default.
  • MNE + MNE-NIRS for the compatibility backend.
  • Windows: the easy-installation script sets up both.

Optional

  • Docker for FreeSurfer anatomy · MCX for Monte-Carlo · ffmpeg for movies · liblsl for the Conductor.
Nothing optional blocks the workflow. Without Python the app opens, plots, runs QC, the GLM, block average, connectivity and DOT on the atlas head. The engines add preprocessing.
getting started · docs

Read next

1

docs/scientific_validity.md

The statistical chain, method by method, with the oracles.

2

docs/tutorial/

The motor-task case study, written out.

3

docs/montage.md · docs/conductor.md

The two pre-data workspaces.

NIRWizard

Questions?

Adam Aske

Feedback goes straight from Help ▸ Feedback to the developer. Downloads, docs and the citation: askeengineering.no/nirwizard