Contact
CoCalc Logo Icon
StoreFeaturesDocsShareSupport News AboutSign UpSign In
| Download

Aulas do Curso de Modelagem matemática IV da FGV-EMAp

Views: 2412
License: GPL3
Image: default
Kernel: SageMath 9.3

Modelo de Fitzhugh-Nagumo

%display typeset

O modelo de Fitzhugh Nagumo é um elegante modelo de um sistema excitável. Históricamente foi desenvolvido de um esforço por simplificar o modelo original de Hodgkin-Huxley mantendo suas propriedades dinâmicas intactas. Mas este modelo é um ponto de partida para o estudo do fenômeno da excitabilidade que, sendo bastante comum em biologia, não se restringe à eletrofisiologia dos neurônios.

Computador analógico usado por Richard Fitzhugh.

Richard Fitzhugh com o computador analógico usado para calcular o modelo.

O que é excitabilidade? 

Um sistema excitável pode ser descrito como um sistema dinâmico que possui um estado de repouso para o qual sempre retorna após sofrer pequenas pertubações. Entretanto se a perturbação ou estímulo ultrapassar seu limiar de excitabilidade, o sistma fará uma excursão mais longa pelo espaço de estados antes de retornar ao seu estado de repouso. Durante esta escursão será refratário a novos estímulos, ou seja, novos estímulos não afetarão sua trajetória. Mas após retornar ao repouso, estará sujeito a uma nova excitação.

O modelo de Fitzhugh-Nagumo consiste em duas equações apenas. A primeira busca representar a excitação do sistema:

dxdt=c(x−13x3)\frac{dx}{dt} = c \left(x-\frac{1}{3}x^3 \right)

Esta equação admite 3 equilíbrios:

var('c') solve(c*(x-x^3/3),x)
[x == -sqrt(3), x == sqrt(3), x == 0]
p=plot(1*(x-x^3/3),(-2,2)) po = point([(-sqrt(3),0),(0,0),(sqrt(3),0)],color='red',pointsize=40) show(p+po)
Image in a Jupyter notebook

Pelo gráfico, podemos ver que temos dois equilíbrios estáveis (x=±3x=\pm \sqrt{3}) e um instável (x=0x=0). Mas esta equação sozinha, nos dá uma sistema bistável, e não um excitável. Para isso temos que acrescentar uma variável, yy, de "recuperação", que neutralize a excitação e leve o sistema de volta para o equilíbrio de "repouso".

dxdt=c(x−13x3−y+j)\frac{dx}{dt} = c \left(x-\frac{1}{3}x^3 -y + j \right)

dydt=1c(x+a−by)\frac{dy}{dt}=\frac{1}{c}(x+a-by)

o parâmetro j representa o estímulo externo, no caso do neurônio a correte de despolarização injetada na célula. Os parâmetros aa e bb são positivos e tomam valores preferencialmente nas seguintes faixas: 1−2b3<a<11-\frac{2b}{3} \lt a \lt 1 e 0<b<10 \lt b \lt 1. A forma como cc aparece em ambas as equações serve para ajustarmos a intensidade da excitabilidade em relação à recuperação. Aumentando cc, aumentamos a excitabilidade e diminuimos a recuperação.

Análise no Plano de Fase

Para nos ajudar nesta análise, vamos definir as nuliclinas de ambas as variáveis:

dydt=0⇒y=1bx+ab\frac{dy}{dt}=0 \Rightarrow y = \frac{1}{b}x + \frac{a}{b}

dxdt=0⇒y=x−13x3+j\frac{dx}{dt}=0 \Rightarrow y= x- \frac{1}{3}x^3 +j

 

Note que o parâmetro cc não afeta nenhuma das nuliclinas.

var('x y a b c j') dxdt = c*((x-(x**3)/3)-y+j) solve(dxdt,y)
[y == -1/3*x^3 + j + x]
dydt = (x+a-b*y)/c solve(dydt,y)
[y == (a + x)/b]
var('y') c=10 j=0.3 a=.7 b=.8 vf = plot_vector_field([c*((x-(x**3)/3)-y+j),(x+a-b*y)/c],(x,-2,2),(y,-1.5,1.5),axes_labels=[r'$x$',r'$y$']) xnull = plot(x-x^3/3+j,(-2,2),color='blue',ymin=-1.5,ymax=1.5, legend_label="Nuliclina de $x$") ynull = plot((a+x)/b,(-2,2),color='green',ymin=-1.5,ymax=1.5, legend_label="Nuliclina de $y$") show(vf+xnull+ynull)
Image in a Jupyter notebook

A interseção entre as nuliclinas é um equilíbrio do systema. Podemos calcular o seu valor.

