Home > bioelectromagnetism > source_dipole_sphere.m

source_dipole_sphere

PURPOSE ^

source_dipole_sphere - calculate surface potential on a sphere containing a dipole

SYNOPSIS ^

function FV = source_dipole_sphere(dipole_moment,dipole_origin,dipole_orient,sphere_radius,LMAX)

DESCRIPTION ^

 source_dipole_sphere - calculate surface potential on a sphere containing a dipole

 Calculates surface voltage, for a single sphere containing a radial
 dipole.  This function is limited to radial dipoles (a dipole at the
 origin can have any orientation).

 The sphere is assigned a homogenous, isotropic conductivity, 
 sigma = 0.33 Siemens/meter, which is commonly used to estimate brain
 conductivity.

 Also, the distance of dipole source to sink is 1e-12 (1 pico meter).

 FV = source_dipole_sphere([dipole_moment],[dipole_origin],...
                           [dipole_orient],[sphere_radius],[Lmax]);
 -------------------------------------------------------------------------
 Inputs
 
 dipole_moment - Ampere meters, 10e-9 by default, which approximates a
 small patch of cortex (see Hamalainen et al [1993], Reviews of Modern
 Physics, 65(2):413-497).

 dipole_origin - The XYZ Cartesian coordinates of the midpoint between the
 source and sink of the dipole.  The orientation of the dipole will be
 radial, with source and sink arranged either side of midpoint.  See also
 the sphere radius specification below.

 dipole_orient - Only if the dipole_origin = [0,0,0] (the default) is it
 possible to specify the dipole orientation; eg, [1 0 0] is along the
 x-axis, [0 1 0] is along the y-axis, etc.  If the dipole is located away
 from the origin, the orientation is along the radial line from the origin
 to the dipole.

 sphere_radius - in meters; the default 0.1 approximates a human head.
 Note that any specification of dipole origin should be within the sphere
 radius.

 Lmax - the order of magnitude for the sum of Legendres, which are used
 for the analytic solution of potential at a spherical surface.  The
 default value is 20, determined after examination of values from 1:250
 (20 is conservative, as convergence was observed at Lmax < 5).

 -------------------------------------------------------------------------
 Returns the FV struct, a spherical tesselation

 FV =
    vertices: [2562x3 double]
       faces: [5120x3 double]
       Cdata: [2562x1 double] - surface potential (Volts)

 To visualize the result, use:

 patch('vertices',FV.vertices,'faces',FV.faces,...
       'FaceVertexCData',FV.Cdata,...
       'Facecolor','interp');

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function FV = source_dipole_sphere(dipole_moment,dipole_origin,dipole_orient,sphere_radius,LMAX)
0002 
0003 % source_dipole_sphere - calculate surface potential on a sphere containing a dipole
0004 %
0005 % Calculates surface voltage, for a single sphere containing a radial
0006 % dipole.  This function is limited to radial dipoles (a dipole at the
0007 % origin can have any orientation).
0008 %
0009 % The sphere is assigned a homogenous, isotropic conductivity,
0010 % sigma = 0.33 Siemens/meter, which is commonly used to estimate brain
0011 % conductivity.
0012 %
0013 % Also, the distance of dipole source to sink is 1e-12 (1 pico meter).
0014 %
0015 % FV = source_dipole_sphere([dipole_moment],[dipole_origin],...
0016 %                           [dipole_orient],[sphere_radius],[Lmax]);
0017 % -------------------------------------------------------------------------
0018 % Inputs
0019 %
0020 % dipole_moment - Ampere meters, 10e-9 by default, which approximates a
0021 % small patch of cortex (see Hamalainen et al [1993], Reviews of Modern
0022 % Physics, 65(2):413-497).
0023 %
0024 % dipole_origin - The XYZ Cartesian coordinates of the midpoint between the
0025 % source and sink of the dipole.  The orientation of the dipole will be
0026 % radial, with source and sink arranged either side of midpoint.  See also
0027 % the sphere radius specification below.
0028 %
0029 % dipole_orient - Only if the dipole_origin = [0,0,0] (the default) is it
0030 % possible to specify the dipole orientation; eg, [1 0 0] is along the
0031 % x-axis, [0 1 0] is along the y-axis, etc.  If the dipole is located away
0032 % from the origin, the orientation is along the radial line from the origin
0033 % to the dipole.
0034 %
0035 % sphere_radius - in meters; the default 0.1 approximates a human head.
0036 % Note that any specification of dipole origin should be within the sphere
0037 % radius.
0038 %
0039 % Lmax - the order of magnitude for the sum of Legendres, which are used
0040 % for the analytic solution of potential at a spherical surface.  The
0041 % default value is 20, determined after examination of values from 1:250
0042 % (20 is conservative, as convergence was observed at Lmax < 5).
0043 %
0044 % -------------------------------------------------------------------------
0045 % Returns the FV struct, a spherical tesselation
0046 %
0047 % FV =
0048 %    vertices: [2562x3 double]
0049 %       faces: [5120x3 double]
0050 %       Cdata: [2562x1 double] - surface potential (Volts)
0051 %
0052 % To visualize the result, use:
0053 %
0054 % patch('vertices',FV.vertices,'faces',FV.faces,...
0055 %       'FaceVertexCData',FV.Cdata,...
0056 %       'Facecolor','interp');
0057 %
0058 
0059 % $Revision: 1.1 $ $Date: 2004/11/12 01:32:36 $
0060 
0061 % Licence:  GNU GPL, no implied or express warranties
0062 % History:  12/2003, Darren.Weber_at_radiology.ucsf.edu
0063 %                    developed from notes and advice from
0064 %                    Dr. Tom.Ferree_at_radiology.ucsf.edu
0065 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0066 
0067 
0068 % LMAX is a parameter used in the Legendre approximation
0069 if ~exist('LMAX','var'), LMAX = 20; end
0070 if isempty(LMAX),        LMAX = 20; end
0071 
0072 % create a spherical surface with a radius that approximates the human
0073 % head, 0.1 meters (10 cm)
0074 if ~exist('sphere_radius','var'), sphere_radius = 0.1; end
0075 if isempty(sphere_radius),        sphere_radius = 0.1; end
0076 
0077 % sphere_tri is an external function
0078 FV = sphere_tri('ico',4,sphere_radius);
0079 
0080 % assign a homogenous, isotropic conductivity to this spherical region
0081 sigma = 0.33; % Siemens/meter, common brain value
0082 fprintf('...assigned brain conductivity (0.33 S/m) to volume\n');
0083 
0084 % distance of dipole source to sink, could approximate the cortical
0085 % thickness
0086 dipole_distance = 1e-12; % 1 pico meter
0087 fprintf('...dipole has source and sink %g meters apart\n',dipole_distance);
0088 
0089 % dipole moment, Ampere meters (10 nA m)
0090 if ~exist('dipole_moment','var'), dipole_moment = 10e-9; end
0091 if isempty(dipole_moment),        dipole_moment = 10e-9; end
0092 fprintf('...dipole moment = %g Ampere meters\n',dipole_moment);
0093 
0094 % dipole current, Amperes
0095 dipole_current = dipole_moment / dipole_distance;
0096 fprintf('...dipole current = %g Amperes\n',dipole_current);
0097 
0098 % Define the vector that lies at the midpoint between the source and sink.
0099 % The origin is the default.
0100 if ~exist('dipole_origin','var'), dipole_origin = [0,0,0]; end
0101 if isempty(dipole_origin),        dipole_origin = [0,0,0]; end
0102 fprintf('...dipole origin = [ %g, %g, %g ] meters\n',dipole_origin);
0103 
0104 % find the magnitude (ie, radius) of the dipole (do not use the matlab norm
0105 % function, it doesn't calculate the same value)
0106 dipole_radius = sqrt( sum( dipole_origin .^2 ) );
0107 
0108 % Calculate the radial dipole unit vector, which is used to find the cosine
0109 % of the angle between the dipole and surface locations below
0110 if dipole_radius,
0111   
0112   % the dipole is not located at the origin
0113   dipole_unit_vector = dipole_origin / dipole_radius;
0114 else
0115   
0116   % the dipole is located at the origin, so the radial orientation is not
0117   % clearly defined and we need another input parameter to define the
0118   % dipole unit vector
0119   
0120   % dipole geometry - oriented along z axis
0121   if ~exist('dipole_orient','var'), dipole_orient = [0 0 1]; end
0122   if isempty(dipole_orient),        dipole_orient = [0 0 1]; end
0123   
0124   % now calculate the dipole unit vector
0125   dipole_unit_vector = dipole_orient / sqrt( sum( dipole_orient .^ 2 ));
0126   
0127 end
0128 fprintf('...dipole unit vector = [ %g, %g, %g ]\n',dipole_unit_vector);
0129 
0130 % calculate location of source and sink, just for fun!
0131 source = dipole_origin + (dipole_unit_vector * dipole_distance);
0132 sink   = dipole_origin - (dipole_unit_vector * dipole_distance);
0133 fprintf('...source vector = [ %+g, %+g, %+g ] meters\n', source);
0134 fprintf('...sink vector   = [ %+g, %+g, %+g ] meters\n', sink);
0135 
0136 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0137 % solve voltage on surface
0138   
0139 fprintf('...calculating surface voltage...'); tic
0140 
0141 % initialise the surface potentials
0142 FV.Cdata = zeros(length(FV.vertices),1);
0143 
0144 if dipole_radius,
0145   
0146   DIPOLE_CONSTANT = ( -dipole_moment / (4 * pi * sigma) ) * (1 / (dipole_radius^2) );
0147   
0148   for vertex = 1:length(FV.vertices),
0149     
0150     % extract spherical surface coordinates
0151     surface_vector = FV.vertices(vertex,:);
0152     
0153     surface_radius = sqrt( sum ( surface_vector .^2 ) );
0154     
0155     if surface_radius < dipole_radius,
0156       error('surface radius is smaller than dipole radius.');
0157     end
0158     
0159     if surface_radius,
0160       surface_unit_vector = surface_vector / surface_radius;
0161     else
0162       surface_unit_vector = [0 0 0];
0163       warning('surface radius is zero.');
0164     end
0165     
0166     cos_theta = dot(dipole_unit_vector, surface_unit_vector);
0167     
0168     summation = 0;
0169     
0170     for L = 1:LMAX,
0171       
0172       TERM1 = 2 * L + 1;
0173       
0174       TERM2 = ( dipole_radius / surface_radius )^(L + 1);
0175       
0176       PnX = LegendreP(L,cos_theta);
0177       if length(PnX) > 1,
0178         PnX_sum = sum(PnX(2:end));
0179       else
0180         PnX_sum = 0;
0181       end
0182       summation = summation + ( TERM1 * TERM2 * PnX_sum );
0183       
0184     end
0185     
0186     FV.Cdata(vertex) = DIPOLE_CONSTANT * summation;
0187     
0188   end % for vertex
0189   
0190 else
0191   
0192   % special case where dipole is at the origin.
0193   
0194   DIPOLE_CONSTANT = ( -dipole_moment / (4 * pi * sigma) );
0195   
0196   for vertex = 1:length(FV.vertices),
0197     
0198     surface_vector = FV.vertices(vertex,:);
0199     
0200     surface_radius = sqrt( sum ( surface_vector .^2 ) );
0201     
0202     if surface_radius < dipole_radius,
0203       error('surface radius is smaller than dipole radius.');
0204     end
0205     
0206     if surface_radius,
0207       surface_unit_vector = surface_vector / surface_radius;
0208     else
0209       surface_unit_vector = [0 0 0];
0210       warning('surface radius is zero.');
0211     end
0212     
0213     cos_theta = dot(dipole_unit_vector, surface_unit_vector);
0214     
0215     FV.Cdata(vertex) = DIPOLE_CONSTANT * (3 / (surface_radius^2) ) * cos_theta;
0216     
0217   end % for vertex
0218   
0219 end
0220 
0221 t=toc; fprintf('done (%5.2f sec)\n',t);
0222 
0223 return
0224 
0225 
0226 
0227 
0228 
0229 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
0230 % SUBFUNCTIONS...
0231 
0232 function p=LegendreP(nmax,x)
0233 
0234 % function p=LegendreP(nmax,x)
0235 % Computes all Legendre polynomials from n=0 to n=nmax,
0236 % them in an array from n=1 to nmax+1
0237 % Uses the recursion relation in Numerical Recipes.
0238 % T Ferree
0239 
0240 p=zeros(nmax+1,1);
0241 
0242 if nmax>=0
0243   p0=1.0;
0244   p(1)=p0;
0245 end
0246 
0247 if nmax>=1 
0248   p1=x;
0249   p(2)=p1;
0250 end
0251 
0252 if nmax>=2
0253   for j=2:nmax
0254     c1=(2.0*j-1.0)/(1.0*j);
0255     c2=(1.0*j-1.0)/(1.0*j);
0256     p(j+1)=c1*x*p(j-1+1)-c2*p(j-2+1);
0257   end
0258 end
0259 
0260 return;

Generated on Mon 15-Aug-2005 15:36:19 by m2html © 2003