Skip to content

ENH: Support TD data #11064

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

Draft
wants to merge 44 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
3f875d3
adding the new snirf data types to the constants
Zahra-M-Aghajan Aug 11, 2021
cc92adc
more places to add the data types and constants
Zahra-M-Aghajan Aug 11, 2021
0d2fe87
adding constants for the allowed dataTypeLabels for the processed dat…
Zahra-M-Aghajan Aug 11, 2021
21ecb90
updating the snirf reader to accept other data types: gated histogram…
Zahra-M-Aghajan Aug 11, 2021
4491064
setting the formatter line length
Zahra-M-Aghajan Aug 11, 2021
dbdcebc
the reordering of the channels does not make much sense, need to inquire
Zahra-M-Aghajan Aug 12, 2021
80de954
Merge remote-tracking branch 'upstream/main' into feature/TD-nirs_snirf
Zahra-M-Aghajan Aug 19, 2021
32c5496
Merge remote-tracking branch 'upstream/main' into feature/TD-nirs_snirf
larsoner Aug 21, 2022
a35822a
MAINT: Simpler with .item
larsoner Aug 21, 2022
c2c217c
WIP: Constants
larsoner Aug 21, 2022
ac52bc0
FIX: Flake
larsoner Aug 21, 2022
da275f1
FIX: Consistent
larsoner Aug 21, 2022
3986b96
FIX: Missed
larsoner Aug 21, 2022
ce8b3af
FIX: Better code
larsoner Aug 21, 2022
1244add
FIX: Scale
larsoner Aug 21, 2022
3944254
FIX: Missing
larsoner Aug 21, 2022
967dddd
FIX: Flake
larsoner Aug 21, 2022
e97367d
FIX: Syntax
larsoner Aug 21, 2022
4b963cd
Merge remote-tracking branch 'upstream/main' into feature/TD-nirs_snirf
larsoner Aug 23, 2022
15e2878
Merge remote-tracking branch 'upstream/main' into feature/TD-nirs_snirf
larsoner Mar 1, 2023
d26ff8a
FIX: shape
larsoner Mar 1, 2023
f84fe27
FIX: Slash
larsoner Mar 1, 2023
50f3064
FIX: Bad merge
larsoner Mar 1, 2023
495bdf7
Merge branch 'main' into feature/TD-nirs_snirf
larsoner Mar 2, 2023
a076e23
Merge remote-tracking branch 'upstream/main' into feature/TD-nirs_snirf
larsoner Mar 9, 2023
698d2a6
FIX: Add tests
larsoner Mar 9, 2023
d3b75ab
FIX: Reg
larsoner Mar 9, 2023
b1cf310
Merge branch 'main' into feature/TD-nirs_snirf
larsoner Mar 14, 2023
0c4f886
MAINT: Revert
larsoner Oct 28, 2024
34c36f5
Merge remote-tracking branch 'upstream/main' into feature/TD-nirs_snirf
larsoner Oct 28, 2024
b5e9967
Empty commit for credit
larsoner Oct 28, 2024
34dffbf
DOC: Change
larsoner Oct 28, 2024
d62dbb1
MAINT: Mailmap
larsoner Oct 28, 2024
880356e
FIX: SI
larsoner Oct 28, 2024
4f0e8e6
FIX: Oops
larsoner Oct 28, 2024
a5c97b8
FIX: Oops
larsoner Oct 28, 2024
fba1ffa
FIX: idx
larsoner Oct 28, 2024
9f4234d
WIP
larsoner Oct 28, 2024
b3b3f2e
FIX: Test
larsoner Oct 28, 2024
9723621
Merge remote-tracking branch 'upstream/main' into feature/TD-nirs_snirf
larsoner Oct 28, 2024
2b03f75
Merge remote-tracking branch 'upstream/main' into feature/TD-nirs_snirf
larsoner Apr 4, 2025
e9403d8
WIP: More constants
larsoner Apr 4, 2025
6ee5068
FIX: Caps
larsoner Apr 4, 2025
b2b3716
FIX: More
larsoner Apr 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .mailmap
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ Yousra Bekhti <[email protected]> Yoursa BEKHTI <[email protected]
Yousra Bekhti <[email protected]> Yoursa BEKHTI <[email protected]>
Yousra Bekhti <[email protected]> Yousra BEKHTI <[email protected]>
Yousra Bekhti <[email protected]> yousrabk <[email protected]>
Zahra M. Aghajan <[email protected]> Zahra M. Aghajan <[email protected]>
Zhi Zhang <[email protected]> ZHANG Zhi <[email protected]>
Zhi Zhang <[email protected]> ZHANG Zhi <[email protected]>
Ziyi ZENG <[email protected]> ZIYI ZENG <[email protected]>
1 change: 1 addition & 0 deletions doc/changes/devel/11064.newfeature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added basic support for TD fNIRS data, by :newcontrib:`Zahra Aghajan`, :newcontrib:`Julien Dubois`, :newcontrib:`John Griffiths`, `Robert Luke`_, and `Eric Larson`_.
3 changes: 3 additions & 0 deletions doc/changes/names.inc
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@
.. _Joan Massich: https://github.com/massich
.. _Johann Benerradi: https://github.com/HanBnrd
.. _Johannes Niediek: https://github.com/jniediek
.. _John Griffiths: https://www.grifflab.com
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JohnGriffiths @julien-dubois-k @Zahra-M-Aghajan let me know if you want a different URL to link from your name in the changelog

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

