{ "cells": [ { "cell_type": "markdown", "id": "4c4b24eb", "metadata": { "lines_to_next_cell": 0, "pycharm": { "name": "#%% md\n" } }, "source": [ "# *(Jansen & Rit, 1995)*: Jansen-Rit Model\n", "\n", "[![Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/brainpy/examples/blob/main/neurons/JR_1995_jansen_rit_model.ipynb)\n", "[![Open in Kaggle](https://kaggle.com/static/images/open-in-kaggle.svg)](https://kaggle.com/kernels/welcome?src=https://github.com/brainpy/examples/blob/main/neurons/JR_1995_jansen_rit_model.ipyn)" ] }, { "cell_type": "markdown", "id": "c37e4fad", "metadata": { "pycharm": { "name": "#%% md\n" } }, "source": [ "The Jansen-Rit model, a neural mass model of the dynamic interactions between 3 populations:\n", "\n", "- pyramidal cells (PCs)\n", "- excitatory interneurons (EINs)\n", "- inhibitory interneurons (IINs)\n", "\n", "Originally, the model has been developed to describe the waxing-and-waning\n", "of EEG activity in the alpha frequency range (8-12 Hz) in the visual cortex [1].\n", "In the past years, however, it has been used as a generic model to describe\n", "the macroscopic electrophysiological activity within a cortical column [2].\n", "\n", "By using the linearity of the convolution operation, the dynamic interactions between PCs, EINs and IINs can be\n", "expressed via 6 coupled ordinary differential equations that are composed of the two operators defined above:\n", "\n", "$$\n", "\\begin{aligned}\n", "\\dot V_{pce} &= I_{pce}, \\\\\n", "\\dot I_{pce} &= \\frac{H_e}{\\tau_e} c_4 S(c_3 V_{in}) - \\frac{2 I_{pce}}{\\tau_e} - \\frac{V_{pce}}{\\tau_e^2}, \\\\\n", "\\dot V_{pci} &= I_{pci}, \\\\\n", "\\dot I_{pci} &= \\frac{H_i}{\\tau_i} c_2 S(c_1 V_{in}) - \\frac{2 I_{pci}}{\\tau_i} - \\frac{V_{pci}}{\\tau_i^2}, \\\\\n", "\\dot V_{in} &= I_{in}, \\\\\n", "\\dot I_{in} &= \\frac{H_e}{\\tau_e} S(V_{pce} - V_{pci}) - \\frac{2 I_{in}}{\\tau_e} - \\frac{V_{in}}{\\tau_e^2},\n", "\\end{aligned}\n", "$$\n", "\n", "where $V_{pce}$, $V_{pci}$, $V_{in}$ are used to represent the average membrane potential\n", "deflection caused by the excitatory synapses at the PC population, the inhibitory synapses at the PC\n", "population, and the excitatory synapses at both interneuron populations, respectively.\n", "\n", "- [1] B.H. Jansen & V.G. Rit (1995) Electroencephalogram and visual evoked potential generation in a mathematical model of coupled cortical columns. Biological Cybernetics, 73(4): 357-366.\n", " \n", "- [2] A. Spiegler, S.J. Kiebel, F.M. Atay, T.R. Knösche (2010) Bifurcation analysis of neural mass models: Impact of extrinsic inputs and dendritic time constants. NeuroImage, 52(3): 1041-1058, https://doi.org/10.1016/j.neuroimage.2009.12.081." ] }, { "cell_type": "code", "execution_count": 1, "id": "7e88603f", "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "import brainpy as bp\n", "import brainpy.math as bm" ] }, { "cell_type": "code", "execution_count": 2, "id": "8b4c32f4", "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "class JansenRitModel(bp.DynamicalSystem):\n", " def __init__(self, num, C=135., method='exp_auto'):\n", " super(JansenRitModel, self).__init__()\n", "\n", " self.num = num\n", "\n", " # parameters #\n", " self.v_max = 5. # maximum firing rate\n", " self.v0 = 6. # firing threshold\n", " self.r = 0.56 # slope of the sigmoid\n", " # other parameters\n", " self.A = 3.25\n", " self.B = 22.\n", " self.a = 100.\n", " self.tau_e = 0.01 # second\n", " self.tau_i = 0.02 # second\n", " self.b = 50.\n", " self.e0 = 2.5\n", " # The connectivity constants\n", " self.C1 = C\n", " self.C2 = 0.8 * C\n", " self.C3 = 0.25 * C\n", " self.C4 = 0.25 * C\n", "\n", " # variables #\n", " # y0, y1 and y2 representing the firing rate of\n", " # pyramidal, excitatory and inhibitory neurones.\n", " self.y0 = bm.Variable(bm.zeros(self.num))\n", " self.y1 = bm.Variable(bm.zeros(self.num))\n", " self.y2 = bm.Variable(bm.zeros(self.num))\n", " self.y3 = bm.Variable(bm.zeros(self.num))\n", " self.y4 = bm.Variable(bm.zeros(self.num))\n", " self.y5 = bm.Variable(bm.zeros(self.num))\n", " self.p = bm.Variable(bm.ones(self.num) * 220.)\n", "\n", " # integral function\n", " self.derivative = bp.JointEq([self.dy0, self.dy1, self.dy2, self.dy3, self.dy4, self.dy5])\n", " self.integral = bp.odeint(self.derivative, method=method)\n", "\n", " def sigmoid(self, x):\n", " return self.v_max / (1. + bm.exp(self.r * (self.v0 - x)))\n", "\n", " def dy0(self, y0, t, y3): return y3\n", "\n", " def dy1(self, y1, t, y4): return y4\n", "\n", " def dy2(self, y2, t, y5): return y5\n", "\n", " def dy3(self, y3, t, y0, y1, y2):\n", " return (self.A * self.sigmoid(y1 - y2) - 2 * y3 - y0 / self.tau_e) / self.tau_e\n", "\n", " def dy4(self, y4, t, y0, y1, p):\n", " return (self.A * (p + self.C2 * self.sigmoid(self.C1 * y0)) - 2 * y4 - y1 / self.tau_e) / self.tau_e\n", "\n", " def dy5(self, y5, t, y0, y2):\n", " return (self.B * self.C4 * self.sigmoid(self.C3 * y0) - 2 * y5 - y2 / self.tau_i) / self.tau_i\n", "\n", " def update(self, tdi):\n", " self.y0.value, self.y1.value, self.y2.value, self.y3.value, self.y4.value, self.y5.value = \\\n", " self.integral(self.y0, self.y1, self.y2, self.y3, self.y4, self.y5, tdi.t, p=self.p, dt=tdi.dt)" ] }, { "cell_type": "code", "execution_count": 3, "id": "fcaa14b2", "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [], "source": [ "def simulation(duration=5.):\n", " dt = 0.1 / 1e3\n", " # random input uniformly distributed between 120 and 320 pulses per second\n", " all_ps = bm.random.uniform(120, 320, size=(int(duration / dt), 1))\n", " jrm = JansenRitModel(num=6, C=bm.array([68., 128., 135., 270., 675., 1350.]))\n", " runner = bp.DSRunner(jrm,\n", " monitors=['y0', 'y1', 'y2', 'y3', 'y4', 'y5'],\n", " inputs=['p', all_ps, 'iter', '='],\n", " dt=dt)\n", " runner.run(duration)\n", "\n", " start, end = int(2 / dt), int(duration / dt)\n", " fig, gs = bp.visualize.get_figure(6, 3, 2, 3)\n", " for i in range(6):\n", " fig.add_subplot(gs[i, 0])\n", " title = 'E' if i == 0 else None\n", " xlabel = 'time [s]' if i == 5 else None\n", " bp.visualize.line_plot(runner.mon.ts[start: end], runner.mon.y1[start: end, i],\n", " title=title, xlabel=xlabel, ylabel='Hz')\n", " fig.add_subplot(gs[i, 1])\n", " title = 'P' if i == 0 else None\n", " bp.visualize.line_plot(runner.mon.ts[start: end], runner.mon.y0[start: end, i],\n", " title=title, xlabel=xlabel)\n", " fig.add_subplot(gs[i, 2])\n", " title = 'I' if i == 0 else None\n", " bp.visualize.line_plot(runner.mon.ts[start: end], runner.mon.y2[start: end, i],\n", " title=title, show=i==5, xlabel=xlabel)" ] }, { "cell_type": "code", "execution_count": 4, "id": "1f531829", "metadata": { "pycharm": { "name": "#%%\n" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "WARNING:jax._src.lib.xla_bridge:No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "aaf4c909356b4326a687dd176b8b3d5d", "version_major": 2, "version_minor": 0 }, "text/plain": [ " 0%| | 0/50000 [00:00" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "simulation()" ] } ], "metadata": { "jupytext": { "cell_metadata_filter": "-all", "encoding": "# -*- coding: utf-8 -*-", "formats": "ipynb,auto:percent", "notebook_metadata_filter": "-all" }, "kernelspec": { "display_name": "brainpy", "language": "python", "name": "brainpy" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.12" }, "latex_envs": { "LaTeX_envs_menu_present": true, "autoclose": false, "autocomplete": true, "bibliofile": "biblio.bib", "cite_by": "apalike", "current_citInitial": 1, "eqLabelWithNumbers": true, "eqNumInitial": 1, "hotkeys": { "equation": "Ctrl-E", "itemize": "Ctrl-I" }, "labels_anchors": false, "latex_user_defs": false, "report_style_numbering": false, "user_envs_cfg": false }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": false } }, "nbformat": 4, "nbformat_minor": 5 }