Getting started with fNIRS montage

Hi,
I am new to fnirs and MNE. I want to draw the montage (electrodes layout) in 2D and also in 3D on a head model. I am not sure how to start. Some of the electrodes in the montage correspond to the 10-20 eeg electrodes locations, but some don’t. So I have the distance between electrodes, and thier distance from known 10-20 electrodes, but I am not sure how to proceed and what is the format that this info should be stored in. I have a MKII fnirs system (Artinis).
Thanks in advance!

Hello @Michalw and welcome to the forum!

I’m tagging @rob-luke, MNE’s fNIRS expert, who I’m sure will be able to give you some advice!

Best wishes,
Richard

Hi @Michalw,

Thanks for trying out fNIRS with MNE and taking the time to report your question. I don’t have access to an Artinis system, but we can figure this out together, it may just take a few more questions to find the optimal approach.

What we need to do is create a Montage in MNE. This can be done either by reading a file that contains the optode positions in 3D, or by providing the positions manually. Let’s address each approach in turn.

Using a file with optode positions.

Have you looked at this tutorial Importing data from fNIRS devices — MNE 0.24.dev0 documentation ?

The Artinis Octomon and Brite23 have set optode positions. So we created a file to store these positions, then we can simply read it and use the set_montage code. In MNE you must code your optodes and sources and detectors according to a specific convention (see Importing data from fNIRS devices — MNE 0.24.dev0 documentation). Then you need to create a file describing the 3D locations of your specific setup, here is an example from the bride 23 mne-python/artinis-brite23.elc at 0b503d8b64bd1383eee0450c3998700ad354a1ef · mne-tools/mne-python · GitHub

So in the end your code would look something like…

# Following from the tutorial linked above
info = mne.create_info(ch_names=ch_names, ch_types=ch_types, sfreq=sfreq)
raw = mne.io.RawArray(data, info, verbose=True)
montage = mne.channels.read_custom_montage('/path/to/custom/montage.elp')
raw.set_montage(montage)
raw.plot_sensors()

Make sure to read the documentation for each function, and you will probably need to specify the coord_frame too.

Manually listing positions

You could also create the montage just in your script using mne.channels.make_dig_montage — MNE 0.23.4 documentation

Then the same procedure as above would follow.

# Following from the tutorial linked above
info = mne.create_info(ch_names=ch_names, ch_types=ch_types, sfreq=sfreq)
raw = mne.io.RawArray(data, info, verbose=True)
montage = mne.channels.make_dig_montage(...)
raw.set_montage(montage)
raw.plot_sensors()

Questions to you

Does Artinis provide a file specifying the positions of the optodes? If so, can you share an example of this so we can see if it matches an existing location reader?

1 Like

Hi,
Thanks for your time and help. In Brite24, the optodes placement on the head are flexible. There are predefined templates, the researcher can choose where on the head to place the template. The template is not physical, it’s just a description of the order and number of transmitters and receivers and the definition of channels, without the definition of distances between them. I can even choose to make holes for the optodes on the elastic cap so all I can provide is a 2D drawing of the template (assuming a channel length of 30mm) and information regarding optodes that have the same location as electrodes in the 10-20 system (anchor). So I am still not sure how to start…

First, I suggest that you ask Artinis to provide some way to export the sensor locations. The location of the optodes makes a difference with fNIRS measurements. There is more than just the distance between optodes. The properties of the skin and skull etc vary across the head.

But in the meantime, can you estimate the 10-20 positions of where your sensors were placed? Or failing that, can you make up some 3d locations that roughly match the properties of your montage? You just need some rough location estimates to tell the software.

Hi Dr. Luke. I’m also fussing with how to visualize my data that I collected using the artinis-Brite24. I am uploading a screenshot here that shows the artinis-Brite23 montage plotted (I was trying things!) and the sensors from my data plotted as well. (Those are the bunched, inferior, and posterior things you see). I have two questions. #1) I’d really love to visualize my data properly, so do you have any tips that would allow me to do that? #2) Obviously the information about how my sensors were located is inaccurate (for plotting), so is there a chance that this will also affect my analysis/results?

Hi @rob-luke ,

I am following the same instructions you provided for manually listing positions. My data consists of the following details:

  • 14 Source, 16 detectors
  • 72 channels
  • lw 760, hw 850
  • 36 [x,y] positions
    I am listing the 3d position provided in the data to build the montage.

I am getting the following error:
when ch_types = [“hbo”,“hbr”…]
ValueError: The chromophore in info must be [“hbo”, “hbr”], but got [‘760’, ‘850’] instead
OR
when I remove the the ch_types
picks = ch_indices[ch_type]

KeyError: None
OR
when ch_types is [“fnirs_cw_amplitude”…]
ValueError: NIRS channels is missing wavelength information in the info[“chs”] structure. The encoded wavelengths are [nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan, nan].

could you please help me with this?

  1. The raw.plot_sensors() method draws the point between the source and the detector, which is the channel position; the montage.plot() method draws the position of the source and detector. So you can first check whether the montage you provide is correct.
  2. The graphs drawn by raw.plot_sensors() may be messy and disordered. The reason for this damn problem is that mne’s index of source and detector starts from 1, and the of each channel you provide The source/detector index may start from 0. For example, in the .snirf file I provided: sourceIndex=[0, 1, 1, 2], detetorIndex=[0, 1, 2, 3], then the four channels should be S0-D0, S1-D1 , S1-D2, S2-D3, but mne will process it as S3-D3, S0-D0, S0-D1, S1-D2. So the final displayed channel coordinates may be messy. The correct data you should provide is: sourceIndex=[1, 2, 2, 3], detetorIndex=[1, 2, 3, 4].
  3. In addition, the unit of the coordinates will also be a possible cause of the error. Maybe the unit of your coordinate data is dm. However, mne does not support the dm unit, so you may need to convert beforehand.