adding montage and fiducials in bids format

  • MNE version: 1.4.2
  • operating system: Windows 10 / Ubuntu 22.04.2 LTS

Dear MNE community,

I am using mne/mne-bids to convert my data (from a TMSi SAGA in Poly5 format) to BIDS. Where I get stuck is in defining the electrode placements and properly document recorded fiducials.
We use an easycap with standard 10-20 electrode layout and have recorded lpa/rpa/nasion with Localite neuronavigation.

However, a couple of things tell me I am doing something wrong.
First, the electrodes are documented as being stored in CapTrak space, even though the standard montage in mne that I use should be defined in fsaverage space.
Second, when I try to register the electrodes to the individuals MRI, it does not look very good, not what I would expect after transforming from fsaverage to individual freesurfer space.

This is roughly what I did:

First, I import the standard 10-20 montage and add it to my raw data:

mont=mne.channels.make_standard_montage('standard_1020')
raw.set_montage(mont)

…and write it in bids format:

write_raw_bids(raw, bids_path=[my bids path],event_id=event_id,allow_preload=True,
               format='BrainVision',overwrite=True)

I also add fiducials recorded with neuronavigation software to the T1w sidecar:

entries = {
    'AnatomicalLandmarkCoordinates': {
        'NAS': [],
        'LPA': [],
        'RPA': []
    }
}

anat_nii=anat_folder.copy().update(extension='.nii.gz')
nif=nib.load(anat_nii)
nii_mat=nif.header.get_qform()
fiducial_voxels=fiducials
for idx,fid in enumerate(fiducials):
    coord=np.append(np.reshape(fid, (3,-1)),[[1]],axis=0)
    fiducial_voxels[idx,:]=np.reshape(np.linalg.lstsq(nii_mat,coord,rcond=0)[0][0:3],[1,3])

landmarks = mne.channels.make_dig_montage(lpa=fiducial_voxels[0],nasion=fiducial_voxels[1],rpa=fiducial_voxels[2],coord_frame="mri_voxel")
anat_folder = BIDSPath(subject=subject,session=session,datatype='anat',acquisition='lowres',suffix='T1w',root=bids_folder)
anat_sidecar = anat_folder.copy().update(extension='.json')
update_sidecar_json(bids_path=anat_sidecar, entries=entries)
update_anat_landmarks(anat_folder, landmarks)

I notice that fiducials have been added to the ‘coordsystem.json’ as well. I guess they are part of the standard monetage then?

Now, I try to read the bids formatted data and calculate transforms from standard electrode placements to the individual MRI:

raw=read_raw_bids(eeg_data)

trans=get_head_mri_trans(eeg_data, 
                   t1_bids_path=t1_data, 
                   fs_subject=subject, 
                   fs_subjects_dir=fsdir)

…and plot the results:

fig = mne.viz.plot_alignment(
    raw.info,
    trans=trans,
    subject=subject,
    subjects_dir=fsdir,
    show_axes=True,
    dig='fiducials',
    mri_fiducials=True,
    coord_frame="mri",
)

And this is the result:

Is there anthing obviously wrong with my approach or are the results to be expected?

Any help is much appreciated!

yes, it seems like they are: https://github.com/mne-tools/mne-python/blob/bb1d54798e56b2854cba76d0f3b12a383b8bb96f/mne/channels/data/montages/standard_1020.elc#L104-L106

Why have you recorded the fiducial positions, but not the electrode positions? You are now trying to mix true, recorded (digitized) fiducial positions with template positions that have nothing to do with your study participant :thinking: I haven’t come across an approach like that and I am wondering what the advantages of this are.

Another complicating factor is that the MNE-Python 10-20 template positions are not “idealized” positions (e.g., computed on a sphere as in GitHub - sappelhoff/eeg_positions: Compute and plot standard EEG electrode positions.), but based on “realistic” positions. A good read for this topic can be found here (it’s an ongoing problem):

This is probably a problem on the side of mne-bids.

Unfortunately dealing with digitized sensor positions is not very advanced in MNE-BIDS … one could call it a “work in progress”, but it’s been in progress for quite a while, because it is a relatively complex undertaking that requires input from many different people. So far, none of us volunteers was motivated or hard-pressed enough to take this on fully.

Some issues to read through may be:

Finally, my practical advice for you when dealing with coordinate systems and mne-bids and it doesn’t work out of the box is to:

  1. report this issue (as you did), and hope that somebody (maybe even you?) will fix it eventually
  2. proceed with your work by writing custom code and not relying on mne-bids for this particular aspect

Thank you, this is very helpful!

It clarifies some things for me. My idea with recording fiducials was that they would allow for finding (nonlinear) transforms from template space to individual MRI space. But since the montage that I use is defined on fsaverage, this indeed seems redundant.

If I understand things correctly, I should manually changing the coordsystem.json for now.

What I am still struggling with is the correct approach when not having electrode positions recorded but an available MRI image. Would it make sense to run freesurfer on the individual MRI and use fsaverage to subject transforms on the standard 1020 montage to map that to subject MRI space? Seems like that would be the most accurate without recording actual eletrode placements.

I will make sure to read up on your suggestions, I wasn’t even aware of the idealized vs realistic issue.

Best regards,
Jonas

I don’t really have experience with that, so I have my fingers crossed for your that somebody else stumbles over this and can be of help. :slight_smile:

While the approach sounds reasonable from a data analysis perspective, I don’t think it’s a good idea to store a standard montage in BIDS format as if it were digitized electrodes. (In fact, MNE aligns the montage using the LPA/RPA/nasion, so what you propose might already be done under the hood in raw.set_montage). That has the potential to be confusing for folks consuming the data downstream.

Mainak