00001 /*!@file ModelNeuron/NeuralDecoder.C Class declaration for a neural 00002 simulation module*/ 00003 00004 // //////////////////////////////////////////////////////////////////// // 00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00006 // University of Southern California (USC) and the iLab at USC. // 00007 // See http://iLab.usc.edu for information about this project. // 00008 // //////////////////////////////////////////////////////////////////// // 00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00011 // in Visual Environments, and Applications'' by Christof Koch and // 00012 // Laurent Itti, California Institute of Technology, 2001 (patent // 00013 // pending; application number 09/912,225 filed July 23, 2001; see // 00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00015 // //////////////////////////////////////////////////////////////////// // 00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00017 // // 00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00019 // redistribute it and/or modify it under the terms of the GNU General // 00020 // Public License as published by the Free Software Foundation; either // 00021 // version 2 of the License, or (at your option) any later version. // 00022 // // 00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00026 // PURPOSE. See the GNU General Public License for more details. // 00027 // // 00028 // You should have received a copy of the GNU General Public License // 00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00031 // Boston, MA 02111-1307 USA. // 00032 // //////////////////////////////////////////////////////////////////// // 00033 // 00034 // Primary maintainer for this file: David Berg <dberg@usc.edu> 00035 // $HeadURL:svn://ilab.usc.edu/trunk/saliency/src/ModelNeuron/NeuralDecoder.C$ 00036 00037 #include "ModelNeuron/NeuralDecoder.H" 00038 00039 #include <cmath> 00040 00041 // ###################################################################### 00042 //! implementations of NeuralDecoder 00043 // ##################################################################### 00044 NeuralDecoder::NeuralDecoder(const NeuralDecoder& rhs) : 00045 itsWindowSize(rhs.itsWindowSize), itsSamples(rhs.itsSamples) 00046 { 00047 } 00048 00049 // ###################################################################### 00050 NeuralDecoder& NeuralDecoder::operator=(const NeuralDecoder& rhs) 00051 { 00052 if (this != &rhs) 00053 { 00054 itsWindowSize = rhs.itsWindowSize; 00055 itsSamples = rhs.itsSamples; 00056 } 00057 return *this; 00058 } 00059 00060 // ###################################################################### 00061 //! implementations of HoldDecoder 00062 // ###################################################################### 00063 void HoldDecoder::push(const double& data) 00064 { 00065 if (itsSignal.size() < 1) 00066 itsLastSpike = data; 00067 else 00068 { 00069 itsSignal.push_back(data); 00070 itsLastSpike = itsSignal.front(); 00071 itsSignal.pop_front(); 00072 } 00073 } 00074 00075 // ###################################################################### 00076 const double HoldDecoder::getOutput() const 00077 { 00078 return itsLastSpike; 00079 } 00080 00081 // ###################################################################### 00082 void HoldDecoder::reset() 00083 { 00084 itsLastSpike = 0.0; 00085 itsSignal.clear(); 00086 itsSignal.resize(itsSamples, 0.0); 00087 } 00088 00089 // ###################################################################### 00090 //! implementations of HistDecoder 00091 // ###################################################################### 00092 void HistDecoder::push(const double& data) 00093 { 00094 00095 itsSpikeCount += data; 00096 itsSampleCount++; 00097 00098 if (itsSampleCount == itsSamples) 00099 { 00100 itsSampleCount = 0; 00101 itsLastCount = itsSpikeCount; 00102 itsSpikeCount = 0.0; 00103 } 00104 } 00105 00106 // ###################################################################### 00107 const double HistDecoder::getOutput() const 00108 { 00109 return itsLastCount / itsWindowSize.secs(); 00110 } 00111 00112 // ###################################################################### 00113 void HistDecoder::reset() 00114 { 00115 itsSpikeCount = 0; 00116 itsLastCount = 0.0; 00117 itsSampleCount = 0; 00118 } 00119 00120 // ###################################################################### 00121 //! implementations of RectDecoder 00122 // ###################################################################### 00123 void RectDecoder::push(const double& data) 00124 { 00125 itsSpikeRate += data - itsSignal.front(); 00126 itsSignal.pop_front(); 00127 itsSignal.push_back(data); 00128 } 00129 00130 // ###################################################################### 00131 const double RectDecoder::getOutput() const 00132 { 00133 return itsSpikeRate / itsWindowSize.secs(); 00134 } 00135 00136 // ###################################################################### 00137 void RectDecoder::reset() 00138 { 00139 itsSpikeRate = 0.0; 00140 itsSignal.clear(); 00141 itsSignal.resize(itsSamples, 0.0); 00142 } 00143 00144 // ###################################################################### 00145 //! implementations of ExpDecoder 00146 // ###################################################################### 00147 void ExpDecoder::push(const double& data) 00148 { 00149 itsSpikeRate *= itsAlpha; 00150 itsSpikeRate += (1.0-itsAlpha)*data; 00151 } 00152 00153 // ###################################################################### 00154 const double ExpDecoder::getOutput() const 00155 { 00156 return itsSpikeRate; 00157 } 00158 00159 // ###################################################################### 00160 void ExpDecoder::reset() 00161 { 00162 itsSpikeRate = 0.0; 00163 } 00164 00165 // ###################################################################### 00166 //! implementation of AlphaDecoder 00167 // ###################################################################### 00168 AlphaDecoder::AlphaDecoder(const SimTime& timeStep, 00169 const SimTime& windowSize) : 00170 NeuralDecoderDerived<AlphaDecoder>(timeStep,windowSize), 00171 itsSignal(), itsKernel() 00172 { 00173 const double a = 1.0 / windowSize.secs(); 00174 //find the optimal array size of the filter if we truncate at a 00175 //small value, C. No easy analytical solution exists to this problem, 00176 //so lets just use newtons method of roots to approximate 00177 double C = 0.0001; 00178 //our initial estimate b. Since 1/a should define the peak of the 00179 //function in time, a good place to start is just a little beond that. 00180 double b = 1.0/a + 0.1 * (1.0 / a); 00181 for (int i = 0; i < 20; i++) 00182 { 00183 //our function 00184 double func = (a*a) * b * exp(-1 * a * b); 00185 //its second derivitive 00186 double func2 = ( (a*a) - (a * a * a) * b ) / exp(a * b); 00187 b = b - ( func - C ) / func2; 00188 } 00189 SimTime end = SimTime::SECS(b); 00190 SimTime ii = SimTime::SECS(-1*b); 00191 for (; ii < end; ii += timeStep) 00192 { 00193 if (ii > SimTime::ZERO()) 00194 { 00195 double temp = (a * a) * ii.secs() * exp(-1.0 * a * ii.secs()); 00196 itsKernel.push_back(temp); 00197 } 00198 } 00199 itsSignal.resize(itsKernel.size(),0.0); 00200 } 00201 00202 // ###################################################################### 00203 void AlphaDecoder::push(const double& data) 00204 { 00205 itsSignal.push_back(data); 00206 itsSignal.pop_front(); 00207 } 00208 00209 // ###################################################################### 00210 const double AlphaDecoder::getOutput() const 00211 { 00212 std::vector<double>::const_reverse_iterator iter = itsKernel.rbegin(); 00213 std::deque<double>::const_iterator iters = itsSignal.begin(); 00214 double val = 0.0; 00215 while (iters != itsSignal.end()) 00216 val += (*iter++) * (*iters++); 00217 return val; 00218 } 00219 00220 // ###################################################################### 00221 void AlphaDecoder::reset() 00222 { 00223 itsSignal.clear(); 00224 } 00225 00226 // ###################################################################### 00227 /* So things look consistent in everyone's emacs... */ 00228 /* Local Variables: */ 00229 /* indent-tabs-mode: nil */ 00230 /* End: */