iSpike  2.1
Spike conversion library for robotics
D:/Home/Programs/iSpike/src/Channel/OutputChannel/JointOutputChannel.cpp
Go to the documentation of this file.
00001 //iSpike includes
00002 #include <iSpike/Channel/OutputChannel/JointOutputChannel.hpp>
00003 #include <iSpike/Log/Log.hpp>
00004 #include <iSpike/ISpikeException.hpp>
00005 using namespace ispike;
00006 
00007 //Property names
00008 #define MIN_ANGLE_NAME "Minimum Angle"
00009 #define MAX_ANGLE_NAME "Maximum Angle"
00010 #define RATE_OF_DECAY_NAME "Rate of Decay"
00011 #define CURRENT_INCREMENT_NAME "Current Increment"
00012 #define NEURON_WIDTH_NAME "Neuron Width"
00013 #define NEURON_HEIGHT_NAME "Neuron Height"
00014 #define DEGREE_OF_FREEDOM_PROP "Degree of Freedom"
00015 
00016 //Debug defines
00017 //S#define DEBUG_NEURON_IDS
00018 
00019 
00021 JointOutputChannel::JointOutputChannel() : OutputChannel() {
00022         //First define the properties of this channel
00023         addProperty(Property(Property::Double, -90.0,  MIN_ANGLE_NAME, "The minimum angle to read", true));
00024         addProperty(Property(Property::Double, 90.0, MAX_ANGLE_NAME, "The maximum angle to read", true));
00025         addProperty(Property(Property::Double, 0.25, RATE_OF_DECAY_NAME,  "The rate of decay of the angle variables", false));
00026         addProperty(Property(Property::Double, 10, CURRENT_INCREMENT_NAME,  "The amount by which the input current to the neurons is incremented by each spike", false));
00027         addProperty(Property(Property::Integer, 10, NEURON_WIDTH_NAME, "Width of the neuron network", true));
00028         addProperty(Property(Property::Integer, 1, NEURON_HEIGHT_NAME, "Height of the neuron network", true));
00029         addProperty(Property(Property::Integer, 0, DEGREE_OF_FREEDOM_PROP, "Degree of freedom of joint.", false));
00030 
00031         //Create the description
00032         channelDescription = Description("Joint Output Channel", "This channel converts a pattern of spikes into an angle and writes it", "Angle Writer");
00033 
00034         //Initialize variables
00035         writer = NULL;
00036 }
00037 
00038 
00040 JointOutputChannel::~JointOutputChannel(){
00041         if(writer != NULL)
00042                 delete writer;
00043 }
00044 
00045 
00046 /*--------------------------------------------------------------------*/
00047 /*---------                 PUBLIC METHODS                     -------*/
00048 /*--------------------------------------------------------------------*/
00049 
00050 //Inherited from OutputChannel
00051 void JointOutputChannel::setFiring(const std::vector<unsigned>& buffer){
00052         //Work through the neuron ids in the buffer
00053         #ifdef DEBUG_NEURON_IDS
00054                 cout<<"OutputChannel: Firing neuron IDs ";
00055         #endif//DEBUG_NEURON_IDS
00056         for(std::vector<unsigned>::const_iterator iter = buffer.begin(); iter != buffer.end(); ++ iter){
00057                 #ifdef DEBUG_NEURON_IDS
00058                         cout<<*iter<<", ";
00059                 #endif//DEBUG_NEURON_IDS
00060                 currentVariables[*iter] += currentIncrement;
00061         }
00062         #ifdef DEBUG_NEURON_IDS
00063                 cout<<endl;
00064         #endif//DEBUG_NEURON_IDS
00065 }
00066 
00067 
00068 //Inherited from PropertyHolder
00069 void JointOutputChannel::setProperties(map<string, Property>& properties){
00070         updateProperties(properties);
00071 }
00072 
00073 
00074 //Inherited from OutputChannel
00075 void JointOutputChannel::initialize(Writer* writer, map<string, Property>& properties){
00076         //This class requires an angle writer, so cast and check
00077         this->writer = dynamic_cast<AngleWriter*>(writer);
00078         if(this->writer == NULL)
00079                 throw ISpikeException("Cannot initialize JointOutputChannel with a null writer.");
00080 
00081         //Update properties in this and dependent classes
00082         updateProperties(properties);
00083 
00084         //Set up current variables
00085         for(unsigned i=0; i<size(); ++i) {
00086                 currentVariables.push_back(0.0);
00087         }
00088 
00089         // Calculate angle covered by each current variable */
00090         double angleDist = (maxAngle - minAngle) / double(size()-1);
00091 
00092         // Populate the current variable angles
00093         for(unsigned n=0; n < size(); ++n) {
00094                 currentVariableAngles.push_back(minAngle + n * angleDist);
00095         }
00096 
00097         //Start the writer thread running
00098         this->writer->start();
00099 
00100         setInitialized(true);
00101 }
00102 
00103 
00104 //Inherited from Channel
00105 void JointOutputChannel::step(){
00106         //Check writer for errors
00107         if(writer->isError()){
00108                 LOG(LOG_CRITICAL)<<"AngleWriter Error: "<<writer->getErrorMessage();
00109                 throw ISpikeException("Error in AngleWriter");
00110         }
00111 
00112         // Exponential decay of variables
00113         for(vector<double>::iterator iter = currentVariables.begin(); iter != currentVariables.end(); ++iter) {
00114                 (*iter) *= rateOfDecay;
00115         }
00116 
00117         /* Now work out the weighted sum */
00118         double angleSum = 0.0;
00119         double weightSum = 0.0;
00120         for(unsigned n = 0; n < size(); ++n) {
00121                 angleSum += currentVariableAngles.at(n) * currentVariables.at(n);
00122                 weightSum += currentVariables.at(n);
00123         }
00124 
00125         //Calculate new angle
00126         double newAngle = 0.0;
00127         if(weightSum != 0.0)
00128                 newAngle = angleSum/weightSum;
00129 
00130         //Check angle is in range and set it in writer
00131         if(newAngle > maxAngle){
00132                 LOG(LOG_WARNING)<<"JointOutputChannel: New angle ("<<newAngle<<") exceeds the maximum ("<<maxAngle<<"). Has been limited to the maximum";
00133                 newAngle = maxAngle;
00134         }
00135         else if(newAngle < minAngle){
00136                 LOG(LOG_WARNING)<<"JointOutputChannel: New angle ("<<newAngle<<") is less than the minimum ("<<minAngle<<"). Has been limited to the minimum";
00137                 newAngle = minAngle;
00138         }
00139         writer->setAngle(newAngle);
00140 }
00141 
00142 
00143 /*--------------------------------------------------------------------*/
00144 /*---------              PROTECTED METHODS                     -------*/
00145 /*--------------------------------------------------------------------*/
00146 
00148 void JointOutputChannel::updateProperties(map<string, Property>& properties) {
00149         if(propertyMap.size() != properties.size())
00150                 throw ISpikeException("JointOutputChannel: Current properties do not match new properties.");
00151 
00152         updatePropertyCount = 0;
00153         for(map<string,Property>::iterator iter = properties.begin(); iter != properties.end(); ++iter){
00154                 //In updateReadOnly mode, only update properties that are not read only
00155                 if((isInitialized() && !propertyMap[iter->first].isReadOnly()) || !isInitialized()) {
00156                         string paramName = iter->second.getName();
00157                         switch (iter->second.getType()) {
00158                                 case Property::Integer: {
00159                                         if (paramName == NEURON_WIDTH_NAME)
00160                                                 setWidth(updateIntegerProperty(iter->second));
00161                                         else if (paramName == NEURON_HEIGHT_NAME)
00162                                                 setHeight(updateIntegerProperty(iter->second));
00163                                         else if (paramName == DEGREE_OF_FREEDOM_PROP)
00164                                                 writer->setDegreeOfFreedom(updateIntegerProperty(iter->second));
00165                                 }
00166                                 break;
00167                                 case Property::Double:{
00168                                         if (paramName == MIN_ANGLE_NAME)
00169                                                 minAngle = updateDoubleProperty(iter->second);
00170                                         else if (paramName == MAX_ANGLE_NAME)
00171                                                 maxAngle = updateDoubleProperty(iter->second);
00172                                         else if (paramName == RATE_OF_DECAY_NAME)
00173                                                 rateOfDecay = updateDoubleProperty(iter->second);
00174                                         else if (paramName == CURRENT_INCREMENT_NAME)
00175                                                 currentIncrement = updateDoubleProperty(iter->second);
00176                                 }
00177                                 break;
00178                                 case Property::Combo: break;
00179                                 case Property::String: break;
00180                                 default:
00181                                         throw ISpikeException("Property type not recognized.");
00182                         }
00183                 }
00184         }
00185 
00186         //Check angles are sensible
00187         if(maxAngle <= minAngle) {
00188                 throw ISpikeException("JointOutputChannel: Maximum angle must be greater than minimum angle");
00189         }
00190 
00191         //Check all properties were updated
00192         if(!isInitialized() && updatePropertyCount != propertyMap.size())
00193                 throw ISpikeException("JointOutputChannel: Some or all of the properties were not updated: ", updatePropertyCount);
00194 }
00195 
00196 
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Defines