Custom fNIRS Montage

Configuration:

  • Python: 3.10.6
  • MNE version: e.g. 1.1.1
  • operating system: Windows 10

For my research I use a Shimadzu Foire-300 and am able to properly create RawArray files. However, I am having issues with creating a proper DIGMontages. I tried to follow your answers on other support discussions but to no result.

Because of the Foire-3000 not returning optical density data we only have a RawArray using hbo and hbr data, setting up the montage and plotting it seems to work reasonably. However when applying the montage to the RawArray I get the following error:

ValueError : ‘S10’ is not in list

and earlier I get a warning:

“Consider setting the channel types to be of EEG/sEEG/ECoG/DBS/fNIRS using inst.set_channel_types before calling inst.set_montage, or omit these channels when creating your montage.”

I feel as if these two messages are connected but don’t know how to solve it. I tried setting channel types to no avail and tried reduce the double hbo/hbr channel names to only include hbo channels.

I looked into the source code and noticed that .set_montage splits the channel names by ‘_’ and then tries to index the channel names by their split[0] and split[1] parts. However it seems to go wrong here and I don’t really know what step I should take to correctly create sensor locations for my data.

I hope to find an answer to a couple of questions:

  • if I have hbr/hbo channels should I set up the digital montage with 51 or 102 channels?
  • Is my set up of channel names and coordinates proper?
  • with my limited fiducials what is the best coordinate frame: mri, head or unknown?

My Code:

dict_ch_pos = {'CH01': [18.592699,1.143265,0.035148],
'CH02':[19.784060,-0.518858,0.582227],
'CH03':[20.045658,2.546851,1.358827],
'CH04':[21.237019,0.884728,1.905906],
'CH05':[22.308882,2.177669,3.590291],
'CH06':[22.028385,-0.860704,2.789638],
'CH07':[23.100250,0.432237,4.474023],
'CH08':[22.186592,-2.375688,3.622757],
'CH09':[23.533587,-1.708249,5.490698],
'CH10':[20.172302,-4.454614,2.717572],
'CH11':[19.629038,-5.999544,3.692056],
'CH12':[23.853470,1.283925,6.363868],
'CH13':[24.052835,2.320395,8.230345],
'CH14':[24.286806,-0.856561,7.380543],
'CH15':[24.654545,0.123084,9.371391],
'CH16':[22.032858,-4.311061,4.570611],
'CH17':[23.379852,-3.643623,6.438551],    
'CH18':[21.489594,-5.855992,5.545094],
'CH19':[22.770203,-5.327726,7.428386],
'CH20':[23.921515,3.355422,10.225385],
'CH21':[24.523224,1.158112,11.366430],
'CH22':[24.264742,2.225241,12.942490],
'CH23':[24.269310,-2.790230,8.423134],
'CH24':[24.637049,-1.810584,10.413981],
'CH25':[23.659660,-4.474334,9.412968],
'CH26':[24.405617,-3.806060,10.992815],
'CH27':[20.475264,-7.167827,6.455670],
'CH28':[21.755871,-6.639562,8.338962],
'CH29':[20.354549,-7.999532,9.109634],
'CH30':[24.870075,-0.883081,12.037460],
'CH31':[24.611593,0.184047,13.613520],
'CH32':[24.638643,-2.878557,12.616294],
'CH33':[24.162529,-1.678006,14.749978],
'CH34':[22.862587,-6.316775,9.948372],
'CH35':[23.608543,-5.648501,11.528219],
'CH36':[21.461266,-7.676744,10.719044],
'CH37':[22.111305,-7.034263,12.792088],
'CH38':[23.651363,1.391631,15.641346],
'CH39':[23.202301,-0.470422,16.777805],
'CH40':[21.732430,0.917597,18.418945],
'CH41':[23.710838,-4.589693,13.759712],
'CH42':[23.234724,-3.389143,15.893396],
'CH43':[22.213600,-5.975455,15.023582],
'CH44':[21.789673,-4.992026,16.664827],
'CH45':[19.345104,-8.401552,12.134482],
'CH46':[19.995142,-7.759070,14.207526],
'CH47':[22.166668,-2.121834,17.673340],
'CH48':[20.696796,-0.733815,19.314480],
'CH49':[20.721615,-3.724717,18.444771],
'CH50':[20.089256,-7.278500,15.619411],
'CH51':[19.665329,-6.295071,17.260658]}

