iSpike
2.1
Spike conversion library for robotics
|
00001 //iSpike includes 00002 #include <iSpike/Channel/InputChannel/JointInputChannel.hpp> 00003 #include <iSpike/ISpikeException.hpp> 00004 #include <iSpike/Reader/AngleReader.hpp> 00005 #include <iSpike/Log/Log.hpp> 00006 00007 00008 using namespace ispike; 00009 00010 //Local debugging information 00011 //#define DEBUG 00012 //#define RECORD_TIMING 00013 00014 //Names of properties 00015 #define DEGREE_OF_FREEDOM_NAME "Degree Of Freedom" 00016 #define STANDARD_DEVIATION_NAME "Standard Deviation" 00017 #define MIN_ANGLE_NAME "Minimum Angle" 00018 #define MAX_ANGLE_NAME "Maximum Angle" 00019 #define NEURON_WIDTH_NAME "Neuron Width" 00020 #define NEURON_HEIGHT_NAME "Neuron Height" 00021 #define PARAM_A_NAME "Parameter A" 00022 #define PARAM_B_NAME "Parameter B" 00023 #define PARAM_C_NAME "Parameter C" 00024 #define PARAM_D_NAME "Parameter D" 00025 #define PEAK_CURRENT_NAME "Peak Current" 00026 #define CONSTANT_CURRENT_NAME "Constant Current" 00027 00028 00029 00031 JointInputChannel::JointInputChannel() { 00032 // First define the properties of this channel 00033 addProperty(Property(Property::Integer, 0, DEGREE_OF_FREEDOM_NAME, "The degree of freedom to read from this joint", false)); 00034 addProperty(Property(Property::Double, 0.5, STANDARD_DEVIATION_NAME, "The standard deviation as a percentage of neurons covered", true)); 00035 addProperty(Property(Property::Double, -90.0, MIN_ANGLE_NAME, "The minimum angle to read", true)); 00036 addProperty(Property(Property::Double, 90.0, MAX_ANGLE_NAME, "The maximum angle to read", true)); 00037 addProperty(Property(Property::Integer, 10, NEURON_WIDTH_NAME, "Width of the neuron network", true)); 00038 addProperty(Property(Property::Integer, 1, NEURON_HEIGHT_NAME, "Height of the neuron network", true)); 00039 addProperty(Property(Property::Double, 0.1, PARAM_A_NAME, "Parameter A of the Izhikevich Neuron Model", false)); 00040 addProperty(Property(Property::Double, 0.2, PARAM_B_NAME, "Parameter B of the Izhikevich Neuron Model", false)); 00041 addProperty(Property(Property::Double, -65.0, PARAM_C_NAME, "Parameter C of the Izhikevich Neuron Model", false)); 00042 addProperty(Property(Property::Double, 2.0, PARAM_D_NAME, "Parameter D of the Izhikevich Neuron Model", false)); 00043 addProperty(Property(Property::Double, 40.0, PEAK_CURRENT_NAME, "Maximum current that will be injected into neuron", true)); 00044 addProperty(Property(Property::Double, 0.0, CONSTANT_CURRENT_NAME, "This value is added to the incoming current", false)); 00045 00046 //Create the description 00047 channelDescription = Description("Joint Input Channel", "This is a joint input channel", "Angle Reader"); 00048 00049 //Initialize variables 00050 reader = NULL; 00051 } 00052 00053 00055 JointInputChannel::~JointInputChannel(){ 00056 if(reader != NULL) 00057 delete reader; 00058 } 00059 00060 00061 /*--------------------------------------------------------------------*/ 00062 /*--------- PUBLIC METHODS -------*/ 00063 /*--------------------------------------------------------------------*/ 00064 00065 //Inherited from InputChannel 00066 void JointInputChannel::initialize(Reader* reader, map<string, Property>& properties){ 00067 //This class requires an angle reader, so cast it and check 00068 this->reader = dynamic_cast<AngleReader*>(reader); 00069 if(this->reader == NULL) 00070 throw ISpikeException("Cannot initialize JointInputChannel with a null reader."); 00071 00072 //Update and store properties 00073 updateProperties(properties); 00074 00075 //Start the reader thread running 00076 this->reader->start(); 00077 00078 if(size() < 2) { 00079 throw ISpikeException("JointInputChannel must use two or more neurons"); 00080 } 00081 00082 /* Angle covered by each neuron */ 00083 double angleDist = (maxAngle - minAngle) / double(size()-1); 00084 00085 //Standard deviation expressed in angle 00086 double sdAngle = standardDeviation * angleDist; 00087 00088 //Create normal distribution and calculate current factor 00089 normalDistribution = boost::math::normal_distribution<double>(0.0, sdAngle); 00090 currentFactor = peakCurrent / pdf(normalDistribution, 0.0); 00091 00092 /* populate the angles */ 00093 for(unsigned n=0; n < size(); ++n) { 00094 neuronAngles.push_back(minAngle + n * angleDist); 00095 } 00096 00097 //Set up Izhikevich simulation 00098 neuronSim.initialize(size()); 00099 00100 setInitialized(true); 00101 } 00102 00103 00104 //Inherited from Channel. This will be done immediately if we are not stepping or deferred until the end of the step */ 00105 void JointInputChannel::setProperties(map<string,Property>& properties){ 00106 updateProperties(properties); 00107 } 00108 00109 00110 //Inherited from InputChannel 00111 void JointInputChannel::step(){ 00112 //Check reader for errors 00113 if(reader->isError()){ 00114 LOG(LOG_CRITICAL)<<"AngleReader Error: "<<reader->getErrorMessage(); 00115 throw ISpikeException("Error in AngleReader"); 00116 } 00117 00118 //Get angle and check it is in range 00119 double tmpAngle = reader->getAngle(); 00120 if(tmpAngle > maxAngle){ 00121 LOG(LOG_WARNING)<<"JointInputChannel: New angle ("<<tmpAngle<<") exceeds the maximum ("<<maxAngle<<"). Has been limited to the maximum"; 00122 tmpAngle = maxAngle; 00123 } 00124 else if(tmpAngle < minAngle){ 00125 LOG(LOG_WARNING)<<"JointInputChannel: New angle ("<<tmpAngle<<") is less than the minimum ("<<minAngle<<"). Has been limited to the minimum"; 00126 tmpAngle = minAngle; 00127 } 00128 00129 //Set input currents to neurons 00130 for(unsigned index = 0; index < size(); ++index) { 00131 neuronSim.setInputCurrent( index, constantCurrent + currentFactor * pdf(normalDistribution, neuronAngles[index]-tmpAngle) ); 00132 } 00133 00134 //Step the simulator 00135 neuronSim.step(); 00136 } 00137 00138 00139 /*--------------------------------------------------------------------*/ 00140 /*--------- PROTECTED METHODS -------*/ 00141 /*--------------------------------------------------------------------*/ 00142 00145 void JointInputChannel::updateProperties(map<string, Property>& properties){ 00146 if(propertyMap.size() != properties.size()) 00147 throw ISpikeException("JointInputChannel: Current properties do not match new properties."); 00148 00149 updatePropertyCount = 0; 00150 for(map<string, Property>::iterator iter = properties.begin(); iter != properties.end(); ++iter) { 00151 //In updateReadOnly mode, only update properties that are not read only 00152 if( ( isInitialized() && !propertyMap[iter->first].isReadOnly() ) || !isInitialized()) { 00153 string paramName = iter->second.getName(); 00154 switch (iter->second.getType()) { 00155 case Property::Integer: { 00156 if(paramName == DEGREE_OF_FREEDOM_NAME) 00157 reader->setDegreeOfFreedom(updateIntegerProperty(iter->second)); 00158 else if (paramName == NEURON_WIDTH_NAME) 00159 setWidth(updateIntegerProperty(iter->second)); 00160 else if (paramName == NEURON_HEIGHT_NAME) 00161 setHeight(updateIntegerProperty(iter->second)); 00162 } 00163 break; 00164 case Property::Double: { 00165 if (paramName == PARAM_A_NAME) 00166 neuronSim.setParameterA(updateDoubleProperty(iter->second)); 00167 else if (paramName == PARAM_B_NAME) 00168 neuronSim.setParameterB(updateDoubleProperty(iter->second)); 00169 else if (paramName == PARAM_C_NAME) 00170 neuronSim.setParameterC(updateDoubleProperty(iter->second)); 00171 else if (paramName == PARAM_D_NAME) 00172 neuronSim.setParameterD(updateDoubleProperty(iter->second)); 00173 else if (paramName == PEAK_CURRENT_NAME) 00174 peakCurrent = updateDoubleProperty(iter->second); 00175 else if (paramName == CONSTANT_CURRENT_NAME) 00176 constantCurrent = updateDoubleProperty(iter->second); 00177 else if(paramName == STANDARD_DEVIATION_NAME) 00178 standardDeviation = updateDoubleProperty(iter->second); 00179 else if (paramName == MIN_ANGLE_NAME) 00180 minAngle = updateDoubleProperty(iter->second); 00181 else if (paramName == MAX_ANGLE_NAME) 00182 maxAngle = updateDoubleProperty(iter->second); 00183 } 00184 break; 00185 case Property::Combo: break; 00186 case Property::String: break; 00187 default: 00188 throw ISpikeException("Property type not recognized."); 00189 } 00190 } 00191 } 00192 00193 //Check angles are sensible 00194 if(maxAngle <= minAngle) { 00195 throw ISpikeException("Maximum angle must be greater than minimum angle"); 00196 } 00197 00198 //Check all properties were updated 00199 if(!isInitialized() && updatePropertyCount != propertyMap.size()) 00200 throw ISpikeException("Some or all of the properties were not updated: ", updatePropertyCount); 00201 } 00202 00203