I looked into the code a bit more and it assumes the positions in probeInfo.mat
are in MNI coordinates. Here are some positions from some MNE sample data in NIRx format (the only step was converting to m):
array([[ 0.01484444, -0.1186096 , -0.03058643],
[ 0.06703548, -0.0877003 , -0.00301732],
[ 0.0849505 , -0.02859492, 0.02743647],
[ 0.05828255, 0.04093365, 0.04528764],
[ 0.00951329, 0.08760125, 0.01047327],
[-0.00041748, 0.04718504, 0.0780284 ],
[-0.03847298, 0.00863416, 0.08460399],
[-0.07234127, -0.02961652, 0.06552235],
[-0.07737436, -0.06410442, 0.02685754],
[-0.06508504, -0.08662543, -0.025913 ]])
And here are your positions:
array([[0.16142004, 0.12078901, 0.23869662],
[0.16190077, 0.15281011, 0.24067443],
[0.17805025, 0.13694617, 0.23186901],
[0.17564347, 0.10489866, 0.22882012],
[0.18902322, 0.1196376 , 0.22042102],
[0.1963126 , 0.10167294, 0.20434089],
[0.17677754, 0.16762691, 0.22983916],
[0.19067097, 0.15024533, 0.22068665],
[0.20081685, 0.13287539, 0.20610075],
[0.20493866, 0.11535151, 0.19094783],
[0.09543835, 0.11853737, 0.23809364],
[0.09205033, 0.15109726, 0.24079295],
[0.07789328, 0.13440933, 0.23010027],
[0.08324163, 0.10251256, 0.22770537],
[0.06645596, 0.11696868, 0.21818607],
[0.05848653, 0.09967643, 0.19999609],
[0.07669894, 0.16724697, 0.22812119],
[0.06353808, 0.15020131, 0.21844956],
[0.05210999, 0.13223815, 0.20172453],
[0.04942323, 0.11429096, 0.18430076]])
So clearly the coordinates that you got from the device have an offset and are not in MNI coordinates as the code says is expected. Here’s the part of the code @rob-luke wrote that reads in NIRx channel positions
# Read information about probe/montage/optodes
# A word on terminology used here:
# Sources produce light
# Detectors measure light
# Sources and detectors are both called optodes
# Each source - detector pair produces a channel
# Channels are defined as the midpoint between source and detector
mat_data = loadmat(files['probeInfo.mat'])
probes = mat_data['probeInfo']['probes'][0, 0]
requested_channels = probes['index_c'][0, 0]
src_locs = probes['coords_s3'][0, 0] / 100.
det_locs = probes['coords_d3'][0, 0] / 100.
ch_locs = probes['coords_c3'][0, 0] / 100.
# These are all in MNI coordinates, so let's transform them to
# the Neuromag head coordinate frame
src_locs, det_locs, ch_locs, mri_head_t = _convert_fnirs_to_head(
'fsaverage', 'mri', 'head', src_locs, det_locs, ch_locs)
So, if your coordinates are not in MNI, then we could guess at how to get them there but that’s really not ideal, we should have better positions. @mlrocca, do you know what coordinate frame the locations of your sensors are in? Is this somehow set in the device settings? It’s a bit odd that NIRx uses mat files since they allow any type of data and structure to the data, usually files from a device like this (e.g. edf
or fif
) have a well-specified structure (e.g. the first line is the sampling frequency, the next lines before a break are the channels type of thing) which in my opinion is a pretty good idea to avoid chaos, confusion and issues saving and loading the files like we have here where the program expects a particular structure but doesn’t get it. In summary, it seems like there is unfortunately a bit of a flawed design choice in the NIRx device structure that doesn’t specify exactly where things that you need in the recording should be and that’s causing the program to fail and requiring the experimenter to have to go back and find things (e.g. the transform to MNI) that they really shouldn’t have to do. Sorry it’s a bit of a mess!