Tutorial on Pre-processing of fNIRS Signals (NIRSport 2 System)
- Manousos A. Klados

- Jul 8
- 2 min read

Introduction to Functional Near-Infrared Spectroscopy (fNIRS)
Functional near-infrared spectroscopy (fNIRS) is a non-invasive neuroimaging technique that measures brain activity through the hemodynamic responses associated with neuronal behavior. It utilizes near-infrared light to detect changes in oxygenated (HbO) and deoxygenated (HbR) hemoglobin concentrations in cortical tissues. Due to its portability, ease of use, and high temporal resolution, fNIRS has become an increasingly popular tool in cognitive neuroscience, clinical diagnostics, and developmental studies, allowing researchers to investigate brain function in naturalistic environments and populations where traditional neuroimaging techniques like fMRI are challenging to implement.
Step-by-Step fNIRS Preprocessing Pipeline
Step 1: Loading SNIRF Data
First, we need to load our SNIRF data. Python’s mne library offers convenient support for reading SNIRF files.
import mne
# Load SNIRF
dataraw_fnirs = mne.io.read_raw_snirf('your_file.snirf', preload=True)
print(raw_fnirs.info)Step 2: Converting Raw Intensity to Optical Density
Raw intensity signals must be converted into optical density to reflect changes in absorbed light.
raw_od = mne.preprocessing.nirs.optical_density(raw_fnirs)Step 3: Converting Optical Density to Hemoglobin Concentration
Next, convert optical density to oxy- (HbO) and deoxyhemoglobin (HbR) concentrations using the modified Beer-Lambert law.
raw_haemo = mne.preprocessing.nirs.beer_lambert_law(raw_od)Step 4: Filtering
Apply a band-pass filter to remove physiological artifacts (e.g., heartbeat, respiration) and instrumental noise.
raw_haemo.filter(l_freq=0.01, h_freq=0.2, h_trans_bandwidth=0.05, verbose=True)Step 5: Artifact Detection and Correction
Identify and correct motion artifacts, often prominent in fNIRS data.
from mne.preprocessing.nirs import scalp_coupling_index
# Calculate Scalp Coupling Index (SCI) to identify bad channels
sci = scalp_coupling_index(raw_od)
raw_haemo.info['bads'] = list(sci[sci < 0.5].index) # Mark bad channels
# Interpolate bad channels
raw_haemo.interpolate_bads()Step 6: Data Downsampling (Optional)
Reduce data size and computational load if necessary.
raw_haemo.resample(sfreq=2.0) # Resample to 2 HzStep 7: Epoching
Segment continuous data into epochs aligned with experimental events.
events, event_dict = mne.events_from_annotations(raw_haemo)
epochs = mne.Epochs(raw_haemo, events, event_id=event_dict, tmin=-5, tmax=15, baseline=(None, 0), detrend=1, preload=True)Final Thoughts
This preprocessing pipeline will give you clean, artifact-free fNIRS data ready for statistical analysis or machine learning applications. You can customize each step to better fit your research needs and data characteristics. Happy analyzing!
Enjoyed this post?
If you found this helpful, subscribe to my email list for more on research workflows, productivity in academia, and life as a scholar.
You can also visit my website add me as friend in LinkedIn to connect, explore options, or see what I’m working on.
Dr. Manousos Klados, MSc, PhD. PGCert. FHEA, FIMA
🎓Associate Professor in Psychology
Director of MSc/MA in Cognitive/Clinical Neuropsychology
✍️ Editor in Chief of Brain Organoid and System Neuroscience Journal
🧬 Scientific Consultant @ NIRx
🧑💻 Personal websites: www.mklados.com



Comments