No BSD License  

Highlights from
Model of atrial fibrillation/flutter.

image thumbnail
from Model of atrial fibrillation/flutter. by Peter Hammer
Computer model of atrial fibrillation originally published by Moe et al in 1964 to demonstrate suffi

afib
function afib
% AFIB   Computer model of atrial fibrillation model by Moe et al, 
%        American Heart Journal 1964; 67(2):200-220.
%
% Implemented in Matlab by Peter Hammer, Children's Hospital Boston, Feb 2002.
%
%       Cellular automata model simulating atrial flutter/fibrillation.
%       A cluster of (4) cells is rapidly stimulated causing periodic waves
%       of activation to spread across the model surface. Due to variation
%       in refractory periods across the surface, the wavefronts are broken
%       up as they collide with regions that are still refractory. The
%       rapid stimulation is terminated after 80 steps yet activation
%       wavefronts still travel throughout the model surface. The authors
%       carefully chose the cluster of cells to stimulate by looking for
%       adjacent cells with short refractory periods. I do not do that
%       here; rather I just keep varying the initial state of the random
%       number generator used to asign the K value until I get
%       self-sustaining activity. 
%
%       In the figure, three discrete states are plotted: activated or scheduled (blue), 
%       refractory (light blue), and resting/excitable (white). The time step
%       number of the simulation is displayed below the activation pattern.
%       To modulate the speed of the simulation, change the input argument
%       to the pause statement (time, in seconds, to pause during each step).
%
%       Along with plotting the activation across the surface with time, a
%       second plot is generated showing the "pseudo-electrogram". This reproduces one
%       of the plots from the original paper. (See paper cited above for details.)
%
%       To see some interesting activation patterns, try setting initial state of random 
%       number generator (4th line of code below) to:
%       84 (colliding rotors then random)
%       97 (moving focus, terminates)
%       119 (moving focus/rotor)
%       136 (moving focus)
%       137(multiple wavelets)
%       142(large rotor) 

clear all
R=31; C=32;					    	    % Array dimensions (units).
kv=sqrt(10:20);					        % Range of constants (steps^0.5).
rand('seed',142);
ik=ceil(size(kv,2)*rand(R,C));		    % Matrix of uniform random numbers, 1:11.
k=kv(ik);							    % Matrix of random constants (steps^0.5).

dt=5;								    % Time step (msec).
arp=-6*ones(size(k));           	    % Initial refractory state throughout (excitable).
nhood=[-1 0;-1 1;0 -1;0 1;1 -1;1 0];	% Neighborhood of adjacent units.
s0=zeros(R,C);				    	    % Array with ones if in state 0.
atimes=cell(R*C,1);			    	    % Cell array of beat times (in steps).

br=[1:31 1:31 zeros(1,34) 32*ones(1,34)];   % Row coordinates of border.
bc=[zeros(1,31) 33*ones(1,31) 0:33 0:33];   % Column coordinates of border.
px=0.5*(br-1)+bc; py=1+(br-1)*sqrt(3)/2;    % Convert coords to hexagonal for plotting.
fh=figure('position',[160 325 350 175],'color',[1 1 1]); % [160 325 630 330]
plot(px,py,'w.','markersize',16); hold on   % Plot the border.
axis image
axh=gca;
set(axh,'xcolor',[1 1 1],'ycolor',[1 1 1])
th=text(15,-2,'');

