Skip to content

Axial to planar gradiometer transformation #9609

Description

@piuskern

For axial gradiometer data, e.g. from CTF 275 systems, a transformation to virtual planar gradiometers would be helpful. This is a standard procedure in many data analysis pipelines for axial systems. It would facilitate plotting and subsequent interpretation.

The issue has been briefly discussed during the office hour on 2021-07-23.

@britta-wstnr

Activity

  1. welcome commented on Jul 23, 2021

    @welcome

    Hello! 👋 Thanks for opening your first issue here! ❤️ We will try to get back to you soon. 🚴🏽‍♂️

  2. britta-wstnr commented on Jul 23, 2021

    @britta-wstnr
    Member

    Thanks @piuskern.
    I agree, some methods for this would be useful. During the office hours, we also briefly touched upon how to solve this computationally. As discussed, I will check in detail what FieldTrip does and report back, then we can discuss how we want to proceed.

  3. added this to the 0.24 milestone on Jul 26, 2021
  4. britta-wstnr commented on Jul 28, 2021

    @britta-wstnr
    Member

    FieldTrip supports different methods on how to compute planar from axial grads: sourceproject using a minimum current estimate, fitplane using the neighborhood structure, and sincos using the neighborhood structure as well, but more flexibly than the fitplane option. sincos is default here.

    For the combination of the vertical and horizontal parts, using an SVD is one option, sum (sqrt(horizontal ** 2 + vertical ** 2)) and complex are others.

  5. larsoner commented on Jul 28, 2021

    @larsoner
    Member

    I would start with just the sourceproject method since we have it implemented already and I think @agramfort suggested it should be the best in principle. We can assume YAGNI on the others until we see otherwise (especially if the values aren't that different, or they do differ but the sourceproject is better for example in round-trip test to a different system/sensor type and back).

  6. britta-wstnr commented on Jul 28, 2021

    @britta-wstnr
    Member

    FWIW, there is some rather old opinion by Robert, referring to simulations, saying the sincos method outperforms the others. See here: https://mailman.science.ru.nl/pipermail/fieldtrip/2005-August/026154.html

    But I agree, if it's there, let's start with it and then we can always add this (and compare again, if we are feeling adventurous 😉 )

  7. britta-wstnr commented on Aug 18, 2021

    @britta-wstnr
    Member

    @larsoner What would be a good API for this / where should this live?

  8. larsoner commented on Aug 18, 2021

    @larsoner
    Member

    We have inst.interpolate_bads as a mixin for raw/epochs/evoked, I think it should be part of that same mixin as a new method:

    def interpolate_to(self, sensors=None, dev_head_t=None):
    

    where sensors can be (to start) only None, 'ctf planar grad', 'ctf', and 'neuromag'? If sensors is None then it's useful just for transforming to a new dev_head_t.

    I suggest just these three string options to start because in this issue 'ctf planar grad' is desired, and I could see people wanting to know what their data would look like if they had been acquired on these other systems. Having ctf and neuromag is also nice because we can round-trip from actual Neuromag data to CTF and back to Neuromag and check the agreement, same with CTF to Neuromag to CTF.

    Under the hood this should use the same underlying machinery as interpolate_bads -- it's actually quite simple hopefully as we "just" need to set info_to properly by replacing some info_from['chs'] with the known canonical ones for the given system.

    I like sensors as the name because in theory we could eventually support remapping other channel types (e.g., EEG) someday. But for now the function should operate only on MEG data.

  9. britta-wstnr commented on Aug 20, 2021

    @britta-wstnr
    Member

    Thanks for the detailed overview @larsoner ! I hope to give this a shot soon, maybe together with @piuskern ?

  10. larsoner commented on Oct 22, 2021

    @larsoner
    Member

    @britta-wstnr I'm bumping the milestone as 0.24 is going to be released in just a week or so, but it could still make 0.24 if you have time for it

  11. modified the milestones: 0.24, 1.0 on Oct 22, 2021
  12. modified the milestones: 1.0, 1.1 on Feb 11, 2022
  13. 9 remaining items

  14. larsoner commented on Mar 5, 2024

    @larsoner
    Member

    No it has not been implemented yet, still needs a volunteer to give it a shot

  15. contsili commented on Oct 21, 2024

    @contsili
    Contributor

    Hi all, after a discussion with @britta-wstnr I would like to take over this issue.

    We have inst.interpolate_bads as a mixin for raw/epochs/evoked, I think it should be part of that same mixin as a new method:

    def interpolate_to(self, sensors=None, dev_head_t=None):
    

    @larsoner do you still think this is still a good API?

    Additionally, I see that you decided on sourceproject method. Shall we still proceed with this method?

  16. larsoner commented on Oct 21, 2024

    @larsoner
    Member

    Yeah @contsili that would be great! We can always add other projection methods via a new keyword argument later. I think in principle the PR should be fairly straightforward 🤞

    One issue is that we'll need to store the canonical CTF and Neuromag sensor definitions somewhere (positions, orientations, and coil def number). I don't think we currently do that anywhere as we rely on this info to be stored in a given file being read with read_raw_fif or similar. So you'll probably need to add two new files to mne/channels/data/montages/ to store this info, one for Neuromag and one for CTF. It's a bit of a misnomer to call these "montages" but it's the closest thing we have at the moment I think. And at some point we might want to use the montage mechanics to be able to store / set OPM channel info. I would save this info just as a simple human-readable CSV probably with cols name,coil,x,y,z,ex,ey,ez (I think that's all we need?), I don't think it will end up being too large.

  17. contsili commented on Dec 17, 2024

    @contsili
    Contributor

    I would start with just the sourceproject method since we have it implemented already and I think @agramfort suggested it should be the best in principle. We can assume YAGNI on the others until we see otherwise (especially if the values aren't that different, or they do differ but the sourceproject is better for example in round-trip test to a different system/sensor type and back).

    @larsoner, could you point me to where the sourceproject method is implemented in the mne repo?

  18. larsoner commented on Dec 17, 2024

    @larsoner
    Member

    I think it is implicitly what we use already in

    def _interpolate_bads_meeg(

    which wraps to

    def _map_meg_or_eeg_channels(info_from, info_to, mode, origin, miss=None):

    But really I don't think you need to worry about the mapping method for now. The critical part is that we already have a function that allows mapping from one sensor type (given a suitable info) to another (given its suitable info). What method is used under the hood is a second-level detail/consideration, and we can worry/think about it once we do the work of getting the API right as above.

  19. britta-wstnr commented on Feb 5, 2025

    @britta-wstnr
    Member

    Hi @contsili! 👋 Are you still interested in tackling this? 🙂

  20. contsili commented on Feb 5, 2025

    @contsili
    Contributor

    Hi @britta-wstnr . Yes I am still interested. I started working and I have less time but I will do it!

    I think a good plan is to wait for this PR #13044 to be merged and then I can extend the functionality of interpolate_to to MEG.

  21. britta-wstnr commented on Feb 5, 2025

    @britta-wstnr
    Member

    Hi @contsili! Great to hear 🙌
    Don't hesitate to open a PR with snippets already, it's better to have early discussions on implementations (less work for you and the code reviewers! 🙂 ). You can open a PR in DRAFT mode to signal that this is not a fully-working implementation yet. Looking forward to it!

  22. larsoner commented on Feb 10, 2025

    @larsoner
    Member

    @contsili #13044 is in so you should be good to go!

  23. added this to the 1.10 milestone on Feb 10, 2025
  24. modified the milestones: 1.10, 1.11 on Jun 26, 2025
  25. removed this from the 1.11 milestone on Nov 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions