源估计,通常称为 STC (Source Time Courses),是信号源定位的一种。源定位方法解决了所谓的逆问题。MNE提供了不同的求解方法:dSPM、sLORETA、LCMV、MxNE等。
源定位包括将EEG/MEG传感器数据投射到位于个体受试者大脑解剖结构中的三维“源空间”中。因此,源估计的定义就是:对数据进行转换,使每个传感器位置记录的时间序列映射到“源空间”的每个空间位置的时间序列。
STC对象包含源随时间的振幅。它只存储某个大脑活动的振幅,而不存储源的位置。为了访问这些位置,你需要使用源空间(通常缩写为src
)来计算正算子(通常缩写为fwd
)。
源估计有不同的形式:
mne.SourceEstimate
: 用于仅在皮质的源空间
mne.VolSourceEstimate
: 用于体积源空间
mne.VectorSourceEstimate
: 用于具有矢量值(强度和方向)源激活的仅在皮质的源空间
mne.MixedSourceEstimate
: 用于皮约束源和体积源组合形成的源空间。
SourceEstimate
是一个向量,主要与FreeSurfer的表面展示(surface representations)一起使用。
让我们来了解一下mne.SourceEstimate
。首先设置环境并加载一些数据:
from mne import read_source_estimate
from mne.datasets import sample
print(__doc__)
# Paths to example data
sample_dir_raw = sample.data_path()
sample_dir = sample_dir_raw / "MEG" / "sample"
subjects_dir = sample_dir_raw / "subjects"
fname_stc = sample_dir / "sample_audvis-meg"
该数据集包含来自音视频任务的源估计数据。利用dSPM方法将其映射到FreeSurfer得到的膨胀皮层表面表征上。它突出了听觉皮层的一个明显峰值。
让我们看看这个峰值长什么样。
stc = read_source_estimate(fname_stc, subject="sample")
# Define plotting parameters
surfer_kwargs = dict(
hemi="lh",
subjects_dir=subjects_dir,
clim=dict(kind="value", lims=[8, 12, 15]),
views="lateral",
initial_time=0.09,
time_unit="s",
size=(800, 800),
smoothing_steps=5,
)
# Plot surface
brain = stc.plot(**surfer_kwargs)
# Add title
brain.add_text(0.1, 0.9, "SourceEstimate", "title", font_size=16)
前面说了,源估计是由源空间stc定义的空间位置上的时间序列。在FreeSurfer曲面(由3D三角剖分组成)的背景下,我们可以将膨胀脑表征(inflated brain representation)上的每个数据点称为顶点vertex。如果每个顶点都表示时间序列的空间位置,那么时间序列和空间位置可以写成一个矩阵,矩阵中的每个顶点(行)在多个时间点(列)都可以赋值。这个值是我们的信号在给定的空间和时间点的强度。正是这个矩阵存储在stc.data
中。
让我们看一下shape:
shape = stc.data.shape
print(f"The data has {shape} vertex locations with {shape} sample points each.")
The data has (7498, 25) vertex locations with (7498, 25) sample points each.
我们看到stc携带了长度为25个采样长度的共7498个时间序列。这些时间序列属于7498个顶点,这些顶点依次表示皮层表面的位置。那么这些顶点值是从哪里来的呢?
FreeSurfer将两个半球分开,并创建左半球和右半球的表面表示。曲面位置的索引存储在stc.vertices
中。这是一个包含两个整数数组的列表,索引FreeSurfer网格的一个特定顶点。因此,一个为42的值将映射到索引为42的网格的x,y,z坐标上。
由于两个半球总是分开表示的,因此上述引入的两种属性也可以通过选择各自的半球得到。这是通过添加正确的前缀(lh或rh)来完成的。
shape_lh = stc.lh_data.shape
print(
f"The left hemisphere has {shape_lh} vertex locations with {shape_lh} sample points"
" each."
)
The left hemisphere has (3732, 25) vertex locations with (3732, 25) sample points each.
我们看到,矩阵的行大小发生了变化。我们可以检查一下stc的行数,用stc.lh_data
和 stc.rh_data
。
is_equal = stc.lh_data.shape[0] + stc.rh_data.shape[0] == stc.data.shape[0]
print(
"The number of vertices in stc.lh_data and stc.rh_data do "
+ ("not " if not is_equal else "")
+ "sum up to the number of rows in stc.data"
)
The number of vertices in stc.lh_data and stc.rh_data do sum up to the number of rows in stc.data
结果显而易见。
如上所述,src
是一个stc映射到表面的映射,承载了攻坚信息。“表面”是什么呢?表面由每个半球的三角网格构成,组成一个面的每个三角形由3个顶点组成。由于src
是左半球和右半球两个源空间的列表,我们可以通过首先选择源空间来访问各自的数据。左半球可以通过src[0]['tris']
访问,其中索引0和1代表左和右半球。
src[0][' tris ']
中的值引用src[0]['rr']
中的行索引。这里我们找到了曲面网格的实际坐标。顶点的每个行索引值都会从这里选择一个坐标。此外,src[0]['vertno']
存储与stc.lh_vertno
,相同的数据。除非使用如mne.inverse_sparse.mixed_norm()
的稀疏求解器,因为只有一小部分顶点实际上具有非零激活值。
换句话说,就是stc.lh_vertno
等于src[0]['vertno']
,而stc.rh_vertno
等于src[1]['vertno']
。stc中的第n个时间序列stc.lh_data
对应于stc.lh_vertno
中的第n个值。
让我们获得数据的峰值幅度作为顶点和时间点索引。
peak_vertex, peak_time = stc.get_peak(hemi="lh", vert_as_index=True, time_as_index=True)
第一个值表示哪个顶点,第二个值表示stc.lh_vertno
或stc.lh_data
中的哪个时间点索引。我们可以利用它们各自的信息来得到与峰值近似的曲面顶点的索引及其值。
peak_vertex_surf = stc.lh_vertno[peak_vertex]
peak_value = stc.lh_data[peak_vertex, peak_time]
可视化:
brain = stc.plot(**surfer_kwargs)
# We add the new peak coordinate (as vertex index) as an annotation dot
brain.add_foci(peak_vertex_surf, coords_as_verts=True, hemi="lh", color="blue")
# We add a title as well, stating the amplitude at this time and location
brain.add_text(0.1, 0.9, "Peak coordinate", "title", font_size=14)
stc
是MNE-Python的一个类,表示从源估计中获得的转换的时间序列。对于两个半球,数据分别存储在stc.lh_data
和stc.rh_data
中,储存形式为的形式为一个m*n的矩阵,m是这个半球的空间位置的数量,n是时间点的个数。
stc.lh_vertno
和 stc.rh_vertno
对应 src[0]['vertno']
和 src[1]['vertno']
。这些是表面表征的位置索引。
表面的坐标存储在src[0]['rr']
和src[1]['rr']
中,分别表示左半球和右半球。3D坐标可以通过下述逻辑访问:
lh_coordinates = src[0]['rr'][stc.lh_vertno]
lh_data = stc.lh_data
或:
lh_coordinates = src[0]['rr'][stc.lh_vertno]
lh_data = stc.lh_data