NINFA is a MATLAB framework for running custom neurofeedback protocols via Lab Streaming Layer (LSL) streams. Its flexible and reusable software design enables real-time data acquisition across brain regions and neuroimaging techniques. While initially developed for fNIRS, it is also compatible with EEG and other modalities.
By providing a unified and adaptable framework, NINFA allows researchers, students, and engineers to design and run neurofeedback experiments without reinventing the wheel.
- Operating System: Windows 10 or 11 (macOS and Linux support coming soon)
- MATLAB Version: 2023b
The first step is to clone the repository using the following command:
# SSH
git clone [email protected]:PsychoOI/NINFA.git
# Or HTTPS (if SSH keys aren’t set up)
git clone https://github.com/PsychoOI/NINFA.gitThe next step is to prepare your JSON configuration file. This file defines the experiment setup, including:
- Model name and type. Having a descriptive name for your measurement configuration is a good practice. (e.g., impulsivity_protocol.json )
- LSL stream type (e.g., NIRS, EEG) and expected channels
- Channel map (long and short channels defined from the probe set)
- Metadata for blinded experiments
The channels parameter should match the complete set of sources and detectors in your probe set. Channels can be organized (though not always required) into five blocks:
- Block 1: Counter (devch 0)
- Block 2 & 3: Wavelength measurements (devch 1 … N for both blocks, where N is the number of channels in the probe set)
- Block 4 & 5: HbO and HbR measurements (devch 1 … N)
Ensure this structure is set correctly and matches, so the mapping between dev channels and LSL ones works smoothly and yields correct values.
The channel_map parameter maps the probe set channels configuration by identifying the long and short channels used in the experiment. NINFA detects whether this is real or sham feedback and acts accordingly.
Finally, the modes parameter is used for blinded experiments. Here, you can define different experiment modes, where the operator assigns labels for real and sham conditions and selects which algorithm to use. During runtime, the experimenter only chooses between Condition A and B without knowing which one corresponds to the real feedback.
// A pseudo-JSON for illustration
{
"name": "your_model_name",
"type": "NIRS", // Assuming you have an fNIRS device
"lsl": {
"type": "NIRS", // Assuming you have an fNIRS device
"channels": [
// Counter devch 0
{ "devch": 0, "type": "COUNTER", "unit": "" },
// Dev channels with wavelength = 760NM (1 -> N)
{ "devch": 1, "type": "WL760NM", "unit": "V" },
''''
{ "devch": N, "type": "WL760NM", "unit": "V" },
// Dev channels with wavelength = 850NM (1 -> N)
{ "devch": 1, "type": "WL850NM", "unit": "V" },
''''
{ "devch": N, "type": "WL850NM", "unit": "V" },
// HbO channels (1 -> N)
{ "devch": 1, "type": "HbO", "unit": "μmol/L" },
''''
{ "devch": N, "type": "HbO", "unit": "μmol/L" },
// HbR channels (1 -> N)
{ "devch": 1, "type": "HbR", "unit": "μmol/L" },
''''
{ "devch": N, "type": "HbR", "unit": "μmol/L" }
]
},
// Neurofeedback and short separation channels
"channel_map": {
"long_channels": { "HbO": [7, 11, 17], "HbR": []},
"short_channels": { "HbO": [4, 10, 19], "HbR": []}
},
// Real and sham neurofeedback in a blinded mode
"modes": {
"A": { "label": "Condition A", "role": "real", "protocol": "MovAvg_SS"},
"B": { "label": "Condition B", "role": "sham", "protocol": "BandPass"}
},
// Enabling the blind_role in the UI -> Otherwise you choose manually in the UI
"ui": {"blind_role": true},
"default_mode": "A",
"randomize": false
}Finally, consider formatting the reference file name as code: your_experiment_model.json (and double-check the casing/extension).
After creating your JSON file, save it under the devices directory.
To start NINFA, please run main.m inside the repository in MATLAB.
NINFA can run in two modes
- Blinded (You choose condition A or B without knowing which is which)
- Unblinded (You manually choose a real or sham experiment and which algorithm to use)
| Blinded NINFA | Unblinded NINFA |
|---|---|
![]() |
![]() |
Left → A Blinded NINFA, Right → Unblinded NINFA
Automatically, it starts in a blinded mode where the experimenter only has to choose condition A or B. You shouldn’t be able to select protocol and role in a blinded version, as you can in the unblinded version.
-
Select your device
-
[Optional] Adjust the
TYPEof the LSL input stream to match the type in your neuroimaging device -
Click
OPENto connect with the LSL input stream. -
Configure your
EPOCHS(i.e., block design) section using the + sign. -
Click
FILEand thenSAVE; you can use this setting in the future. -
Click
STARTto run a session.
An example of deselecting channels that are of bad quality on your device.
| Setting | Description |
|---|---|
TYPE |
Device type whether NIRS of EEG. |
MODEL |
Which device model are you using? A model is a blueprint representing your device configuration. Check the Device Model Configuration for more details. |
CONDITION |
The conditions or modes in the JSON file represent whether sham or real neurofeedback is used and which protocol to use. |
| Setting | Description |
|---|---|
PROTOCOL |
The Matlab file from the folder protocols with the algorithm executed on each window. |
ROLE |
Real or Sham Neurofeedback |
CHANNELS |
Select LSL channels to use in the selected protocol. They should be preselected in the JSON file, but can be edited here. |
BAD CHANNELS |
The channels might have bad signal quality, and must be deselected here. |
WINDOW SIZE (S) |
Size of the sliding window in seconds. It is used for feedback signal calculation. The window always contains the last n seconds of samples. |
SESSION LENGTH (S) |
The session will automatically stop after this time. |
| Setting | Description |
|---|---|
STUDY |
Name of Study |
SUBJECT |
Number of Subject |
RUN |
Number of Run |
The session will be automatically saved in the subfolder sessions with the name STUDY-SUBJECT-RUN.mat
An epoch is a configurable timespan within a session.
| Setting | Description |
|---|---|
START (S) |
Start of Epoch (in seconds) |
END (S) |
End of Epoch (in seconds) |
MARKER |
Marker Value (1-99) of Epoch (also sent on LSL) |
VISIBLE |
Visibility of Bar in Feedback Window during Epoch |
COLOR |
Background Color in Feedback Window during Epoch |
- Add epoch by clicking
+ - Remove last or selected epoch(s) by clicking
- - Chose background color of selected epoch(s) by clicking
COLOR
- Sends triggers on LSL with stream type and name set to
Trigger - Sends trigger with value
100on session start - Sends trigger with value
101on session end - Sends trigger with custom value from column
MARKERon each epoch start
- Sends markers on LSL with stream type and name set to
Marker - Sends markers with the same sample rate as LSL input (one marker for each LSL input sample)
- Default value is
0(if no active epoch)
- A protocol calculates a feedback value from an input window
- To add a protocol, please put the Matlab file in the subfolder
protocols - The
MovAvg_SS.mexample requires a NIRS device that sends at least oneHbOchannel with aμmol/Lunit and one short channel selected. - The
RecordOnly.mworks with any device type and model and just records data - The
BandPass.mexample requires a NIRS device that sends at least oneHbOchannel with aμmol/Lunit without short channel selection. - The
MovAvg.mexample requires a NIRS device that sends at least oneHbOchannel withμmol/Lunit without short channel selection.
DELAYshows the current offset in the playback schedule (where we arevswhere we should be)- It typically occurs if the average runtime of your protocol is larger than
1s/samplerate - A longer delay can be noticed when the
DELAYvalue turns red.
Shows a centered bar with feedback values <= 0.5 visualized in blue and values > 0.5 visualized in red.
- Ahmed Eldably
- Costanza Iester
- Clint Banzhaf
- Beatrix Barth




