Skip to content

Latest commit

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

CardioPy

License: Apache 2.0Python 3.8+Jupyter Notebook

A computational model of cardiac tissue electrophysiology using the FitzHugh-Nagumo (FHN) reaction-diffusion system. This project simulates wave propagation in 2D myocardial tissue and investigates the relationship between electrical stimulus parameters and the initiation of self-sustaining excitation waves.

Wave Propagation Animation

Overview

Cardiac tissue is an electrically active medium where action potentials—rapid depolarization followed by repolarization—drive rhythmic contraction. Understanding how electrical stimuli initiate self-sustaining waves is crucial for studying defibrillation, arrhythmias, and pacemaker design.

This project models cardiac tissue as a 2D continuous medium governed by a reaction-diffusion partial differential equation (PDE) using the FitzHugh-Nagumo model—a simplified two-variable system that captures essential excitable dynamics:

  • Existence of an excitation threshold
  • "All-or-nothing" behavior
  • Wave propagation through diffusive coupling

Key Questions

What is the relationship between stimulus intensity (I_amp) and duration (t_dur) required to trigger a self-sustaining propagating wave in 2D cardiac tissue?

Model Description

Cellular Dynamics: FitzHugh-Nagumo

The FHN model describes each point in the tissue with two variables:

  • V: Membrane potential (fast, excitatory variable)
  • w: Recovery variable (slow, inhibitory variable)

$$ \frac{\partial V}{\partial t} = V - \frac{V^3}{3} - w + I_{stim} $$

$$ \frac{\partial w}{\partial t} = \epsilon (V + \beta - \gamma w) $$

Parameters:

  • $\epsilon$: Recovery rate (typically 0.01 - 0.1)
  • $\beta$: Polarization parameter
  • $\gamma$: Recovery parameter

Spatial Coupling: Reaction-Diffusion

Using the monodomain approximation, the complete system is:

$$ \frac{\partial V}{\partial t} = D \nabla^2 V + \underbrace{\left( V - \frac{V^3}{3} - w + I_{stim} \right)}_{\text{reaction term (FHN)}} $$

$$ \frac{\partial w}{\partial t} = \epsilon (V + \beta - \gamma w) $$

where:

  • $D$: Diffusion coefficient (electrical conductivity)
  • $I_{stim}$: Applied stimulus current (non-zero only during the pulse)

Numerical Methods

Spatial Discretization: 5-point finite difference Laplacian with Neumann (zero-flux) boundary conditions using reflected ghost nodes.

Temporal Integration: Operator splitting with two approaches:

MethodUpdateStabilityPerformance
Explicit (Euler Forward)$V^{n+1} = V^n + \Delta t \cdot D \nabla^2 V^n$Conditional (CFL: $\Delta t \le \Delta x^2 / 4D$)Fast per step, many steps needed
Implicit (Crank-Nicolson)$(I - \frac{\Delta t D}{2}\nabla^2) V^{n+1} = (I + \frac{\Delta t D}{2}\nabla^2) V^n$UnconditionalSlower per step, fewer steps

Results

Strength-Duration Curve

Strength-Duration Curve

The strength-duration relationship follows the Lapicque/Weiss equation:

$$ I_{amp} = \frac{R}{1 - e^{-t_{dur} / \tau}} $$

Physiological Parameters Derived:

  • Reobase (R): ~1.133 μA/cm² (minimum current for infinite duration)
  • Chronaxia (t_c): ~2.250 ms (time needed at 2× reobase)

Numerical Method Comparison

MethodPrecisionAvg. CPU Time (s)Stability
ExplicitReference~7.3Conditional (requires $\Delta t = 0.02$ ms)
Implicit (Crank-Nicolson)Nearly identical~16.3Unconditional

The implicit method is ~2.2× slower for this grid size but enables larger time steps for finer meshes.

Stability Analysis

When the explicit method violates the CFL condition ($\Delta t > \Delta x^2/4D$), numerical instabilities manifest as "checkerboard" patterns with unphysical oscillations between ±2 in adjacent pixels.

Stability Test

Getting Started

