mne-tools / mne-tools/mne-python

Numerical warnings from `optical_density` / `temporal_derivative_distribution_repair` on channels in `info["bads"]`

Open
#14,318 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

ENH
Dominant language
Python
Stars
3.5k
Forks
1.6k
Avg merge
1d 6h
Merged PRs (30d)
100

Description

Describe the new feature or enhancement

Description

mne.preprocessing.nirs.optical_density and mne.preprocessing.nirs.temporal_derivative_distribution_repair are applied to channels marked as 'bad' (intentionally).
The side effect is that garbage in a 'bad' channel warns without naming it:

_optical_density.py:49: RuntimeWarning: divide by zero encountered in log
_tddr.py:97: RuntimeWarning: invalid value encountered in subtract

So users cannot tell whether the data is about to be discarded anyways or is a real problem
in a channel they keep.

Reproduction

import warnings
import numpy as np
import mne

info = mne.create_info(["S1_D1 760", "S1_D1 850", "S2_D2 760", "S2_D2 850"], 10.0,
                       "fnirs_cw_amplitude")
for ch in info["chs"]:
    ch["loc"][6:9] = [0.03, 0.0, 0.0]
    ch["loc"][9] = float(ch["ch_name"].split()[1])

data = np.random.default_rng(0).normal(1e5, 1e3, (4, 1000))
data[2, 500], data[2, 501] = -6.6e245, 8.0e-304  # corrupt samples, channel already bad
info["bads"] = ["S2_D2 760", "S2_D2 850"]
raw = mne.io.RawArray(data, info, verbose=False)

with warnings.catch_warnings(record=True) as caught:
    warnings.simplefilter("always")
    od = mne.preprocessing.nirs.optical_density(raw, verbose=False)
    tddr = mne.preprocessing.nirs.temporal_derivative_distribution_repair(od, verbose=False)
print([str(w.message) for w in caught])
print("non-finite per channel:", (~np.isfinite(tddr.get_data())).sum(axis=1))
['Negative intensities encountered. Setting to abs(x)', 'divide by zero encountered in log',
 'invalid value encountered in subtract']
non-finite per channel: [   0    0 1000    0]
Describe your proposed implementation

Output the channel names which have bad values and let the user ignore them. This might be verbose in some cases.

Describe possible alternatives

Only warn if non-bad channels have invalid values. This does not add verbosity to the warning but might hide issues in cases where bad channels are still used.

Additional context

MNE 1.13.0.dev256+g51216abcb

I can implement if this makes sense to add.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the reproduction and inspect mne/preprocessing/nirs/_optical_density.py and _tddr.py, the files named by the warnings. Trace how channels in info["bads"] are handled during optical_density and temporal_derivative_distribution_repair. Done means warnings make the affected channel names clear and users can distinguish bad-channel artifacts from problems in retained data.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
data
Issue type
Feature
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
68/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.