iSpike
2.1
Spike conversion library for robotics
|
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