Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: Movement correction for OPM data #11275

Open
larsoner opened this issue Oct 24, 2022 · 11 comments
Open

ENH: Movement correction for OPM data #11275

larsoner opened this issue Oct 24, 2022 · 11 comments

Comments

@larsoner
Copy link
Member

Time-varying position / head-movement correction would be the next natural step after #10780 I think.

IIRC the procedure is/could be here:

  1. Extract time-varying rigid-body position + rotation of the system, typically using optical tracking: new mne.chpi.read_head_pos_optitrack, or mne.chpi.calculate_head_pos_optitrack, depending on the complexity of the problem (if optitrack directly gives pos+rot, or we actually need to do some calculation). It's a bit of a misnomer, but mne.chpi is where all our head-position related stuff lives, so the optitrack outputting pos+rot as a function of time is natural there. We could put it in a new mne.optitrack, or mne.preprocessing.opm or something if we want, but optical tracking seems pretty generic.
  2. Clean up position+rotation parameters: new mne.chpi.clean_head_positions or so? Or maybe this should be built into calculate_head_pos_optitrack. TBD.
  3. Add head positions to the raw data (as new channels) -- this is what maxwell_filter does, so it's natural for us to do it as well -- maybe mne.chpi.add_head_positions(raw, pos) and you can choose how to interpolate. (Under the hood this probably boils down to a mne.add_channels((raw, RawArray(...))) or so but we'll need to interpolate/upsample the positions+rotations, and setting the info correctly will be annoying -- so not totally trivial, thus worth wrapping.)
  4. Regressing can then be done immediately with regress_artifact I think. OPM-specific options we need, if any, should hopefully be useful for other types of regression and thus reasonably implemented there.

@neurofractal did you ever play around/try regressing quaternions rather than Euler angles for rotation angle (by my bad memory you use Euler for regression)? We can convert back and forth but the .pos files we use for position + rotation information in space store in quaternions, so if those work just as well or better than Euler angles it's a slightly more natural fit here.

@larsoner larsoner added this to the 1.3 milestone Oct 24, 2022
@neurofractal
Copy link
Contributor

This sounds very logical. I have tried quaternions with the regression with very similar results. I plot Euler angles in the paper as I think they're more intuitive to interpret! But yes easy to convert backwards and forwards :)

@larsoner larsoner modified the milestones: 1.3, 1.4 Dec 8, 2022
@larsoner larsoner modified the milestones: 1.4, 1.5 Apr 21, 2023
@larsoner larsoner modified the milestones: 1.5, 1.6 Jul 31, 2023
@GonReina
Copy link
Contributor

Hello, I am happy to give this a go if that's. I have access to OPM-MEG data so could test it with that. I guess it would be good to decide where to implement this functionality, it sounds sensible to add the optitrack io and data cleaning to something like mne.optitrack. @larsoner @drammock what do you think?

@neurofractal
Copy link
Contributor

Would be useful - just as a note of caution, motion capture data need to be good quality or else it adds noise to your data when regressing.

@larsoner
Copy link
Member Author

Since it's really used for preprocessing the data and we might end up needing motion/movement-specific stuff (like cleaning/smoothing/interpolating the motion data for example?) then a new namespace mne.preprocessing.motion or mne.preprocessing.movement would make sense, e.g. with a first function mne.preprocessing.movement.read_optitrack or so.

So far I think https://github.com/mne-tools/mne-python/blob/main/mne/datasets/ucl_opm_auditory/ucl_opm_auditory.py just has the stationary data when you download it but there is also a moving version right @neurofractal ? If so that would be a good dataset to use for improving the OPM tutorial. And we can take the optitrack data from it and add it to mne-testing-data for unit testing.

But @Gon-reina you could start by open a draft pull request to add the mne.preprocessing.motion.read_optitrack or so based on some code you already have (?) and we can iterate on the API and namespace there if needed. git mv is pretty easy. And we can update mne-testing-data and the tutorial in subsequent commits.

@GonReina
Copy link
Contributor

That sounds like a good plan. I do have code that will read and process optitrack data but it's in MATLAB. However I don't think it would be too difficult to implement in Python. I will open the draft pull request once I have something working. I could also record some movement data since I have access to our OPM lab, might be a good dataset just for testing movement correction.

@larsoner
Copy link
Member Author

I could also record some movement data since I have access to our OPM lab, might be a good dataset just for testing movement correction.

That would be great -- for mne-testing-data ideally it would be very short (1-10 sec maybe?). Whatever minimum amount of data allows us to be confident that the reader is working properly. You could record this data and process it with your MATLAB code and save the output to .mat or CSV or something and include it with the raw optitrack data when uploading to mne-testing-data. Then your PR here can use the data and np.testing.assert_allclose that the Python result is similar to MATLAB.

@GonReina
Copy link
Contributor

Sounds good! I'll do a quick scan later this week as soon as I'm free and run it through MATLAB. Thanks for the help!

@neurofractal
Copy link
Contributor

As a word of caution - we have found regression performs far worse than spatial filtering techniques like HFC... so if you have enough channels this is the way to go.

@GonReina
Copy link
Contributor

Thanks for the advice! I do agree with that and I do use HFC with all of my data. However, I do find that our background fields are really small thanks to the use of our coils. This already helps massively with movement artifacts so HFC doesn't tend to make much of a difference (at least from my experience) if the nulling is working properly. Some people in our group are starting to do some sitting to standing experiments and stuff like that which involves a lot of head movement so I was just curious as to how much of a difference this could make to the data. I also just wanted to contribute to mne to make it more OPM friendly so thought this could be a good first issue for that.

@neurofractal
Copy link
Contributor

Awesome - good luck :)

@larsoner
Copy link
Member Author

Adding something along these lines in a tutorial would be good.

@larsoner larsoner removed this from the 1.6 milestone Nov 7, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants