刺激#

本部分将介绍如何生成刺激并将刺激应用到数字孪生脑仿真中。刺激是一个关于时间的函数,任意时刻的刺激值将按照空间分布作用到某空间(如图谱所定义的脑区空间)。Stimulus是定义刺激的基类,继承该类并实现make_time_func函数即可自定义刺激。在刺激模块中,已经实现了一些类以快速生成常用的刺激。

使用内置类生成刺激#

(单)脉冲刺激#

PulseStimulus用于生成具有单个脉冲的刺激。

# 从API中导入脉冲刺激类
from zjb.main.api import PulseStimulus
from matplotlib import pyplot as plt

# 实例化一个脉冲刺激,脉冲强度为10, 起始时间4, 脉冲宽度2
stimulus = PulseStimulus(amp=10, start=4, width=2)
# 获取生成刺激的函数,该函数的输入为时间,输出为该时刻的刺激强度
func = stimulus.numba_func
# 创建间隔0.1,100个时间点的列表
ts = [0.1 * i for i in range(100)]
# 计算每个时刻的刺激值
ss = [func(t) for t in ts]
# 绘制刺激
plt.plot(ts, ss)
plt.show()
../_images/7d8f70debe1536785dc48fa7b078d08b24cec0bd5658aef9fe6224886b28033e.png

备注

脉冲包含起始时刻,不包含终止时刻。例如起始时刻为1, 宽度为1的刺激,脉冲时间为大于等于1,小于2

备注

每次获取刺激实例的numba_func时都可能会生成新的Numba函数。因此在不修改实例参数的情况下,不要多次调用stimulus.numba_func,这可能会产生极大的编译开销。内置的刺激类大多实现了numba_func属性的缓存,在不修改参数的情况下不会生成新的Numba函数,但仍然建议不要多次调用stimulus.numba_func

N周期脉冲刺激#

NCyclePulseStimulus用于生成具有多个(固定周期)脉冲的刺激

from zjb.main.api import NCyclePulseStimulus
from matplotlib import pyplot as plt

# 实例化一个连续的周期脉冲刺激,脉冲强度为10, 起始时刻为10,脉冲宽度为1, 脉冲周期为2
stimulus = NCyclePulseStimulus(amp=10, start=10, width=1, period=2, count=0)
func = stimulus.numba_func

ts = [0.1 * i for i in range(200)]
ss = [func(t) for t in ts]

plt.plot(ts, ss)
plt.show()
../_images/abbbc97426c75f1c44298d9b7cf6c269e543fb0d4b1bcce710d527b31ad2136b.png

自定义脉冲刺激#

CustomPulseStimulus用于生成由多个任意形状的脉冲组成的自定义脉冲刺激,其中每个自定义脉冲包括起始时间,终止时间和脉冲强度三个参数构成。

from zjb.main.api import CustomPulseStimulus
from matplotlib import pyplot as plt

# 实例化一个由3个脉冲组成的自定义脉冲刺激
stimulus = CustomPulseStimulus(series=[[1, 3, 1], [4, 5, 2], [0.5, 9.5, 0.1]])
func = stimulus.numba_func

ts = [0.1 * i for i in range(100)]
ss = [func(t) for t in ts]

plt.plot(ts, ss)
plt.show()
../_images/91974960e3e2cbe6e51eb3018fdd527c3bace38ba5ed4577fe360a5f7dd6880f.png

正弦刺激#

SinusoidStimulus用于生成形如\(amp * \sin(2 \pi * freq * t + phase) + offset\)的正弦刺激。

from zjb.main.api import SinusoidStimulus
from matplotlib import pyplot as plt

stimulus = SinusoidStimulus(amp=2, freq=0.5, phase=0, offset=0)
func = stimulus.numba_func

ts = [0.1 * i for i in range(100)]
ss = [func(t) for t in ts]

plt.plot(ts, ss)
plt.show()
../_images/35e5952eea6a253b07fc65e633719ee32833512e9a47a83f8ea6ba487be37dd4.png

