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="https://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 }