chan_names = [
'S1_D1 hbo', 'S1_D1 hbr',       # 1
'S2_D1 hbo', 'S2_D1 hbr',       # 2
'S1_D2 hbo', 'S1_D2 hbr',       # 3
'S2_D2 hbo', 'S2_D2 hbr',       # 4
'S3_D2 hbo', 'S3_D2 hbr',       # 5
'S2_D3 hbo', 'S2_D3 hbr',       # 6
'S3_D3 hbo', 'S3_D3 hbr',       # 7
'S4_D3 hbo', 'S4_D3 hbr',       # 8
'S6_D3 hbo', 'S6_D3 hbr',       # 9
'S4_D4 hbo', 'S4_D4 hbr',       # 10
'S7_D4 hbo', 'S7_D4 hbr',       # 11
'S3_D5 hbo', 'S3_D5 hbr',       # 12
'S5_D5 hbo', 'S5_D5 hbr',       # 13
'S6_D5 hbo', 'S6_D5 hbr',       # 14
'S8_D5 hbo', 'S8_D5 hbr',       # 15
'S4_D6 hbo', 'S4_D6 hbr',       # 16
'S6_D6 hbo', 'S6_D6 hbr',       # 17
'S7_D6 hbo', 'S7_D6 hbr',       # 18
'S9_D6 hbo', 'S9_D6 hbr',       # 19
'S5_D7 hbo', 'S5_D7 hbr',       # 20
'S8_D7 hbo', 'S8_D7 hbr',       # 21
'S10_D7 hbo', 'S10_D7 hbr',     # 22
'S6_D8 hbo', 'S6_D8 hbr',       # 23
'S8_D8 hbo', 'S8_D8 hbr',       # 24
'S9_D8 hbo', 'S9_D8 hbr',       # 25
'S11_D8 hbo', 'S11_D8 hbr',     # 26
'S7_D9 hbo', 'S7_D9 hbr',       # 27
'S9_D9 hbo', 'S9_D9 hbr',       # 28
'S12_D9 hbo', 'S12_D9 hbr',     # 29
'S8_D10 hbo', 'S8_D10 hbr',     # 30
'S10_D10 hbo', 'S10_D10 hbr',   # 31
'S11_D10 hbo', 'S11_D10 hbr',   # 32
'S13_D10 hbo', 'S13_D10 hbr',   # 33
'S9_D11 hbo', 'S9_D11 hbr',     # 34
'S11_D11 hbo', 'S11_D11 hbr',   # 35
'S12_D11 hbo', 'S12_D11 hbr',   # 36
'S14_D11 hbo', 'S14_D11 hbr',   # 37
'S10_D12 hbo', 'S10_D12 hbr',   # 38
'S13_D12 hbo', 'S13_D12 hbr',   # 39
'S15_D12 hbo', 'S15_D12 hbr',   # 40
'S11_D13 hbo', 'S11_D13 hbr',   # 41
'S13_D13 hbo', 'S13_D13 hbr',   # 42
'S14_D13 hbo', 'S14_D13 hbr',   # 43
'S16_D13 hbo', 'S16_D13 hbr',   # 44
'S12_D14 hbo', 'S12_D14 hbr',   # 45
'S14_D14 hbo', 'S14_D14 hbr',   # 46
'S13_D15 hbo', 'S13_D15 hbr',   # 47
'S15_D15 hbo', 'S15_D15 hbr',   # 48
'S16_D15 hbo', 'S16_D15 hbr',   # 49
'S14_D16 hbo', 'S14_D16 hbr',   # 50
'S16_D16 hbo', 'S16_D16 hbr',   # 51
]

#### Fiducials and scaling
nasion = [x*0.01 for x in [11.232580,0.487142,0.482432]]
lpa = [x*0.01 for x in [8.851848,6.727137,10.000131]]
rpa = [x*0.01 for x in [9.345170,-6.998555,8.775833]]
hsp = [x*0.01 for x in [24.690950,-0.762161,11.439560]]

for k, v in dict_ch_pos.items():
  dict_ch_pos[k] = [x*0.01 for x in v]

final_pos = [.]
for x in dict_ch_pos.values():
  final_pos.append(x)
  final_pos.append(x)

values = list(dict_ch_pos.values())
locations = dict(zip(chan_names, final_pos))
chan_types = ['hbo', 'hbr'] * 51
channel_types = dict(zip(chan_names, chan_types))

montage = mne.channels.make_dig_montage(ch_pos=locations, nasion=nasion, lpa=lpa, rpa=rpa, coord_frame='head') 

info = mne.create_info(ch_names=chan_names, ch_types=chan_types, sfreq=sfreq)
raw_haemo = mne.io.RawArray(ndata, info, verbose=True)

raw_haemo.info['bads'] = ['S2_D3 hbo', 'S2_D3 hbr', 'S3_D3 hbo', 'S3_D3 hbr', 'S4_D3 hbo', 'S4_D3 hbr', 'S6_D3 hbo', 'S6_D3 hbr']

raw_haemo.set_channel_types(channel_types)
raw_haemo.set_montage(montage)
raw_haemo.plot_sensors()

I appreciate everyone’s effort to help and thank you in advance!

Cheers,

Jim

Hi Jim,

Thanks for reporting this issue. And it’s great to see someone using MNE with a Shimadzu device. We should write a proper reader for your hardware so you don’t have to load data by hand.

But in the meantime, you need to follow the specific naming of the channels as described in Importing data from fNIRS devices — MNE 1.2.dev0 documentation I hope this will resolve your issue.

Please let us know if this resolves the issue.

Thank you for your reply. I was able to fix it by properly naming it! Problem resolved!

Great to hear! Please let us know if you encounter any other issues. Be extra vigilant as you are using a device that is untested with MNE (although I don’t expect any issues)

1 Like

Everything works excellent, love the software and support. Keep up the good work!

1 Like