sols=solve([dxdt(a=a,b=b,c=c,j=j),dydt(a=a,b=b,c=c)],[x,y]) for sol in sols: show(sol)
[x=(0.4966487372747987+1.220647330194089i),y=(1.495810921593498+1.525809162742611i)]\renewcommand{\Bold}[1]{\mathbf{#1}}\left[x = \left(0.4966487372747987 + 1.220647330194089i\right), y = \left(1.495810921593498 + 1.525809162742611i\right)\right]
[x=(0.4966487372747987−1.220647330194089i),y=(1.495810921593498−1.525809162742611i)]\renewcommand{\Bold}[1]{\mathbf{#1}}\left[x = \left(0.4966487372747987 - 1.220647330194089i\right), y = \left(1.495810921593498 - 1.525809162742611i\right)\right]
[x=(−0.9932974689126025),y=(−0.3666218551949299)]\renewcommand{\Bold}[1]{\mathbf{#1}}\left[x = \left(-0.9932974689126025\right), y = \left(-0.3666218551949299\right)\right]
pe = point((sol[0].rhs(),sol[1].rhs()), color='red',pointsize=50) show(vf+xnull+ynull+pe)
Image in a Jupyter notebook

Vamos calcular a Jacobiana do sistema:

Jac = jacobian([dxdt,dydt], [x,y]) Jac
(−(x2−1)c−c1c−bc)\renewcommand{\Bold}[1]{\mathbf{#1}}\left(\begin{array}{rr} -{\left(x^{2} - 1\right)} c & -c \\ \frac{1}{c} & -\frac{b}{c} \end{array}\right)
eqx = -0.9932974689126025 Jac(x=eqx,b=b,c=c).eigenvalues()
[−11470389350i 2137383719017539699+394074511470389350,11470389350i 2137383719017539699+394074511470389350]\renewcommand{\Bold}[1]{\mathbf{#1}}\left[-\frac{1}{1470389350} i \, \sqrt{2137383719017539699} + \frac{39407451}{1470389350}, \frac{1}{1470389350} i \, \sqrt{2137383719017539699} + \frac{39407451}{1470389350}\right]
def fun(t,Y, params): x, y = Y c,j,a,b=params #j=0.9*(heaviside(t-20)-heaviside(t-50)) return[ c*(x-x**3/3-y+j), (x+a-b*y)/c ] jfun = lambda t,st,p: jacobian([c*((x-(x**3)/3)-y+j),(x+a-b*y)/c], [x,y]).subs(x=st[0], c=p[0],j=p[1],a=p[2],b=p[3]) jfun (0,[sol[0].rhs(),sol[1].rhs()],[c,j,a,b])
(0.1336013825181741−10110−0.0800000000000000)\renewcommand{\Bold}[1]{\mathbf{#1}}\left(\begin{array}{rr} 0.1336013825181741 & -10 \\ \frac{1}{10} & -0.0800000000000000 \end{array}\right)
T = ode_solver() T.algorithm='rk8pd' T.function= fun T.jacobian = jfun t_range = [0,80] y0 = [-1.19940806511,-0.624260036595]#[.5,.5] T.ode_solve(t_range,y0,params=[3,0.5,.7,.8],num_points=500)
#fun(0,[1.49900000000000,0.0833333333333333],[0.08,0,.7,.8]) px = list_plot([(p[0],p[1][0]) for p in T.solution], plotjoined=True, legend_label="x"); py = list_plot([(p[0],p[1][1]) for p in T.solution], color='green', legend_label="y"); px.legend() show(px+py); #print T.solution
Image in a Jupyter notebook
@interact def traj_plot(x0=slider(-2,2,.1, -1.19940806511),y0=slider(-1.5,1.5,.1,-0.624260036595)): inits = [x0,y0]#[.5,.5] T.ode_solve(t_range,inits,params=[c,j,a,b],num_points=500) traj = list_plot([(p[1][0],p[1][1]) for p in T.solution],color="orange", plotjoined=True); pi = point([inits[0],inits[1]],color='green', pointsize=50) show(vf+xnull+ynull+traj+pi)
T = ode_solver() T.algorithm='rk8pd' #cfun = nagumo_C(0.4) T.function= fun t_range = [0,80] y0 = [-1.19940806511,-0.624260036595] T.ode_solve(t_range,y0,params=[3,0.4,.7,.8],num_points=500)
px = list_plot([(p[0],p[1][0]) for p in T.solution], plotjoined=True, legend_label="x"); py = list_plot([(p[0],p[1][1]) for p in T.solution], color='green', legend_label="y"); show(px+py);
Image in a Jupyter notebook
import numpy as np @interact def bifurcation(j_min=slider(0,1,0.01,0),j_max=slider(0,2,0.01,1.4)): T = ode_solver() T.algorithm='rk8pd' pts = [] for j in np.linspace(j_min,j_max,200): #cfun = nagumo_C(j) T.function= fun t_range = [0,50] y0 = [-1.19940806511,-0.624260036595] T.ode_solve(t_range,y0,params=[3,j,.7,.8], num_points=200) sol = T.solution pts += [(j,p[1][0]) for n,p in enumerate(sol[0:]) if abs(p[1][1]-0.5) < 0.01] show(points(pts,pointsize=2), gridlines=True)