Permalink
Cannot retrieve contributors at this time
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
334 lines (288 sloc)
12 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"math" | |
//"github.com/sbinet/go-hdf5/pkg/hdf5" | |
) | |
//PURPOSE: Hold various neuronal parameters | |
type NeuronParameters struct { | |
restVoltage float64 //V_rest | |
lipidBilayerCapacitance float64 //C_m | |
sodiumActivationMaxConductance float64 //g-_Na | |
potassiumMaxConductance float64 //g-_K | |
leakConductance float64 //g-_l | |
sodiumReversePotential float64 //E_Na | |
potassiumReversePotential float64 //E_K | |
leakReversePotential float64 //E_l | |
} | |
//MODIFIES: np | |
//EFFECTS: Fills the neuronParameters struct with default values | |
func (np *NeuronParameters) initializeParametersWithDefaults() { | |
np.restVoltage = 0 | |
np.lipidBilayerCapacitance = 1 | |
np.sodiumActivationMaxConductance = 120 | |
np.potassiumMaxConductance = 36 | |
np.leakConductance = 0.3 | |
np.sodiumReversePotential = 115 | |
np.potassiumReversePotential = -12 | |
np.leakReversePotential = 10.613 | |
} | |
//PURPOSE: Hold various data about a single neuron and its state | |
type Neuron struct { | |
parameters NeuronParameters | |
sodiumConductance float64 | |
potassiumConductance float64 | |
//activation and inactivation dimensionless quantities | |
m float64 | |
n float64 | |
h float64 | |
stimulation []float64 | |
V_m []float64 | |
currentTimeStep float64 | |
simulation *Simulation | |
} | |
//MODIFIES: neuron's currentTimeStep | |
//EFFECTS: Instantiates a single neuron | |
func (neuron *Neuron) initializeNeuron(simulation *Simulation) { | |
neuron.setSimulation(simulation) | |
neuron.intializeVoltageArray() | |
neuron.initializeStimulationArray() | |
neuron.currentTimeStep = 1 | |
neuron.initializeDimensionlessQuantities() | |
} | |
func (neuron *Neuron) initializeStimulationArray() { | |
neuron.stimulation = make([]float64, len(neuron.simulation.timeArray)) | |
} | |
//MODIFIES: neuron's stimulation array | |
//EFFECTS: Fills the stimulation array with a single 10mV stimulation period from 5ms to 30ms | |
func (neuron *Neuron) setSampleStimulationValues() { | |
for time, currentTime := range neuron.simulation.timeArray { | |
if currentTime >= 5 && currentTime <= 30 { | |
neuron.stimulation[time] = float64(10) | |
} | |
} | |
} | |
//MODIFIES: neuron's simulation pointer | |
//EFFECTS: Sets the neuron.simulation pointer to the input simulation | |
func (neuron *Neuron) setSimulation(simulation *Simulation) { | |
neuron.simulation = simulation | |
} | |
//MODIFIES: neuron's V_m array | |
//EFFECTS: Initializes neuron's voltage array, and sets the first element equal to the neuron's rest voltage | |
func (neuron *Neuron) intializeVoltageArray() { | |
neuron.V_m = make([]float64, len(neuron.simulation.timeArray)) | |
neuron.V_m[0] = neuron.parameters.restVoltage | |
} | |
//REQUIRES: neuron has the voltage array initialized and parameters set. | |
//MODIFIES: neuron's m, n, and h | |
//EFFECTS: Initializes the dimensionless quantities | |
func (neuron *Neuron) initializeDimensionlessQuantities() { | |
neuron.m = neuron.sodiumMInfinity() | |
neuron.n = neuron.potassiumNInfinity() | |
neuron.h = neuron.sodiumHInfinity() | |
} | |
//REQUIRES: neuron is properly initialized | |
//MODIFIES: neuron's m, n, and h | |
//EFFECTS: Calculates the dimensionless quantities for the current neuron timestep | |
func (neuron *Neuron) calculateDimensionlessQuantities() { | |
neuron.m += (neuron.sodiumAlphaM()*(1-neuron.m) - //FUNCTIONS ARE CALLING CURRENT VALUES AND NOT PREVIOUS ONES | |
neuron.sodiumBetaM()*neuron.m) * neuron.simulation.deltaTime | |
neuron.h += (neuron.sodiumAlphaH()*(1-neuron.h) - | |
neuron.sodiumBetaH()*neuron.h) * neuron.simulation.deltaTime | |
neuron.n += (neuron.potassiumAlphaN()*(1-neuron.n) - | |
neuron.potassiumBetaN()*neuron.n) * neuron.simulation.deltaTime | |
} | |
//MODIFIES: neuron's currentTimeStep | |
//EFFECTS: Runs all update calculations for the neuron in its current timestep | |
func (neuron *Neuron) calculateSimulationStep() { | |
//potassium and sodium calculation step | |
neuron.calculatePotassiumAndSodiumConductance() | |
neuron.calculateDimensionlessQuantities() | |
neuron.calculateNewVoltage() | |
neuron.currentTimeStep += 1 | |
} | |
//MODIFIES: neuron's V_m array | |
//EFFECTS: Calculates the neuron's membrane potential at the current neuron timestep | |
func (n *Neuron) calculateNewVoltage() { | |
n.V_m[int(n.currentTimeStep)] = n.V_m[int(n.currentTimeStep)-1] | |
n.V_m[int(n.currentTimeStep)] += (n.stimulation[int(n.currentTimeStep)-1] - n.sodiumConductance* | |
(n.previousVoltage()-n.parameters.sodiumReversePotential) - n.potassiumConductance* | |
(n.previousVoltage()-n.parameters.potassiumReversePotential) - n.parameters.leakConductance* | |
(n.previousVoltage()-n.parameters.leakReversePotential)) / n.parameters.lipidBilayerCapacitance * n.simulation.deltaTime | |
} | |
//MODIFIES: neuron's sodiumConductance and potassiumConductance | |
//EFFECTS: Calculates the neuron's potassium and sodium conductance and the current neuron timestep | |
func (neuron *Neuron) calculatePotassiumAndSodiumConductance() { | |
neuron.sodiumConductance = neuron.parameters.sodiumActivationMaxConductance * neuron.h * math.Pow(neuron.m, 3.) | |
neuron.potassiumConductance = neuron.parameters.potassiumMaxConductance * math.Pow(neuron.n, 4.) | |
} | |
//EFFECTS: Returns neuron's membrane potential at the current neuron timestep | |
func (neuron *Neuron) currentVoltage() float64 { | |
return neuron.V_m[int(neuron.currentTimeStep)] | |
} | |
func (neuron *Neuron) previousVoltage() float64 { | |
return neuron.V_m[int(neuron.currentTimeStep)-1] | |
} | |
//EFFECTS: Calculates and returns the neuron's current first potassium rate constant value | |
func (neuron *Neuron) potassiumAlphaN() float64 { | |
if neuron.previousVoltage() != 10 { | |
return 0.01 * (-neuron.previousVoltage() + 10) / (math.Exp((-neuron.previousVoltage()+10)/10) - 1) | |
} | |
return 0.1 | |
} | |
//EFFECTS: Calculates and returns the neuron's current second potassium rate constant value | |
func (neuron *Neuron) potassiumBetaN() float64 { | |
return 0.125 * math.Exp(-neuron.previousVoltage()/80) | |
} | |
//EFFECTS: Calculates and returns the neuron's current steady state potassium activation value | |
func (neuron *Neuron) potassiumNInfinity() float64 { | |
return neuron.potassiumAlphaN() / | |
(neuron.potassiumAlphaN() + neuron.potassiumBetaN()) | |
} | |
//EFFECTS: Calculates and returns the neuron's current first sodium rate constant value | |
func (neuron *Neuron) sodiumAlphaM() float64 { | |
if neuron.previousVoltage() != 25 { //change to previous voltage | |
return 0.1 * (-neuron.previousVoltage() + 25) / (math.Exp((-neuron.previousVoltage()+25)/10) - 1) | |
} | |
return 1 | |
} | |
//EFFECTS: Calculates and returns the neuron's current second sodium rate constant value | |
func (neuron *Neuron) sodiumBetaM() float64 { | |
return 4 * math.Exp(-neuron.previousVoltage()/18) | |
} | |
//EFFECTS: Calculates and returns the neuron's current sodium steady state activation value | |
func (neuron *Neuron) sodiumMInfinity() float64 { | |
return neuron.sodiumAlphaM() / | |
(neuron.sodiumAlphaM() + neuron.sodiumBetaM()) | |
} | |
//EFFECTS: Calculates and returns the neuron's current first sodium inactivation rate constant value | |
func (neuron *Neuron) sodiumAlphaH() float64 { | |
return 0.07 * math.Exp(-neuron.previousVoltage()/20) | |
} | |
//EFFECTS: Calculates and returns the neuron's current second sodium inactivation rate constant value | |
func (neuron *Neuron) sodiumBetaH() float64 { | |
return 1 / (math.Exp((-neuron.previousVoltage()+30)/10) + 1) | |
} | |
//EFFECTS: Calculates and returns the neuron's current sodium steady state inactivation value | |
func (neuron *Neuron) sodiumHInfinity() float64 { | |
return neuron.sodiumAlphaH() / | |
(neuron.sodiumAlphaH() + neuron.sodiumBetaH()) | |
} | |
//PURPOSE: Hold values and states related to the neural network simulation | |
type Simulation struct { | |
totalSimulationTime float64 | |
deltaTime float64 | |
timeArray []float64 | |
weightMap map[*Neuron]map[*Neuron]float64 | |
neuronArray []*Neuron | |
} | |
//MODIFIES: Neurons in neuronArray | |
//EFFECTS: Initializes all neurons in the neuron array with params | |
func (simulation *Simulation) initializeNeuronArray(params NeuronParameters) { | |
for _, neuron := range simulation.neuronArray { | |
neuron.parameters = params | |
neuron.initializeNeuron(simulation) | |
} | |
} | |
//MODIFIES: Simulation's neuronArray | |
//EFFECTS: Allocates new neurons, and adds them to the simulation's neuronArray | |
func (simulation *Simulation) addNumberofNeuronsToSimulation(neuronCount int) { | |
for i := 0; i < neuronCount; i++ { | |
simulation.neuronArray = append(simulation.neuronArray, new(Neuron)) | |
} | |
} | |
func (simulation *Simulation) allocateWeightMap() { | |
simulation.weightMap = make(map[*Neuron]map[*Neuron]float64, len(simulation.neuronArray)) | |
for _, neuron := range simulation.neuronArray { | |
simulation.weightMap[neuron] = make(map[*Neuron]float64, len(simulation.neuronArray)) | |
} | |
} | |
//MODIFIES: Simulation's weightMap | |
//EFFECTS: Sets all values in the weightMap equal to zero | |
//TODO: Programatically create the array using the neurons contained within the simulation | |
func (simulation *Simulation) initializeWeightMap() { | |
for neuron1 := range simulation.weightMap { | |
for neuron2 := range simulation.weightMap[neuron1] { | |
simulation.weightMap[neuron1][neuron2] = 0.0 | |
} | |
} | |
} | |
//MODIFIES: simulation's weightMap | |
//EFFECTS: Sets the connection weight from neuron1 to neuron2 as weight | |
func (simulation *Simulation) setSynapseWeightPair(neuron1, neuron2 *Neuron, weight float64) { | |
simulation.weightMap[neuron1][neuron2] = weight | |
} | |
//MODIFIES: simulation's neuronArray's neurons | |
//EFFECTS: Updates all of the stimulations based on the current voltages | |
func (simulation *Simulation) updateNeuronStimulationValues() { | |
for _, neuron1 := range simulation.neuronArray { | |
for neuron2 := range simulation.weightMap[neuron1] { | |
if neuron1 == neuron2 { | |
continue | |
} | |
neuron2.stimulation[int(neuron2.currentTimeStep)] += neuron1.V_m[int(neuron1.currentTimeStep)-1] * simulation.weightMap[neuron1][neuron2] | |
} | |
} | |
} | |
//MODIFIES: Simulation's totalSimulationTime, deltaTime | |
//EFFECTS: Intializes the simulation with totalSimulationTime and deltaTime | |
func (simulation *Simulation) initializeSimulation(totalSimulationTime float64, deltaTime float64) { | |
simulation.totalSimulationTime = totalSimulationTime | |
simulation.deltaTime = deltaTime | |
simulation.initializeTimeArray() | |
} | |
//MODIFIES: simulation's timeArray | |
//EFFECTS: Fills timeArray with values from 0 to totalSimulationTime in increments of deltaTime | |
func (simulation *Simulation) initializeTimeArray() { | |
for timestep := float64(0); timestep < simulation.totalSimulationTime+simulation.deltaTime; timestep += simulation.deltaTime { | |
simulation.timeArray = append(simulation.timeArray, timestep) | |
} | |
} | |
//EFFECTS: Run the simulation | |
//TODO: Add support for synaptic connections | |
func (simulation *Simulation) runSimulation() { | |
//simulation code goes here | |
for timeStep := 1; timeStep < len(simulation.timeArray); timeStep++ { | |
simulation.updateNeuronStimulationValues() | |
for _, neuron := range simulation.neuronArray { | |
neuron.calculateSimulationStep() | |
} | |
} | |
} | |
func (simulation *Simulation) printToCSV() { | |
for row, time := range simulation.timeArray { | |
fmt.Print(time, ",") | |
for index, neuron := range simulation.neuronArray { | |
if index != len(simulation.neuronArray)-1 { | |
fmt.Print(neuron.V_m[row], ",") | |
} else { | |
fmt.Print(neuron.V_m[row]) | |
} | |
} | |
fmt.Print("\n") | |
} | |
} | |
/*type HDF5File struct { | |
dims []int | |
dataspace *Dataspace | |
}*/ | |
func main() { | |
//Simulation Parameters | |
totalSimulationTime := float64(220) //Total simulation time in milliseconds | |
deltaTime := float64(0.025) //Simulation timestep in milliseconds | |
var simulation Simulation | |
simulation.initializeSimulation(totalSimulationTime, deltaTime) | |
var params NeuronParameters | |
params.initializeParametersWithDefaults() //defaults are initialized | |
simulation.addNumberofNeuronsToSimulation(3) | |
simulation.initializeNeuronArray(params) | |
simulation.neuronArray[0].setSampleStimulationValues() | |
simulation.allocateWeightMap() | |
simulation.initializeWeightMap() | |
simulation.setSynapseWeightPair(simulation.neuronArray[0], simulation.neuronArray[1], 0.8) | |
simulation.setSynapseWeightPair(simulation.neuronArray[1], simulation.neuronArray[2], 0.9) | |
simulation.setSynapseWeightPair(simulation.neuronArray[2], simulation.neuronArray[1], 0.1) | |
simulation.setSynapseWeightPair(simulation.neuronArray[2], simulation.neuronArray[0], 0.1) | |
simulation.runSimulation() | |
simulation.printToCSV() | |
} |