[Pybrainsim-activity] SF.net SVN: pybrainsim:[138] trunk/src/HeadModelDipoleSphere.py
Status: Planning
Brought to you by:
rgoj
|
From: <rg...@us...> - 2010-06-27 15:31:51
|
Revision: 138
http://pybrainsim.svn.sourceforge.net/pybrainsim/?rev=138&view=rev
Author: rgoj
Date: 2010-06-27 15:31:45 +0000 (Sun, 27 Jun 2010)
Log Message:
-----------
* Adding a work in progress of a single conducting sphere head model with generators as dipoles at last!
Added Paths:
-----------
trunk/src/HeadModelDipoleSphere.py
Added: trunk/src/HeadModelDipoleSphere.py
===================================================================
--- trunk/src/HeadModelDipoleSphere.py (rev 0)
+++ trunk/src/HeadModelDipoleSphere.py 2010-06-27 15:31:45 UTC (rev 138)
@@ -0,0 +1,126 @@
+# PyBrainSim Copyright 2009 Roman Goj
+#
+# This file is part of PyBrainSim.
+#
+# PyBrainSim is free software: you can redistribute it and/or modify it under
+# the terms of the GNU General Public License as published by the Free Software
+# Foundation, either version 3 of the License, or (at your option) any later
+# version.
+#
+# PyBrainSim is distributed in the hope that it will be useful, but WITHOUT ANY
+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+# A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# PyBrainSim. If not, see <http://www.gnu.org/licenses/>.
+
+from __future__ import division
+from numpy import arange, array, ones, identity, dot, zeros, sin, cos, pi, sqrt
+__metaclass__ = type # New style classes. Is this necessary?
+
+"""
+This reimplemenation of the HeadModel class models the head as a single
+conductant sphere containing dipolar sources.
+"""
+
+from HeadModel import HeadModel
+
+class HeadModelDipoleSphere(HeadModel):
+ def __init__(self, head, radius):
+ HeadModel.__init__(self, head)
+ self.head = head
+ self.radius = radius # Radius of the head in [cm]
+ self.leadField = 0;
+
+ def checkPosition(self,position):
+ # Checking if position is a list of two or five numbers
+ # The position of each registration site is given in spherical coordinates
+ # associated with the center of the spherical head. The radial coordinate of the electrode
+ # is always equal to the radius of the head, hence it doesn't need to be specified.
+ # The only two parameters that need to be specified are the angles theta and phi in this
+ # order.
+ # For each generator, all three cordinates must be given: the depth of the dipole and the
+ # theta and phi angles. Additionaly, angles specyfying the orientation of the dipole in
+ # the spherical coordinates of the dipole must also be given. The theta angle is then the
+ # orientation with respect to the surface of the head - i.e. theta = 0 means a radial
+ # dipole, while theta = pi/2 means a tangential dipole. Only values in this range are
+ # allowed! The specification of the phi angle is considered less important and should be
+ # explained more thoroughly in other documentation.
+ if not isinstance(position, list):
+ return False
+ if len(position) != 2 and len(position) != 5:
+ return False
+ # Check the radial coordinate (depth) of the dipole
+ if len(position) == 5 and (position[0] <= 0 or position[0] >= self.radius):
+ return False
+ # Check the theta angle of the orientation of the dipole
+ if len(position) == 5 and (position[3] < 0 or position[3] > pi/2):
+ return False
+ for i in range(len(position)):
+ if (not isinstance(position[i], float)) and (not isinstance(position[i], int)):
+ return False
+
+ # If none of the conditions above fail, the position is correct
+ return True
+
+ def calculateLeadField(self):
+ # How many generators and electrodes do we have?
+ nGenerators = len(self.head.generatorSiteList)
+ nElectrodes = len(self.head.registrationSiteList)
+
+ # Assuming ideal conductivity
+ sigma = 1.0
+
+ # The number of electrodes and generators defines the size of the lead field matrix
+ self.leadField = zeros((nElectrodes,nGenerators))
+
+ for iElectrode in range(nElectrodes):
+ # Calculating the coordinates of the electrode in the Cartesian coordinates associated with the head
+ electrodeTheta = self.head.registrationSiteList[iElectrode][0]
+ electrodePhi = self.head.registrationSiteList[iElectrode][1]
+ xyzElectrodeHead = zeros(3);
+ xyzElectrodeHead[0] = self.radius * sin(electrodeTheta) * cos(electrodePhi);
+ xyzElectrodeHead[1] = self.radius * sin(electrodeTheta) * sin(electrodePhi);
+ xyzElectrodeHead[2] = self.radius * cos(electrodeTheta);
+
+ for iGenerator in range(nGenerators):
+ # Calculating the coordinates of the dipole in the Cartesian coordinates associated with the head
+ dipoleRadius = self.radius - self.head.generatorSiteList[iGenerator][0]
+ dipoleTheta = self.head.generatorSiteList[iGenerator][1]
+ dipolePhi = self.head.generatorSiteList[iGenerator][2]
+ xyzDipoleHead = zeros(3);
+ xyzDipoleHead[0] = dipoleRadius * sin(dipoleTheta) * cos(dipolePhi);
+ xyzDipoleHead[1] = dipoleRadius * sin(dipoleTheta) * sin(dipolePhi);
+ xyzDipoleHead[2] = dipoleRadius * cos(dipoleTheta);
+
+ # Calculating the coordinates of the electrode in the coordinates associated with the dipole
+ xyzElectrodeDipole = xyzElectrodeHead - xyzDipoleHead;
+
+ # Calculating the distance between the dipole and the electrode
+ distance = 0;
+ distance += pow(xyzElectrodeDipole[0],2.0)
+ distance += pow(xyzElectrodeDipole[1],2.0)
+ distance += pow(xyzElectrodeDipole[2],2.0)
+ distance = sqrt(distance)
+
+ self.leadField[iElectrode, iGenerator] = 1.0
+
+ def runHeadModel(self, generatorOutput, recording):
+ # Calculating the lead field
+ self.calculateLeadField()
+
+ print self.leadField
+ print (array([generatorOutput])).transpose()
+
+ # Calculating the recording by multyplying the lead field by the generator output
+ newRecording = dot(self.leadField, (array([generatorOutput])).transpose())
+
+ # Converting the new recording to list format for compatibility with rest of the code
+ newRecording = list(newRecording[:,0])
+
+ print newRecording
+
+ for channel in range(len(recording)):
+ recording[channel].append(newRecording[channel])
+
+ return recording
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|