grifflab.com is perfect, thanks

.. _John Samuelsson: https://github.com/johnsam7
.. _John Veillette: https://psychology.uchicago.edu/directory/john-veillette
.. _Jon Houck: https://www.mrn.org/people/jon-m.-houck/principal-investigators
Expand All @@ -153,6 +154,7 @@
.. _Judy D Zhu: https://github.com/JD-Zhu
.. _Juergen Dammers: https://github.com/jdammers
.. _Jukka Nenonen: https://www.linkedin.com/pub/jukka-nenonen/28/b5a/684
.. _Julien Dubois: https://github.com/julien-dubois-k
.. _Jussi Nurminen: https://github.com/jjnurminen
.. _Kaisu Lankinen: http://bishoplab.berkeley.edu/Kaisu.html
.. _Katarina Slama: https://github.com/katarinaslama
Expand Down Expand Up @@ -324,6 +326,7 @@
.. _Yiping Zuo: https://github.com/frostime
.. _Yousra Bekhti: https://www.linkedin.com/pub/yousra-bekhti/56/886/421
.. _Yu-Han Luo: https://github.com/yh-luo
.. _Zahra Aghajan: https://github.com/Zahra-M-Aghajan
.. _Zhi Zhang: https://github.com/tczhangzhi/
.. _Ziyi ZENG: https://github.com/ZiyiTsang
.. _Zvi Baratz: https://github.com/ZviBaratz
1 change: 1 addition & 0 deletions environment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ dependencies:
- joblib
- jupyter
- lazy_loader >=0.3
- libxml2 !=2.14.0
- mamba
- matplotlib >=3.7
- mffpy >=0.5.7
Expand Down
8 changes: 6 additions & 2 deletions mne/_fiff/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -1044,7 +1044,9 @@
FIFF.FIFFV_COIL_FNIRS_FD_PHASE = 305 # fNIRS frequency domain phase
FIFF.FIFFV_COIL_FNIRS_RAW = FIFF.FIFFV_COIL_FNIRS_CW_AMPLITUDE # old alias
FIFF.FIFFV_COIL_FNIRS_TD_GATED_AMPLITUDE = 306 # fNIRS time-domain gated amplitude
FIFF.FIFFV_COIL_FNIRS_TD_MOMENTS_AMPLITUDE = 307 # fNIRS time-domain moments amplitude
FIFF.FIFFV_COIL_FNIRS_TD_MOMENTS_INTENSITY = 307 # fNIRS time-domain moments intensity
FIFF.FIFFV_COIL_FNIRS_TD_MOMENTS_MEAN = 308 # fNIRS time-domain moments mean
FIFF.FIFFV_COIL_FNIRS_TD_MOMENTS_VARIANCE = 309 # fNIRS time-domain moments variance

