Source code for mne.preprocessing.nirs._scalp_coupling_index
# Authors: The MNE-Python contributors.
# License: BSD-3-Clause
# Copyright the MNE-Python contributors.
import numpy as np
from ...io import BaseRaw
from ...utils import _validate_type, _verbose_safe_false, verbose_static
from ..nirs import _channel_frequencies, _validate_nirs_info
[docs]
@verbose_static("l_freq", "h_freq", "l_trans_bandwidth", "h_trans_bandwidth")
def scalp_coupling_index(
raw,
l_freq=0.7,
h_freq=1.5,
l_trans_bandwidth=0.3,
h_trans_bandwidth=0.3,
verbose=None,
):
r"""Calculate scalp coupling index.
This function calculates the scalp coupling index
:footcite:`pollonini2014auditory`. This is a measure of the quality of the
connection between the optode and the scalp.
Parameters
----------
raw : instance of Raw
The raw data.
l_freq : float | None
For FIR filters, the lower pass-band edge; for IIR filters, the lower
cutoff frequency. If None the data are only low-passed.
h_freq : float | None
For FIR filters, the upper pass-band edge; for IIR filters, the upper
cutoff frequency. If None the data are only high-passed.
l_trans_bandwidth : float | str
Width of the transition band at the low cut-off frequency in Hz
(high pass or cutoff 1 in bandpass). Can be "auto"
(default) to use a multiple of ``l_freq``::
min(max(l_freq * 0.25, 2), l_freq)
Only used for ``method='fir'``.
h_trans_bandwidth : float | str
Width of the transition band at the high cut-off frequency in Hz
(low pass or cutoff 2 in bandpass). Can be "auto"
(default in 0.14) to use a multiple of ``h_freq``::
min(max(h_freq * 0.25, 2.), info['sfreq'] / 2. - h_freq)
Only used for ``method='fir'``.
verbose : bool | str | int | None
Control verbosity of the logging output. If ``None``, use the default
verbosity level. See the :ref:`logging documentation <tut-logging>` and
:func:`mne.verbose` for details. Should only be passed as a keyword
argument.
Returns
-------
sci : array of float
Array containing scalp coupling index for each channel.
References
----------
.. footbibliography::
"""
_validate_type(raw, BaseRaw, "raw")
picks = _validate_nirs_info(raw.info, fnirs="od", which="Scalp coupling index")
raw = raw.copy().pick(picks).load_data()
zero_mask = np.std(raw._data, axis=-1) == 0
filtered_data = raw.filter(
l_freq,
h_freq,
l_trans_bandwidth=l_trans_bandwidth,
h_trans_bandwidth=h_trans_bandwidth,
verbose=_verbose_safe_false(),
).get_data()
# Determine number of wavelengths per source-detector pair
# We use nominal wavelengths as the info structure may contain arbitrary data.
freqs = _channel_frequencies(raw.info)
n_wavelengths = len(np.unique(freqs))
sci = np.zeros(picks.shape)
# Calculate all pairwise correlations within each group and use the minimum as SCI
pair_indices = np.triu_indices(n_wavelengths, k=1)
for gg in range(0, len(picks), n_wavelengths):
group_data = filtered_data[gg : gg + n_wavelengths]
# Calculate pairwise correlations within the group
correlations = np.zeros(pair_indices[0].shape[0])
for n, (ii, jj) in enumerate(zip(*pair_indices)):
with np.errstate(invalid="ignore"):
c = np.corrcoef(group_data[ii], group_data[jj])[0][1]
if np.isfinite(c):
correlations[n] = c
# Use minimum correlation as SCI
group_sci = correlations.min()
# Assign the same SCI value to all channels in the group
sci[gg : gg + n_wavelengths] = group_sci
sci[zero_mask] = 0
sci = sci[np.argsort(picks)] # restore original order
return sci