高斯刺激#

GaussianStimulus用于生成形如\(amp * \exp(- \left(x - \mu\right) ^ 2 / \left(2 \sigma^2\right)) + offset\)的钟形刺激。

from zjb.main.api import GaussianStimulus
from matplotlib import pyplot as plt

stimulus = GaussianStimulus(amp=2, mu=5, sigma=0.5, offset=0)
func = stimulus.numba_func

ts = [0.1 * i for i in range(100)]
ss = [func(t) for t in ts]

plt.plot(ts, ss)
plt.show()
../_images/b9962492c83b0249cd75c0fed2f39ff2e8891a1b7da3e17f6e4b69cc1af72655.png

空间异质的刺激#

以上生成的刺激都是标量值,但是所有的刺激实例都可以通过设置刺激实例的space属性为空间分布的向量值,生成具有空间异质性的向量刺激。

from zjb.main.api import PulseStimulus
from matplotlib import pyplot as plt

stimulus = PulseStimulus(space=[0, 0.5, 1], amp=10, start=4, width=2)
func = stimulus.numba_func

ts = [0.1 * i for i in range(100)]
ss = [func(t) for t in ts]

plt.plot(ts, ss)
plt.show()
../_images/b7df0037cf345ba46cb982ed4b329d4808521a75d64934186b634adb8d230c8b.png

在数字孪生脑仿真中使用刺激#

数字孪生脑模型与数字孪生脑的参数值都支持设置为刺激实例,至少可以在3处设置参数值为刺激,根据实际情况选择其一即可。

from zjb.main.api import (
    DynamicsModel,
    DTBModel,
    Subject,
    DTB,
    RegionalConnectivity,
    Atlas,
    Raw,
    EulerSolver,
    NCyclePulseStimulus,
)
from matplotlib import pyplot as plt

dynamics = DynamicsModel.from_name("ReducedWongWangExcInh")
atlas = Atlas(labels=["1"])

stimulus = NCyclePulseStimulus(amp=0.05, start=100, width=20, period=200)
model = DTBModel(
    dynamics=dynamics,
    atlas=atlas,
    solver=EulerSolver(noises={"S_e": 0.005, "S_i": 0.005}),
    monitors=[Raw(expression="r_e")],
    parameters={"I_ext": stimulus},  # 1. 在数字孪生脑模型中设置I_ext为脉冲刺激
)
conn = RegionalConnectivity(data=[[0.0]], space=atlas.space)
subject = Subject(data={"SC": conn})
dtb = DTB(
    subject=subject,
    model=model,
    connectivity=conn,
    # parameters={"I_ext": stimulus},  # 2. 在数字孪生脑中设置I_ext为脉冲刺激
)

result = dtb.simulate(
    t=1000,
    # dynamic_parameters={"I_ext": stimulus}, # 3. 在仿真时设置I_ext为脉冲刺激
)
ts = result.data[0]
plt.plot(ts.data)
plt.show()
../_images/edefea15bbc3c9981afbf9469d78434b57348f3970537d1d358f97333669a282.png

自定义刺激类#

当内置的刺激不满足需求时,可以通过自定义刺激类来实现具有任意时间模式的刺激,只需要实现一个make_time_func函数即可。

from numba import njit
from zjb.main.api import Stimulus
from matplotlib import pyplot as plt


class MyStimulus(Stimulus):
    def make_time_func(self):
        @njit(inline="always")
        def func(t):
            # 在这里实现自定义的刺激值关于时间的函数
            return t % 1

        return func


# 自定义的刺激也可以使用`space`属性设置异质的空间分布
stimulus = MyStimulus(space=[0, 0.1, 1])
func = stimulus.numba_func

ts = [0.1 * i for i in range(100)]
ss = [func(t) for t in ts]

plt.plot(ts, ss)
plt.show()
../_images/9fdea33ec328ed6cb3289a4f9a6d3efb332e4aec1e15ed1c965463d87de48f4b.png