sr=[12 12 13 13]'; sc=[8 9 8 9]';       % Coordinates of units to stimulate.
si=sub2ind(size(s0),sr,sc);             % Indices of units in cluster to stimulate.
sched=[si ones(size(si))];				% Schedule the units to activate at step 1.
ph1=plot(-2,0,'b.','markersize',16);  % Create handles for active points.
ph2=plot(-2,0,'c.','markersize',16);  % Create handles for refractory points.
for step=1:600
   ia=sched(sched(:,2) == step,1);				% Indices into s0 to activate.
   ia2=sched(sched(:,2) > step,1);              % Additional indices into s0 to plot.
   [sy,sx]=ind2sub(size(s0),[ia;ia2]);          % Coordinates of activated units.
   px=0.5*(sy-1)+sx; py=1+(sy-1)*sqrt(3)/2;     % Convert coords to hexagonal for plotting.
   set(ph1,'xdata',px,'ydata',py);              % Update plot of active units.
   if step > 1
       [ry,rx]=ind2sub(size(s0),inz);               % Coordinates of refractory units.
       px=0.5*(ry-1)+rx; py=1+(ry-1)*sqrt(3)/2;     % Convert coords to hexagonal for plotting.
       set(ph2,'xdata',px,'ydata',py);              % Update plot of refractory units.
       drawnow
       pause(0.01)
       egram(step)=size(inz,1);                     % Build approx egram based on # of active units.
   end
   set(th,'string',num2str(step))                   % Update timer.
   
   s0=zeros(R,C); s0(ia)=1;			        % Update matrix of ones/zeros with activated units.
   sched(sched(:,2) == step,:)=[];          % Remove activated units from table.
   for j=1:size(ia,1)                       % Loop thru units acitvated at this step.
       atimes{ia(j)}=[atimes{ia(j)}; step]; % Append row of atimes with current step.
       if size(atimes{ia(j)},1) > 1         % Element has been activated at least twice.
           lastcycle=diff(atimes{ia(j)}(end-1:end)); %*dt;    % Previous interval (msec).
       else
           lastcycle=40;                    % Use default previous interval of 40 steps.
       end
       arp(ia(j))=round(k(ia(j))*sqrt(lastcycle));   % Set ref pd for units just active.
   end

   % Determine units to schedule for future activation.
   ins0=[];                                     % Indices of neighbors of active units.
   for jj=1:size(nhood,1)	                    % Loop through nhood building column of neighbors.
      ins0=[ins0; find(matrixShift(s0,nhood(jj,1),nhood(jj,2)))];
   end
   if step < 80
       srp=arp(si);
       ins0=[ins0; si(srp<1)];
   end
   ins0=unique(ins0);	        	            % Exclude redundancies.
   ins0=setdiff(ins0,ia);                       % Exclude currently active elements.
   ins0=setdiff(ins0,sched(:,1));               % Exclude units already scheduled for activation.
   inz=find(arp > 0); ins0=setdiff(ins0,inz);   % Exclude units in state 1 (absolute refractory).
   ia2=intersect(ins0,find((arp == 0) | (arp == -1)));	% Units in state 2.
   sched=[sched;[ia2 step+4*ones(size(ia2))]];          % Schedule to activate in 4 steps.
   ia3=intersect(ins0,find((arp == -2) | (arp == -3)));	% Units in state 3.
   sched=[sched;[ia3 step+3*ones(size(ia3))]];          % Schedule to acivate in 3 steps.
   ia4=intersect(ins0,find((arp == -4) | (arp == -5)));	% Units in state 4.
   sched=[sched;[ia4 step+2*ones(size(ia4))]];          % Schedule to acivate in 2 steps.
   ia5=intersect(ins0,find(arp == -6));		            % Units in state 5 (completely recovered).
   sched=[sched;[ia5 step+ones(size(ia5))]];            % Schedule to acivate at next step.
   arp=max(-6,arp-1);                                   % Update refractory period.
end

figure; plot(egram);
title('Pseudo-Electrogram (see paper by Moe et al)')
xlabel('Time Steps')
ylabel('Number of Units Refractory')

% =================== Sub functions ===================
function out=matrixShift(m,r,c)

% MATRIXSHIFT Shift all elements of matrix m up by r rows and right
%   by c columns. Rows and/or columns of zeros are used to fill voids.

for k=1:abs(r)
   if r > 0, m=[m(2:end,:); zeros(1,size(m,2))];
   else m=[zeros(1,size(m,2)); m(1:end-1,:)];
   end
end

for k=1:abs(c)
   if c > 0, m=[zeros(size(m,1),1) m(:,1:end-1)];
   else m=[m(:,2:end) zeros(size(m,1),1)];
   end
end
out=m;

Contact us at files@mathworks.com