iSpike  2.1
Spike conversion library for robotics
D:/Home/Programs/iSpike/src/Channel/InputChannel/JointInputChannel.cpp
Go to the documentation of this file.
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 
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Defines