Skip to content

ENH: Support for Multi-Wavelength (>2) NIRS/SNIRF Data Processing #13401

@zEdS15B3GCwq

Description

@zEdS15B3GCwq

Describe the new feature or enhancement

Goal: extend MNE-Python's NIRS processing to support an arbitrary number of wavelengths (≥2) instead of being limited (hard-coded in several places) to two.

The same idea has been raised in issue #9816 with the main difference that my issue is in preparation for a PR rather than a request. I'd like to discuss implementation details and to explore devs' opinion on how feasible such changes would be.

Please check the linked issue for additional information about why this would be a good idea. In short, (some) Shimadzu fNIRS devices work with 3 wavelengths, and in the future there might be other devices with more, but mne's SNIRF I/O and processing functions are coded to accept only 2 wavelengths.

From my perspective, these changes would be mostly beneficial as I'm using a Shimadzu device. While the device doesn't support .snirf output, there are ways to convert the data to that format. And while it's possible to preprocess and convert to Hb data first in some other tool(s) and then import to mne, it would be ideal to keep the entire processing pipeline to one tool.

Describe your proposed implementation

I've done some exploration in the codebase to identify relevant bits of code, both manually and with the help of Claude 4. Based on this, it seems that relevant parts of the code are in SNIRF I/O (mne.io.snirf) and NIRS preprocessing (mne.preprocessing.nirs). I'm sure some tests will need to be updated as well, but I haven't yet spent time on them.

I actually have a preliminary implementation of the described changes that you can see at my fork. That code is untested, but it should provide a general impression of the extent and complexity of required changes. Of course, tests will need to be added/updated in addition.

Major changes

  • Channel data structure: with 2 wavelengths, channel data is stored as ABAB... . All functions handling OD and amplitude data will need to be updated not to rely on a fixed [::2], [1::2] sequence. I listed this as a major change due to the difficulty of locating every function that works this way. Claude thinks it's been able to find all of them (see list of files to be changed below). It still requires devs' experience to know if there are some I might not have been able to find.
  • Beer-Lambert calculation (algorithmic change): The current implementation uses pseudo-inverse pinv() to calculate ΔOD = E × L × PPF × Δc. I think it's possible to update this with minimal changes, just changing the EL matrix to n x 2 where n is the number of wavelengths, instead of the current 2 x 2. After Beer-Lambert, excess channels will need to be dropped.
  • Scalp coupling index (algorithmic change): I'm not aware of any reports where SCI was defined for >2 wavelengths. My idea here is to calculate all possible pairs of correlation, and use the minimum value. Intuitively, this should be correct as all wavelength channels should be correlated.

I'm hoping to receive feedback on the correctness of the above proposed algorithmic changes. For n=2 wavelengths, the new calculation methods wouldn't introduce any new changes (E in Beer-Lambert would still be 2x2, and there is only one correlation pair so the minimum is irrelevant), and if necessary, the current implementation could be preserved in a separate code path.

Minor changes

  • SNIRF file reading: checks and validation steps need to be updated. While there's a number of validation checks, the overall complexity of the code changes isn't high.

List of affected files and functions:

Describe possible alternatives

The algorithmic changes (Beer-Lambert and SCI) could be implemented in another way. The Beer-Lambert pseudo-inverse should work with n>2 with minimal changes and the change seems mathematically correct. The SCI calculation using the minumum of all correlations appers to be the most conservative in terms of being able to spot any coupling issues, but without studies to rely on, it should be discussed.

Additional context

The project mne-python will also require some changes, which will I will discuss in another issue opened there.

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