/
_scalp_coupling_index.py
67 lines (55 loc) · 1.95 KB
/
_scalp_coupling_index.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# Authors: Robert Luke <mail@robertluke.net>
# Eric Larson <larson.eric.d@gmail.com>
# Alexandre Gramfort <alexandre.gramfort@inria.fr>
#
# License: BSD-3-Clause
import numpy as np
from ...io import BaseRaw
from ...utils import _validate_type, verbose
from ..nirs import _channel_frequencies, _check_channels_ordered
@verbose
def scalp_coupling_index(raw, l_freq=0.7, h_freq=1.5,
l_trans_bandwidth=0.3, h_trans_bandwidth=0.3,
verbose=False):
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)s
%(h_freq)s
%(l_trans_bandwidth)s
%(h_trans_bandwidth)s
%(verbose)s
Returns
-------
sci : array of float
Array containing scalp coupling index for each channel.
References
----------
.. footbibliography::
"""
_validate_type(raw, BaseRaw, 'raw')
if 'fnirs_od' not in raw:
raise RuntimeError(
'Scalp coupling index should be run on optical density data.')
freqs = np.unique(_channel_frequencies(raw.info, nominal=True))
picks = _check_channels_ordered(raw.info, freqs)
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).get_data()
sci = np.zeros(picks.shape)
for ii in range(0, len(picks), 2):
with np.errstate(invalid='ignore'):
c = np.corrcoef(filtered_data[ii], filtered_data[ii + 1])[0][1]
if not np.isfinite(c): # someone had std=0
c = 0
sci[ii] = c
sci[ii + 1] = c
sci[zero_mask] = 0
return sci