Prerequisites

Python 3.8+

Installation

  1. Clone the repository:
git clone https://github.com/yourusername/CardioPy.git
cd CardioPy
  1. Install dependencies:
pip install -r requirements.txt
  1. Launch the Jupyter notebook:
jupyter notebook notebooks/Complete_Notebook.ipynb

Dependencies

  • NumPy
  • SciPy (sparse matrices, linear solvers)
  • Matplotlib
  • Jupyter Notebook

Code Structure

cardiac-modeling/
├── README.md
├── requirements.txt
├── LICENSE
├── notebooks/
│ └── Complete_Notebook.ipynb
├── src/
│ ├── __init__.py
│ ├── fhn_model.py # FHN derivatives and cellular dynamics
│ ├── diffusion.py # Laplacian operator and diffusion solvers
│ ├── stimulus.py # Stimulus application
│ └── simulation.py # Main simulation functions
├── tests/
│ ├── test_fhn.py
│ ├── test_diffusion.py
│ └── test_simulation.py
└── images/
├── strength_duration_curve.png
├── propagation_animation.gif
└── stability_test.png

Key Functions

# FHN cellular dynamicsdefFHN_derivatives(V, w, I_stim, epsilon=0.01, beta=0.7, gamma=0.8):
"""Calculate FHN derivatives"""dVdt=V- (V**3)/3-w+I_stimdwdt=epsilon* (V+beta-gamma*w)
returndVdt, dwdt# Diffusion operator (Neumann boundary conditions)defapply_laplacian(V, dx):
"""2D Laplacian with zero-flux boundary"""# Reflected ghost node implementation
...
# Implicit solver with LU factorization cachingdefimplicit_diffusion_solver(V, dx, dt, D, theta=0.5):
"""Crank-Nicolson diffusion solver with cached LU decomposition"""
...
# Parameter sweepdeffind_threshold(t_dur, metodo='explicito', tol=0.1):
"""Find threshold current using binary search"""
...

Performance Optimizations

The implicit solver uses LU factorization caching to avoid rebuilding and refactoring the sparse matrix at each time step—since the matrix depends only on grid parameters ($N_x, N_y, dx, dt, D$), not the solution itself.

_cache_implicito= {}
defimplicit_diffusion_solver(V, dx, dt, D, theta=0.5):
key= (Nx, Ny, dx, dt, D, theta)
ifkeynotin_implicit_cache:
L=_build_2d_laplacian_operator(Nx, Ny, dx)
I=identity(N, format='csc')
A= (I-theta*dt*D*L).tocsc()
M= (I+ (1-theta) *dt*D*L).tocsc()
lu=splu(A)
_implicit_cache[key] = (M, lu)
M, lu=_implicit_cache[key]
# Solve using cached factorization

Memory/Performance Trade-off:

  • Explicit: Scales as $O(N^2)$ in time steps due to CFL restriction
  • implicit: Scales as $O(N^{1.5})$ due to LU fill-in but maintains constant time steps

References

  • FitzHugh, R. (1961). Impulses and physiological states in theoretical models of nerve membrane. Biophysical Journal, 1(6), 445-466.
  • Nagumo, J., Arimoto, S., & Yoshizawa, S. (1962). An active pulse transmission line simulating nerve axon. Proceedings of the IRE, 50(10), 2061-2070.
  • Aliev, R. R., & Panfilov, A. V. (1996). A simple two-variable model of cardiac excitation. Chaos, Solitons & Fractals, 7(3), 293-301.
  • Clayton, R. H., Bernus, O., Cherry, E. M., et al. (2011). Models of cardiac tissue electrophysiology: progress, challenges and open questions. Progress in Biophysics and Molecular Biology, 104(1-3), 22-48.

License

This project is licensed under the Apache License, Version 2.0 - see the LICENSE file for details.

Acknowledgments

  • This project was developed as part of a Dynamical Systems Modeling course
  • Special thanks to Ronny Calixto for guidance

About

Python framework for 2D cardiac tissue excitation modeling (FHN) calculating reobase, chronaxia, and wave propagation dynamics.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages