001 package com.croftsoft.core.ai.neuro.imp;
002
003 import com.croftsoft.core.ai.neuro.Channel;
004 import com.croftsoft.core.ai.neuro.HhNeuronMut;
005 import com.croftsoft.core.lang.NullException;
006 import com.croftsoft.core.math.MathLib;
007 import com.croftsoft.core.sim.DeltaClock;
008 import com.croftsoft.core.sim.Sim;
009 import com.croftsoft.core.util.seq.Seq;
010
011 /***********************************************************************
012 * Hodgkin-Huxley (HH) neuron.
013 *
014 * Voltages are in units of volts instead of millivolts.
015 * Area-based units are in meters squared instead of centimeters squared.
016 *
017 * For a good description of how the HH equations are derived, see
018 * Nelson, "Chapter 17: Electrophysiological Models", p285, in
019 * Koslow and Subramaniam, "Databasing the Brain: From Data to
020 * Knowledge (Neuroinformatics)", 2005.
021 *
022 * Other references used in implementing the HH equations include:
023 *
024 * Doi and Kumagai, "Nonlinear Dynamics of Small-Scale Biophysical Neural
025 * Networks", Chapter 10, p263, in Poznanski, "Biophysical Neural
026 * Networks: Foundations of Integrative Neuroscience", 2001.
027 *
028 * Feng, "Computational Neuroscience: A Comprehensive Approach", 2004,
029 * p4 and p30.
030 *
031 * @version
032 * $Id: HhNeuronImp.java,v 1.14 2008/09/07 01:48:31 croft Exp $
033 * @since
034 * 2008-08-08
035 * @author
036 * <a href="http://www.CroftSoft.com/">David Wallace Croft</a>
037 ***********************************************************************/
038
039 public final class HhNeuronImp
040 implements HhNeuronMut, Sim
041 ////////////////////////////////////////////////////////////////////////
042 ////////////////////////////////////////////////////////////////////////
043 {
044
045 // Area-based units have been converted from per centimeters squared to
046 // per meters squared. Voltages converted from millivolts to volts.
047
048 public static final double
049 H_INIT = 0.596111046, // steady-state resting
050 LEAK_CONDUCTIVITY = 0.3e+1, // 0.3 mS/cm^2
051 LEAK_REVERSAL_POTENTIAL = -54.4e-3, // -54.4 mV
052 LHOPITAL_THRESHOLD = 1e-9, // L'Hopital's Rule
053 M_INIT = 0.052934218, // steady-state resting
054 MEMBRANE_CAPACITIVITY = 1e-2, // 1 microF/cm^2
055 MEMBRANE_VOLTAGE_INIT = -0.064999722, // steady-state resting
056 N_INIT = 0.317681168, // steady-state resting
057 POTASSIUM_CONDUCTIVITY = 36e+1, // 36 mS/cm^2
058 POTASSIUM_REVERSAL_POTENTIAL = -77e-3, // -77 mV
059 SODIUM_CONDUCTIVITY = 120e+1, // 120 mS/cm^2
060 SODIUM_REVERSAL_POTENTIAL = 50e-3, // 50 mV
061 THRESHOLD = 0; // crossing for spike
062
063 /** 10 microns in diameter in meters. */
064 private static final double DIAMETER = 10e-6;
065
066 /** Area of sphere of 10 microns in diameter in meters squared */
067 public static final double
068 MEMBRANE_AREA = Math.PI * DIAMETER * DIAMETER;
069
070 private final Seq<Channel> channelSeq;
071
072 private final DeltaClock deltaClock;
073
074 //
075
076 private double
077 deltaH,
078 deltaMembraneVoltage,
079 deltaM,
080 deltaN,
081 h,
082 leakConductivity,
083 leakReversalPotential,
084 m,
085 membraneArea,
086 membraneCapacitivity,
087 membraneVoltage,
088 n,
089 potassiumConductivity,
090 potassiumReversalPotential,
091 sodiumConductivity,
092 sodiumReversalPotential,
093 threshold;
094
095 private boolean
096 spiking,
097 willSpike;
098
099 ////////////////////////////////////////////////////////////////////////
100 ////////////////////////////////////////////////////////////////////////
101
102 public HhNeuronImp (
103 final Seq<Channel> channelSeq,
104 final DeltaClock deltaClock,
105 final double h,
106 final double leakConductivity,
107 final double leakReversalPotential,
108 final double m,
109 final double membraneArea,
110 final double membraneCapacitivity,
111 final double membraneVoltage,
112 final double n,
113 final double potassiumConductivity,
114 final double potassiumReversalPotential,
115 final double sodiumConductivity,
116 final double sodiumReversalPotential,
117 final double threshold )
118 ////////////////////////////////////////////////////////////////////////
119 {
120 NullException.check (
121 this.channelSeq = channelSeq,
122 this.deltaClock = deltaClock );
123
124 this.h = h;
125
126 this.leakConductivity = leakConductivity;
127
128 this.leakReversalPotential = leakReversalPotential;
129
130 this.m = m;
131
132 this.membraneArea = membraneArea;
133
134 this.membraneCapacitivity = membraneCapacitivity;
135
136 this.membraneVoltage = membraneVoltage;
137
138 this.n = n;
139
140 this.potassiumConductivity = potassiumConductivity;
141
142 this.potassiumReversalPotential = potassiumReversalPotential;
143
144 this.sodiumConductivity = sodiumConductivity;
145
146 this.sodiumReversalPotential = sodiumReversalPotential;
147
148 this.threshold = threshold;
149 }
150
151 public HhNeuronImp (
152 final Seq<Channel> channelSeq,
153 final DeltaClock deltaClock )
154 ////////////////////////////////////////////////////////////////////////
155 {
156 this (
157 channelSeq,
158 deltaClock,
159 H_INIT,
160 LEAK_CONDUCTIVITY,
161 LEAK_REVERSAL_POTENTIAL,
162 M_INIT,
163 MEMBRANE_AREA,
164 MEMBRANE_CAPACITIVITY,
165 MEMBRANE_VOLTAGE_INIT,
166 N_INIT,
167 POTASSIUM_CONDUCTIVITY,
168 POTASSIUM_REVERSAL_POTENTIAL,
169 SODIUM_CONDUCTIVITY,
170 SODIUM_REVERSAL_POTENTIAL,
171 THRESHOLD );
172 }
173
174 ////////////////////////////////////////////////////////////////////////
175 // accessor methods
176 ////////////////////////////////////////////////////////////////////////
177
178 public double getH ( )
179 ////////////////////////////////////////////////////////////////////////
180 {
181 return h;
182 }
183
184 public double getLeakConductivity ( )
185 ////////////////////////////////////////////////////////////////////////
186 {
187 return leakConductivity;
188 }
189
190 public double getM ( )
191 ////////////////////////////////////////////////////////////////////////
192 {
193 return m;
194 }
195
196 public double getMembraneArea ( )
197 ////////////////////////////////////////////////////////////////////////
198 {
199 return membraneArea;
200 }
201
202 public double getMembraneCapacitivity ( )
203 ////////////////////////////////////////////////////////////////////////
204 {
205 return membraneCapacitivity;
206 }
207
208 public double getMembraneVoltage ( )
209 ////////////////////////////////////////////////////////////////////////
210 {
211 return membraneVoltage;
212 }
213
214 public double getN ( )
215 ////////////////////////////////////////////////////////////////////////
216 {
217 return n;
218 }
219
220 public double getPotassiumConductivity ( )
221 ////////////////////////////////////////////////////////////////////////
222 {
223 return potassiumConductivity;
224 }
225
226 public double getSodiumConductivity ( )
227 ////////////////////////////////////////////////////////////////////////
228 {
229 return sodiumConductivity;
230 }
231
232 public double getThreshold ( )
233 ////////////////////////////////////////////////////////////////////////
234 {
235 return threshold;
236 }
237
238 public boolean isSpiking ( )
239 ////////////////////////////////////////////////////////////////////////
240 {
241 return spiking;
242 }
243
244 ////////////////////////////////////////////////////////////////////////
245 // mutator methods
246 ////////////////////////////////////////////////////////////////////////
247
248 public void setLeakConductivity ( final double leakConductivity )
249 ////////////////////////////////////////////////////////////////////////
250 {
251 this.leakConductivity = leakConductivity;
252 }
253
254 public void setMembraneArea ( final double membraneArea )
255 ////////////////////////////////////////////////////////////////////////
256 {
257 this.membraneArea = membraneArea;
258 }
259
260 public void setMembraneCapacitivity (
261 final double membraneCapacitivity )
262 ////////////////////////////////////////////////////////////////////////
263 {
264 this.membraneCapacitivity = membraneCapacitivity;
265 }
266
267 public void setMembraneVoltage ( final double membraneVoltage )
268 ////////////////////////////////////////////////////////////////////////
269 {
270 this.membraneVoltage = membraneVoltage;
271 }
272
273 public void setPotassiumConductivity (
274 final double potassiumConductivity )
275 ////////////////////////////////////////////////////////////////////////
276 {
277 this.potassiumConductivity = potassiumConductivity;
278 }
279
280 public void setSodiumConductivity ( final double sodiumConductivity )
281 ////////////////////////////////////////////////////////////////////////
282 {
283 this.sodiumConductivity = sodiumConductivity;
284 }
285
286 public void setThreshold ( final double threshold )
287 ////////////////////////////////////////////////////////////////////////
288 {
289 this.threshold = threshold;
290 }
291
292 ////////////////////////////////////////////////////////////////////////
293 // lifecycle methods
294 ////////////////////////////////////////////////////////////////////////
295
296 public void access ( )
297 ////////////////////////////////////////////////////////////////////////
298 {
299 final double deltaTime = deltaClock.getDeltaTime ( );
300
301 final int size = channelSeq.size ( );
302
303 double capacitiveCurrent = 0;
304
305 for ( int i = 0; i < size; i++ )
306 {
307 final Channel channel = channelSeq.get ( i );
308
309 if ( channel.isOpen ( ) )
310 {
311 final double channelCurrent = channel.getConductance ( )
312 * ( membraneVoltage - channel.getReversalPotential ( ) );
313
314 capacitiveCurrent += channelCurrent;
315 }
316 }
317
318 // Multiplying by 1000 to adjust for HH values given in millivolts.
319
320 final double v = ( membraneVoltage - -65e-3 ) * 1000;
321
322
323 // L'Hopital's Rule is applied when the dividend is nearly zero.
324
325 final double alphaM
326 = Math.abs ( 25.0 - v ) < LHOPITAL_THRESHOLD ? 1.0 // -0.1 / -0.1
327 : 0.1 * ( 25.0 - v )
328 / ( Math.exp ( ( 25.0 - v ) / 10.0 ) - 1.0 );
329
330 final double alphaN
331 = Math.abs ( 10.0 - v ) < LHOPITAL_THRESHOLD ? 0.1 // -0.01 / -0.1
332 : 0.01 * ( 10.0 - v )
333 / ( Math.exp ( ( 10.0 - v ) / 10.0 ) - 1.0 );
334
335 final double alphaH
336 = 0.07 * Math.exp ( -v / 20.0 );
337
338 final double betaM
339 = 4.0 * Math.exp ( -v / 18.0 );
340
341 final double betaN
342 = 0.125 * Math.exp ( -v / 80.0 );
343
344 final double betaH
345 = 1.0 / ( Math.exp ( ( 30.0 - v ) / 10.0 ) + 1.0 );
346
347 // Alternate equations for deltaM, deltaN, and deltaH.
348 //
349 // final double
350 // hInf = alphaH / ( alphaH + betaH ),
351 // mInf = alphaM / ( alphaM + betaM ),
352 // nInf = alphaN / ( alphaN + betaN );
353 //
354 // final double
355 // tauH = 1 / ( alphaH + betaH ),
356 // tauM = 1 / ( alphaM + betaM ),
357 // tauN = 1 / ( alphaN + betaN );
358 //
359 // deltaM = deltaTime * ( mInf - m ) / tauM;
360 //
361 // deltaN = deltaTime * ( nInf - n ) / tauN;
362 //
363 // deltaH = deltaTime * ( hInf - h ) / tauH;
364
365 // Multiplied by 1000 to adjust for HH rates in per millisecond units.
366
367 deltaM = deltaTime * 1000 * ( alphaM * ( 1.0 - m ) - betaM * m );
368
369 deltaN = deltaTime * 1000 * ( alphaN * ( 1.0 - n ) - betaN * n );
370
371 deltaH = deltaTime * 1000 * ( alphaH * ( 1.0 - h ) - betaH * h );
372
373 final double
374 leakConductance = membraneArea * leakConductivity,
375 membraneCapacitance = membraneArea * membraneCapacitivity,
376 potassiumConductance = membraneArea * potassiumConductivity,
377 sodiumConductance = membraneArea * sodiumConductivity;
378
379 final double hhCurrent
380 = sodiumConductance * m * m * m * h
381 * ( membraneVoltage - sodiumReversalPotential )
382 + potassiumConductance * n * n * n * n
383 * ( membraneVoltage - potassiumReversalPotential )
384 + leakConductance
385 * ( membraneVoltage - leakReversalPotential );
386
387 capacitiveCurrent += hhCurrent;
388
389 final double deltaCharge = deltaTime * -capacitiveCurrent;
390
391 deltaMembraneVoltage = deltaCharge / membraneCapacitance;
392
393 willSpike = ( membraneVoltage < threshold )
394 && ( membraneVoltage + deltaMembraneVoltage >= threshold );
395 }
396
397 public void mutate ( )
398 ////////////////////////////////////////////////////////////////////////
399 {
400 h = MathLib.clip ( h + deltaH, 0, 1 );
401
402 m = MathLib.clip ( m + deltaM, 0, 1 );
403
404 n = MathLib.clip ( n + deltaN, 0, 1 );
405
406 membraneVoltage += deltaMembraneVoltage;
407
408 spiking = willSpike;
409 }
410
411 ////////////////////////////////////////////////////////////////////////
412 ////////////////////////////////////////////////////////////////////////
413 }