FIFF.FIFFV_COIL_EYETRACK_POS = 400 # Eye-tracking gaze position
FIFF.FIFFV_COIL_EYETRACK_PUPIL = 401 # Eye-tracking pupil size
Expand Down Expand Up @@ -1145,7 +1147,9 @@
FIFF.FIFFV_COIL_FNIRS_FD_AC_AMPLITUDE,
FIFF.FIFFV_COIL_FNIRS_FD_PHASE,
FIFF.FIFFV_COIL_FNIRS_TD_GATED_AMPLITUDE,
FIFF.FIFFV_COIL_FNIRS_TD_MOMENTS_AMPLITUDE,
FIFF.FIFFV_COIL_FNIRS_TD_MOMENTS_INTENSITY,
FIFF.FIFFV_COIL_FNIRS_TD_MOMENTS_MEAN,
FIFF.FIFFV_COIL_FNIRS_TD_MOMENTS_VARIANCE,
FIFF.FIFFV_COIL_MCG_42,
FIFF.FIFFV_COIL_EYETRACK_POS,
FIFF.FIFFV_COIL_EYETRACK_PUPIL,
Expand Down
54 changes: 53 additions & 1 deletion mne/_fiff/pick.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,26 @@ def get_channel_type_constants(include_defaults=False):
unit=FIFF.FIFF_UNIT_RAD,
coil_type=FIFF.FIFFV_COIL_FNIRS_FD_PHASE,
),
fnirs_td_gated_amplitude=dict(
kind=FIFF.FIFFV_FNIRS_CH,
unit=FIFF.FIFF_UNIT_V,
coil_type=FIFF.FIFFV_COIL_FNIRS_TD_GATED_AMPLITUDE,
),
fnirs_td_moments_intensity=dict(
kind=FIFF.FIFFV_FNIRS_CH,
unit=FIFF.FIFF_UNIT_UNITLESS,
coil_type=FIFF.FIFFV_COIL_FNIRS_TD_MOMENTS_INTENSITY,
),
fnirs_td_moments_mean=dict(
kind=FIFF.FIFFV_FNIRS_CH,
unit=FIFF.FIFF_UNIT_S,
coil_type=FIFF.FIFFV_COIL_FNIRS_TD_MOMENTS_MEAN,
),
fnirs_td_moments_variance=dict(
kind=FIFF.FIFFV_FNIRS_CH,
unit=FIFF.FIFF_UNIT_NONE, # TODO: Maybe someday add s^2
coil_type=FIFF.FIFFV_COIL_FNIRS_TD_MOMENTS_VARIANCE,
),
fnirs_od=dict(kind=FIFF.FIFFV_FNIRS_CH, coil_type=FIFF.FIFFV_COIL_FNIRS_OD),
hbo=dict(
kind=FIFF.FIFFV_FNIRS_CH,
Expand Down Expand Up @@ -197,6 +217,10 @@ def get_channel_type_constants(include_defaults=False):
FIFF.FIFFV_COIL_FNIRS_FD_AC_AMPLITUDE: "fnirs_fd_ac_amplitude",
FIFF.FIFFV_COIL_FNIRS_FD_PHASE: "fnirs_fd_phase",
FIFF.FIFFV_COIL_FNIRS_OD: "fnirs_od",
FIFF.FIFFV_COIL_FNIRS_TD_GATED_AMPLITUDE: "fnirs_td_gated_amplitude",
FIFF.FIFFV_COIL_FNIRS_TD_MOMENTS_INTENSITY: "fnirs_td_moments_intensity",
FIFF.FIFFV_COIL_FNIRS_TD_MOMENTS_MEAN: "fnirs_td_moments_mean",
FIFF.FIFFV_COIL_FNIRS_TD_MOMENTS_VARIANCE: "fnirs_td_moments_variance",
},
),
"eeg": (
Expand Down Expand Up @@ -385,6 +409,26 @@ def _triage_fnirs_pick(ch, fnirs, warned):
return True
elif ch["coil_type"] == FIFF.FIFFV_COIL_FNIRS_OD and "fnirs_od" in fnirs:
return True
elif (
ch["coil_type"] == FIFF.FIFFV_COIL_FNIRS_TD_GATED_AMPLITUDE
and "fnirs_td_gated_amplitude" in fnirs
):
return True
elif (
ch["coil_type"] == FIFF.FIFFV_COIL_FNIRS_TD_MOMENTS_INTENSITY
and "fnirs_td_moments_intensity" in fnirs
):
return True
elif (
ch["coil_type"] == FIFF.FIFFV_COIL_FNIRS_TD_MOMENTS_MEAN
and "fnirs_td_moments_mean" in fnirs
):
return True
elif (
ch["coil_type"] == FIFF.FIFFV_COIL_FNIRS_TD_MOMENTS_VARIANCE
and "fnirs_td_moments_variance" in fnirs
):
return True
return False


Expand Down Expand Up @@ -569,7 +613,7 @@ def pick_types(
pick[k] = _triage_meg_pick(info["chs"][k], ref_meg)
elif ch_type in ("eyegaze", "pupil"):
pick[k] = _triage_eyetrack_pick(info["chs"][k], eyetrack)
else: # ch_type in ('hbo', 'hbr')
else: # ch_type in ('hbo', 'hbr', ...)
pick[k] = _triage_fnirs_pick(info["chs"][k], fnirs, warned)

# restrict channels to selection if provided
Expand Down Expand Up @@ -862,6 +906,10 @@ def channel_indices_by_type(info, picks=None):
fnirs_fd_ac_amplitude=list(),
fnirs_fd_phase=list(),
fnirs_od=list(),
fnirs_td_gated_amplitude=list(),
fnirs_td_moments_intensity=list(),
fnirs_td_moments_mean=list(),
fnirs_td_moments_variance=list(),
eyegaze=list(),
pupil=list(),
)
Expand Down Expand Up @@ -1099,6 +1147,10 @@ def _check_excludes_includes(chs, info=None, allow_bads=False):
"fnirs_fd_ac_amplitude",
"fnirs_fd_phase",
"fnirs_od",
"fnirs_td_gated_amplitude",
"fnirs_td_moments_intensity",
"fnirs_td_moments_mean",
"fnirs_td_moments_variance",
)
_EYETRACK_CH_TYPES_SPLIT = ("eyegaze", "pupil")
_DATA_CH_TYPES_ORDER_DEFAULT = (
Expand Down
8 changes: 5 additions & 3 deletions mne/_fiff/tests/test_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
from mne.utils import requires_good_network

# https://github.com/mne-tools/fiff-constants/commits/master
REPO = "mne-tools"
COMMIT = "e27f68cbf74dbfc5193ad429cc77900a59475181"
REPO = "larsoner" # TODO: Replace with upstream once merged
COMMIT = "ba2288355b61b00d65d4f1d8a47ef82b83414201"

# These are oddities that we won't address:
iod_dups = (355, 359) # these are in both MEGIN and MNE files
Expand Down Expand Up @@ -91,7 +91,9 @@
304, # fNIRS frequency domain AC amplitude
305, # fNIRS frequency domain phase
306, # fNIRS time domain gated amplitude
307, # fNIRS time domain moments amplitude
307, # fNIRS time domain moments intensity
308, # fNIRS time domain moments mean
309, # fNIRS time domain moments variance
400, # Eye-tracking gaze position
401, # Eye-tracking pupil size
1000, # For testing the MCG software
Expand Down
35 changes: 35 additions & 0 deletions mne/cov.py
Original file line number Diff line number Diff line change
Expand Up @@ -1517,6 +1517,7 @@ def __init__(
grad=0.1,
mag=0.1,
eeg=0.1,
*,
seeg=0.1,
ecog=0.1,
hbo=0.1,
Expand All @@ -1525,6 +1526,10 @@ def __init__(
fnirs_fd_ac_amplitude=0.1,
fnirs_fd_phase=0.1,
fnirs_od=0.1,
fnirs_td_gated_amplitude=0.1,
fnirs_td_moments_intensity=0.1,
fnirs_td_moments_mean=0.1,
fnirs_td_moments_variance=0.1,
csd=0.1,
dbs=0.1,
store_precision=False,
Expand All @@ -1545,6 +1550,10 @@ def __init__(
self.fnirs_fd_ac_amplitude = fnirs_fd_ac_amplitude
self.fnirs_fd_phase = fnirs_fd_phase
self.fnirs_od = fnirs_od
self.fnirs_td_gated_amplitude = fnirs_td_gated_amplitude
self.fnirs_td_moments_intensity = fnirs_td_moments_intensity
self.fnirs_td_moments_mean = fnirs_td_moments_mean
self.fnirs_td_moments_variance = fnirs_td_moments_variance
self.csd = csd
self.store_precision = store_precision
self.assume_centered = assume_centered
Expand Down Expand Up @@ -1577,6 +1586,15 @@ def fit(self, X):
dbs=self.dbs,
hbo=self.hbo,
hbr=self.hbr,
fnirs_cw_amplitude=self.fnirs_cw_amplitude,
fnirs_fd_ac_amplitude=self.fnirs_fd_ac_amplitude,
fnirs_fd_phase=self.fnirs_fd_phase,
fnirs_od=self.fnirs_od,
fnirs_td_gated_amplitude=self.fnirs_td_gated_amplitude,
fnirs_td_moments_intensity=self.fnirs_td_moments_intensity,
fnirs_td_moments_mean=self.fnirs_td_moments_mean,
fnirs_td_moments_variance=self.fnirs_td_moments_variance,
csd=self.csd,
rank="full",
)
self.estimator_.covariance_ = self.covariance_ = cov_.data
Expand Down Expand Up @@ -1904,6 +1922,7 @@ def regularize(
eeg=0.1,
exclude="bads",
proj=True,
*,
seeg=0.1,
ecog=0.1,
hbo=0.1,
Expand All @@ -1912,6 +1931,10 @@ def regularize(
fnirs_fd_ac_amplitude=0.1,
fnirs_fd_phase=0.1,
fnirs_od=0.1,
fnirs_td_gated_amplitude=0.1,
fnirs_td_moments_intensity=0.1,
fnirs_td_moments_mean=0.1,
fnirs_td_moments_variance=0.1,
csd=0.1,
dbs=0.1,
rank=None,
Expand Down Expand Up @@ -1963,6 +1986,14 @@ def regularize(
Regularization factor for fNIRS raw phase signals.
fnirs_od : float (default 0.1)
Regularization factor for fNIRS optical density signals.
fnirs_td_gated_amplitude : float (default 0.1)
Regularization factor for fNIRS time domain gated amplitude signals.
fnirs_td_moments_intensity : float (default 0.1)
Regularization factor for fNIRS time domain moments amplitude signals.
fnirs_td_moments_mean : float (default 0.1)
Regularization factor for fNIRS time domain moments mean signals.
fnirs_td_moments_variance : float (default 0.1)
Regularization factor for fNIRS time domain moments variance signals.
csd : float (default 0.1)
Regularization factor for EEG-CSD signals.
dbs : float (default 0.1)
Expand Down Expand Up @@ -2003,6 +2034,10 @@ def regularize(
fnirs_fd_ac_amplitude=fnirs_fd_ac_amplitude,
fnirs_fd_phase=fnirs_fd_phase,
fnirs_od=fnirs_od,
fnirs_td_gated_amplitude=fnirs_td_gated_amplitude,
fnirs_td_moments_intensity=fnirs_td_moments_intensity,
fnirs_td_moments_mean=fnirs_td_moments_mean,
fnirs_td_moments_variance=fnirs_td_moments_variance,
csd=csd,
)

Expand Down
4 changes: 2 additions & 2 deletions mne/datasets/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@
# update the checksum in the MNE_DATASETS dict below, and change version
# here: ↓↓↓↓↓↓↓↓
RELEASES = dict(
testing="0.156",
testing="0.162",
misc="0.27",
phantom_kit="0.2",
ucl_opm_auditory="0.2",
Expand Down Expand Up @@ -115,7 +115,7 @@
# Testing and misc are at the top as they're updated most often
MNE_DATASETS["testing"] = dict(
archive_name=f"{TESTING_VERSIONED}.tar.gz",
hash="md5:d94fe9f3abe949a507eaeb865fb84a3f",
hash="md5:34d4f174adbb211ba58a584b6c1d348c",
url=(
"https://codeload.github.com/mne-tools/mne-testing-data/"
f"tar.gz/{RELEASES['testing']}"
Expand Down
24 changes: 24 additions & 0 deletions mne/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@
fnirs_fd_ac_amplitude="k",
fnirs_fd_phase="k",
fnirs_od="k",
fnirs_td_gated_amplitude="k",
fnirs_td_moments_intensity="k",
fnirs_td_moments_mean="k",
fnirs_td_moments_variance="k",
csd="k",
whitened="k",
gsr="#666633",
Expand Down Expand Up @@ -60,6 +64,10 @@
fnirs_fd_ac_amplitude="V",
fnirs_fd_phase="rad",
fnirs_od="V",
fnirs_td_gated_amplitude="AU", # counts
fnirs_td_moments_intensity="AU", # counts
fnirs_td_moments_mean="S",
fnirs_td_moments_variance="S²",
csd="V/m²",
whitened="Z",
gsr="S",
Expand Down Expand Up @@ -88,6 +96,10 @@
fnirs_fd_ac_amplitude="V",
fnirs_fd_phase="rad",
fnirs_od="V",
fnirs_td_gated_amplitude="AU",
fnirs_td_moments_intensity="AU",
fnirs_td_moments_mean="S",
fnirs_td_moments_variance="S²",
csd="mV/m²",
whitened="Z",
gsr="S",
Expand Down Expand Up @@ -117,6 +129,10 @@
fnirs_fd_ac_amplitude=1.0,
fnirs_fd_phase=1.0,
fnirs_od=1.0,
fnirs_td_gated_amplitude=1.0,
fnirs_td_moments_intensity=1.0,
fnirs_td_moments_mean=1.0,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the values are in the range of nanoseconds, so this should be 1e-9 for mean and 1e-18 for variance maybe?

fnirs_td_moments_variance=1.0,
csd=1e3,
whitened=1.0,
gsr=1.0,
Expand Down Expand Up @@ -151,6 +167,10 @@
fnirs_fd_ac_amplitude=2e-2,
fnirs_fd_phase=2e-1,
fnirs_od=2e-2,
fnirs_td_gated_amplitude=1.0,
fnirs_td_moments_intensity=1.0,
fnirs_td_moments_mean=1.0,
fnirs_td_moments_variance=1.0,
csd=200e-4,
dipole=1e-7,
gof=1e2,
Expand Down Expand Up @@ -206,6 +226,10 @@
fnirs_fd_phase="fNIRS (FD phase)",
fnirs_od="fNIRS (OD)",
hbr="Deoxyhemoglobin",
fnirs_td_gated_amplitude="fNIRS (TD amplitude)",
fnirs_td_moments_intensity="fNIRS (TD moment intensity)",
fnirs_td_moments_mean="fNIRS (TD moment mean)",
fnirs_td_moments_variance="fNIRS (TD moment variance)",
gof="Goodness of fit",
csd="Current source density",
stim="Stimulus",
Expand Down
Loading