brian_to_csv.py
Go to the documentation of this file.
00001 #!/usr/bin/env python
00002 
00003 '''
00004 brian_to_csv.py
00005 Copyright 2013 University of Massachusetts Lowell
00006 Author: Jonathan Hasenzahl, Abraham Shultz
00007 '''
00008 
00009 ## @package brian_to_csv
00010 #
00011 # This is a ROS node that is used by itself to generate CSV data files by running
00012 # Brian simulations. Use this node to generate a CSV file, and then use the
00013 # csv_recv node to read the generated file.
00014 
00015 # Note: The CSV file path is currently hardcoded at line 133; it would be nice
00016 #       to make this a server parameter at some point.
00017 #
00018 # @copyright Copyright 2013 University of Massachusetts Lowell
00019 # @author Jonathan Hasenzahl
00020 # @author Abraham Shultz
00021 
00022 import roslib; roslib.load_manifest('neuro_recv')
00023 import rospy
00024 from brian import *
00025 from pickle import Unpickler
00026 import random
00027 
00028 
00029 ## @briefData structure for a MEA channel pad
00030 #  neurons: list of neurons within range of the pad
00031 #  total_weight: combined weights of all the neurons
00032 class Channel():
00033     def __init__(self):
00034         self.neurons = []
00035         self.total_weight = 0.0
00036         
00037     def __str__(self):
00038         name = 'Weight:' + str(self.total_weight)
00039         if len(self.neurons) == 0:
00040             name += '[No neurons]'
00041         else:
00042             for neuron in self.neurons:
00043                 name += '[' + str(neuron) + ']'
00044         return name
00045         
00046     def add(self, neuron):
00047         self.neurons.append(neuron)
00048         self.total_weight += neuron.weight
00049         
00050     def size(self):
00051         return len(self.neurons)
00052 
00053 
00054 ## @brief Data structure for a neuron that is close to a channel pad.
00055 #  data: unique id of the neuron
00056 #  weight: distance from the center of the pad
00057 class CloseNeuron():
00058     def __init__(self, data, dist):
00059         self.data = data
00060         self.weight = 40.0 - dist
00061         
00062     def __str__(self):
00063         return str(self.data) + ':' + str(self.weight)
00064 
00065 ## Runs a Brian simulation "P" and records and publishes voltages captured by
00066 #  the multielectrode array "channels"
00067 def brianRecv(connections, channels):
00068     # LIF model, different time constants for excitory and inhibitory
00069     eqs = Equations('''
00070           dv/dt = (ge+gi-(v+49*mV))/(20*ms) : volt
00071           dge/dt = -ge/(5*ms)               : volt
00072           dgi/dt = -gi/(10*ms)              : volt
00073           ''')
00074 
00075     # Get the neuron count. This is kind of hacky, as it depends on the
00076     # links being stored in increasing order. The +1 is because they are indexed
00077     # from zero. 
00078     neuron_count = connections[-1][0] + 1
00079     
00080     # Set up the population based on the count and equations
00081     P = NeuronGroup(neuron_count, eqs, threshold=-50*mV, reset=-60*mV)
00082     P.v = -60*mV + (15 * rand(len(P))) * mV  
00083     
00084     # Partition population based on assumption of 25% inhibitory, 75% excitatory
00085     excitory_count = int(neuron_count * 0.75)
00086     inhib_count = neuron_count - excitory_count
00087     #Pe = P.subgroup(excitory_count)
00088     #Pi = P.subgroup(inhib_count)
00089     
00090     # Set up connections. First, pick a random set of inhibitory neuron ids. 
00091     # Everything else is excitatory. Then create the connection objects and 
00092     # populate them according to the connectivity list
00093     inhib_neurons = random.sample(xrange(neuron_count), inhib_count)
00094     Ce = Connection (P, P, 'ge')
00095     Ci = Connection (P, P, 'gi')
00096     for connection in connections:
00097         prune = random.randint(0,100)
00098         #if prune < percent_connected:
00099         if connection[0] in inhib_neurons:
00100             Ci[connection[0], connection[1]] = -9*mV
00101         else:
00102             Ce[connection[0], connection[1]] = 1.62*mV
00103 
00104     # Create a list of all the neurons to record
00105     print 'Recorded neurons:',
00106     recorded_neurons = []
00107     for channel in channels:
00108         if channel != None:
00109             for neuron in channel.neurons:
00110                 recorded_neurons.append(neuron.data)
00111                 print neuron.data,
00112     print
00113     print 'Length of recorded neurons array', len(recorded_neurons)
00114     
00115     # Create a monitor to record the voltages of each neuron every 1 ms.
00116     # If timestep = 1, then 10 actions are recorded every ms.
00117     # If timestep = 10, then 1 action is recorded every ms.
00118     # Setting timestep to 1 is in effect 30 s of simulation in just 3 s.
00119     M = StateMonitor(P, "v", record=recorded_neurons, timestep=10)
00120 
00121     # Get running time parameter
00122     try:
00123         running_time = rospy.get_param('brian_running_time')
00124     except KeyError:
00125         rospy.logerr('Could not get brian_running_time parameter, default will be used')
00126         running_time = 30.0
00127         
00128     # Run the simulation
00129     # Divide seconds by 10 if timestep=1 above
00130     rospy.loginfo("Running simulation...")
00131     run(running_time * second)
00132     rospy.loginfo("Simulation finished")    
00133         
00134     rospy.loginfo('Recording dish states...')
00135         
00136     # Open CSV file for recording
00137     # TODO: Make this a server parameter
00138     log = open('/home/jon/ros_workspace/other_stuff/csv/brian.csv', 'w')
00139     log.write('index,')
00140     for index in range(60):
00141         log.write('channel_' + str(index) + ',')
00142     log.write('\n')
00143        
00144     # Write the dishes
00145     for current_dish in range(len(M[recorded_neurons[0]])):    
00146         log.write(str(current_dish) + ',')
00147         for index in range(60):
00148             volt = 0.0
00149             
00150             # Get the weighted average of the volts of the neurons on this 
00151             # channel 
00152             if channels[index] != None:
00153                 for neuron in channels[index].neurons:
00154                     weight = neuron.weight / channels[index].total_weight
00155                     weighted = M[neuron.data][current_dish] * weight
00156                     volt += weighted
00157                     #print '    Neuron: ', neuron.data, 'Weight:', weight, 'State:', M[neuron.data][current_dish]
00158                     #print '    Weighted State: ', weighted, 'Total:', d.samples[index]
00159             log.write(str(volt) + ',')
00160         
00161         log.write('\n')        
00162         
00163     log.close()
00164     
00165     rospy.loginfo('Recording finished')
00166 
00167 ## Populates a 60-channel list using data from an x,y map
00168 def channelizer(pad_neuron_map):
00169     channels = []
00170     for row in range(8):
00171         for col in range(8):
00172             if row == 0 and col == 0:
00173                 continue
00174             elif row == 0 and col == 7:
00175                 continue
00176             elif row == 7 and col == 0:
00177                 continue
00178             elif row == 7 and col == 7:
00179                 continue
00180             channels.append(pad_neuron_map[(row, col)])
00181     return channels
00182         
00183 if __name__ == '__main__':
00184     rospy.init_node('brian_to_csv')
00185     
00186     # Get the file name parameters
00187     try:
00188         connections_file_name = rospy.get_param('brian_connections_file_path')
00189         pad_neuron_map_file_name = rospy.get_param('brian_pad_neuron_map_file_path')
00190     except KeyError:
00191         rospy.logfatal('Could not load file name parameters')
00192     else:
00193         # Load the files
00194         try:
00195             connections_file = open(connections_file_name)
00196             pad_neuron_map_file = open(pad_neuron_map_file_name)
00197         except IOError:
00198             rospy.logfatal('Could not open pickle files')
00199         else:
00200             connections = Unpickler(connections_file).load()
00201             pad_neuron_map = Unpickler(pad_neuron_map_file).load()
00202             connections_file.close()
00203             pad_neuron_map_file.close()
00204             
00205             # Get list of neurons for each channel from the pad neuron map
00206             channels = channelizer(pad_neuron_map)
00207             
00208             # Run the ROS node
00209             try:
00210                 brianRecv(connections, channels)
00211             except rospy.ROSInterruptException: pass


neuro_recv
Author(s): Jonathan Hasenzahl
autogenerated on Sun Jan 5 2014 11:12:29