00001 /*!@file ModelNeuron/LowPass.H Class declarations for temporal 00002 low-pass filter implemented as first-order differential with a 00003 possible firing rate function */ 00004 00005 // //////////////////////////////////////////////////////////////////// // 00006 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00007 // University of Southern California (USC) and the iLab at USC. // 00008 // See http://iLab.usc.edu for information about this project. // 00009 // //////////////////////////////////////////////////////////////////// // 00010 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00011 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00012 // in Visual Environments, and Applications'' by Christof Koch and // 00013 // Laurent Itti, California Institute of Technology, 2001 (patent // 00014 // pending; application number 09/912,225 filed July 23, 2001; see // 00015 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00016 // //////////////////////////////////////////////////////////////////// // 00017 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00018 // // 00019 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00020 // redistribute it and/or modify it under the terms of the GNU General // 00021 // Public License as published by the Free Software Foundation; either // 00022 // version 2 of the License, or (at your option) any later version. // 00023 // // 00024 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00025 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00026 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00027 // PURPOSE. See the GNU General Public License for more details. // 00028 // // 00029 // You should have received a copy of the GNU General Public License // 00030 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00031 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00032 // Boston, MA 02111-1307 USA. // 00033 // //////////////////////////////////////////////////////////////////// // 00034 // 00035 // Primary maintainer for this file: David Berg <dberg@usc.edu> 00036 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/ModelNeuron/LowPass.H $ 00037 00038 #ifndef MODELNEURON_LOWPASS_H_DEFINED 00039 #define MODELNEURON_LOWPASS_H_DEFINED 00040 00041 #include "ModelNeuron/SimUnit.H" 00042 00043 #include<cmath> 00044 // ###################################################################### 00045 // ! A set of policies for the integration method to use in our 00046 // lowpass filters. The equation to be solved is: 00047 // 00048 // dg/dt = (-g + H + I) / tau; 00049 // or 00050 // dg/dt = (-g + H) / tau + I; 00051 // 00052 // where g is the state variable, tau is a decay factor, H is the 00053 // steady state and I is the input. 00054 00055 //All integration policy classes should implement three functions: 00056 // 00057 // MyPolicy(const double& timestep, const double& steadystate, 00058 // const double& tau); 00059 // const double update(const double& in, const double& g) const; 00060 // const double update_nodecay_input(const double& in, const double& g) const; 00061 // 00062 // where MyPolicy is a constructor that takes the time step in ms, the 00063 // steady state value and the decay factor (in ms) as arguments. The 00064 // 'update' and 'update_nodecay_input' functions takes the current 00065 // input and value of the state variable to compute and return the 00066 // state at the next time step. 00067 // ###################################################################### 00068 // ! policy for the forward Euler method 00069 // ###################################################################### 00070 class LowPassFwdEuler 00071 { 00072 public: 00073 static const SimUnit::RateType RateType = SimUnit::NORMAL; 00074 00075 LowPassFwdEuler(const double& timestep, const double& h, const double& tau) : 00076 H(h), Tau(tau), itsTimeStep(timestep) { }; 00077 00078 ~LowPassFwdEuler() { }; 00079 00080 //! update using fwd euler 00081 void update(const double& in, double& g) const 00082 { g = g + itsTimeStep * (-1.0 * g + in + H) / Tau; }; 00083 00084 //! update without applying the decay factor to the input using fwd euler 00085 void update_nodecay_input(const double& in, double& g) const 00086 { g = g + itsTimeStep * (-1.0 * g + H) / Tau + in; }; 00087 00088 //timestep in ms, steady state value, kinetic time constant (msecs) 00089 double H, Tau; 00090 00091 private: 00092 double itsTimeStep; 00093 }; 00094 00095 // ###################################################################### 00096 // ! policy for the exponential Euler method 00097 // ###################################################################### 00098 class LowPassExpEuler 00099 { 00100 public: 00101 static const SimUnit::RateType RateType = SimUnit::STRICT; 00102 00103 LowPassExpEuler(const double& timestep, const double& h, const double& tau) : 00104 H(h), Tau(tau), B(1.0/Tau), E(exp(-1.0 * B * timestep)), E1(1 - E) { }; 00105 00106 ~LowPassExpEuler() { }; 00107 00108 //! update using exp euler 00109 void update(const double& in, double& g) const 00110 { 00111 double A = (H + in) / Tau; 00112 g = g * E + (A / B) * E1; 00113 }; 00114 00115 //! update without applying the decay factor to the input using fwd euler 00116 void update_nodecay_input(const double& in, double& g) const 00117 { 00118 double A = H / Tau + in; 00119 g = g * E + (A / B) * E1; 00120 }; 00121 00122 //timestep in ms, steady state value, kinetic time constant (msecs) 00123 double H, Tau; 00124 00125 private: 00126 double B; //steady state + input / tau 00127 double E; //exp (-1 * B * dt) 00128 double E1; //1 - E 00129 }; 00130 00131 // ###################################################################### 00132 // ! Functors that can serve as firing rate functions. Operator() must 00133 // take a double and return a double. 00134 // ###################################################################### 00135 namespace RateFunctions 00136 { 00137 // ###################################################################### 00138 // an empty rate function 00139 // ###################################################################### 00140 struct EmptyFunction 00141 { 00142 //constructor 00143 EmptyFunction() { }; 00144 //destructor 00145 ~EmptyFunction() { }; 00146 //get the name 00147 static const char* name() { return ""; }; 00148 //overload function call operator 00149 const double operator()(const double& in) const { return in; } 00150 }; 00151 00152 // ###################################################################### 00153 // full wave rectification firing rate function: 00154 // 00155 // f(x) = -x : x < 0 00156 // f(x) = x : x > 0 00157 // ###################################################################### 00158 struct FullRectifyFunction 00159 { 00160 //constructor 00161 FullRectifyFunction() { }; 00162 //destructor 00163 ~FullRectifyFunction() { }; 00164 //get the name 00165 static const char* name() { return "FullRectify"; }; 00166 //overload function call operator 00167 const double operator()(const double& in) const 00168 { 00169 return (in >= 0.0) ? in : -1.0 * in; 00170 } 00171 }; 00172 00173 // ###################################################################### 00174 // half wave rectification firing rate function: 00175 // 00176 // f(x) = 0 : x <= thresh 00177 // f(x) = x : x > thresh 00178 // ###################################################################### 00179 struct RectifyFunction 00180 { 00181 //constructor 00182 RectifyFunction(const double& thresh) : 00183 Thresh(thresh) { }; 00184 //destructor 00185 ~RectifyFunction() { }; 00186 //get the name 00187 static const char* name() { return "Rectify"; }; 00188 //overload function call operator 00189 const double operator()(const double& in) const 00190 { 00191 return (in > Thresh) ? in : 0.0; 00192 } 00193 //paramters 00194 double Thresh; 00195 }; 00196 00197 // ###################################################################### 00198 // half wave rectification with clipping. Make thresh and max the same 00199 // values to create a step function: 00200 // 0.0 in <= thresh 00201 // in if thresh < in < max 00202 // max if in >= max 00203 // ###################################################################### 00204 struct MaxRectFunction 00205 { 00206 //constructor 00207 MaxRectFunction(const double& thresh, const double& max) : 00208 Thresh(thresh), Max(max) { }; 00209 //destructor 00210 ~MaxRectFunction() { }; 00211 //get the name 00212 static const char* name() { return "MaxRect"; }; 00213 //overload function call operator 00214 const double operator()(const double& in) const 00215 { 00216 if (in <= Thresh) 00217 return 0.0; 00218 else if (in > Max) 00219 return Max; 00220 else 00221 return in; 00222 } 00223 //paramters 00224 double Thresh, Max; 00225 }; 00226 00227 // ###################################################################### 00228 // Step Function. 00229 // 0.0 in <= thresh 00230 // max if in > thresh 00231 // ###################################################################### 00232 struct StepFunction 00233 { 00234 //constructor 00235 StepFunction(const double& thresh, const double& max) : 00236 Thresh(thresh), Max(max) { }; 00237 //destructor 00238 ~StepFunction() { }; 00239 //get the name 00240 static const char* name() { return "Step"; }; 00241 //overload function call operator 00242 const double operator()(const double& in) const 00243 { 00244 if (in <= Thresh) 00245 return 0.0; 00246 else 00247 return Max; 00248 } 00249 //paramters 00250 double Thresh, Max; 00251 }; 00252 00253 // ###################################################################### 00254 // A version of the lowpass filter module with a firing threshold 00255 // and rate function described by: 00256 // R = 0; if I < theta 00257 // R = ln(I/theta) if I > theta 00258 // 00259 // Where R is the output rate, I is the 00260 // integrators current value, and theta is a threshold. 00261 // 00262 // From Durstewitz et al, 2000, Nature Reviews 00263 // ###################################################################### 00264 struct LogThreshFunction 00265 { 00266 //constructor 00267 LogThreshFunction(const double& theta) : Thresh(theta) { }; 00268 //destructor 00269 ~LogThreshFunction() { }; 00270 //get the name 00271 static const char* name() { return "LogThresh"; }; 00272 //overload function call operator 00273 const double operator()(const double& in) const 00274 { 00275 if (in < Thresh) 00276 return 0.0; 00277 else 00278 return log(in / Thresh); 00279 } 00280 //paramters 00281 double Thresh; 00282 }; 00283 00284 // ###################################################################### 00285 // A version of the lowpass filter module with a sigmoidal firing 00286 // rate function: 00287 // 00288 // f(x) = 1 / (1 + exp(-beta(u - u_not))) 00289 // 00290 // From Erlhagen & Bicho, 2006, J. Neural Engineering 00291 // ###################################################################### 00292 struct SigmoidFunction 00293 { 00294 //constructor 00295 SigmoidFunction(const double& thresh, const double& slope) : 00296 Thresh(thresh), Slope(slope) { }; 00297 //destructor 00298 ~SigmoidFunction() { }; 00299 //get the name 00300 static const char* name() { return "Sigmoid"; }; 00301 //overload function call operator 00302 const double operator()(const double& in) const 00303 { 00304 return 1 / ( 1 + exp(-1.0 * Slope * (in - Thresh)) ); 00305 } 00306 //paramters 00307 double Thresh, Slope; 00308 }; 00309 } 00310 00311 // ###################################################################### 00312 // lowpass filter: Defines a low pass filter with simple first order 00313 // dynamics: 00314 // 00315 // tau * dg/dt = -g + H + I; 00316 // 00317 // Users can choose between one of the solver types and rate functors 00318 // defined above. See solver and functor definitions for interface 00319 // requirements. Some rate functors constructors take parameters and 00320 // so three constructors are provided that take 0, 1 or 2 extra 00321 // parameters, which are passed to the rate functors. The parameters 00322 // will be assigned in the same order as in the functor 00323 // definition. Several typedefs are defined below for convenience. 00324 // ###################################################################### 00325 template <class RateFunc = RateFunctions::EmptyFunction, 00326 class IntType = LowPassExpEuler> 00327 class LowPassFilter: public SimUnit, public IntType 00328 { 00329 public: 00330 //! Constructor with default params 00331 LowPassFilter(const double& tau, //time constant msecs 00332 const double& h, //steady state 00333 const SimTime& timestep,//simulaton timestep 00334 const std::string& name = "Lowpass", 00335 const std::string& units = "pA"); 00336 00337 //! Constructor with default params, overload for RateFuncs with 1 param 00338 LowPassFilter(const double& tau, //time constant msecs 00339 const double& h, //steady state 00340 const double& param1,//param 1 for the rate function 00341 const SimTime& timestep, //simulaton timestep, 00342 const std::string& name = "Lowpass", 00343 const std::string& units = "pA"); 00344 00345 //! Constructor with default params, overload for RateFuncs with 2 param 00346 LowPassFilter(const double& tau, //time constant msecs 00347 const double& h, //steady state 00348 const double& param1,//param 1 for the rate function 00349 const double& param2,//param 2 for the rate function 00350 const SimTime& timestep, //simulaton timestep 00351 const std::string& name = "Lowpass", 00352 const std::string& units = "pA"); 00353 00354 //! destructor 00355 ~LowPassFilter() { }; 00356 00357 //! get the display output 00358 const double getDisplayOutput() const; 00359 00360 private: 00361 //! integrate a time step using exponential euler 00362 const double doIntegrate(const SimTime& dt, 00363 const double& ine, const double& inh); 00364 00365 //!initialize or reset internal variables 00366 void doInit(); 00367 00368 //! clone this object 00369 LowPassFilter<RateFunc, IntType>* doClone() const; 00370 00371 double itsG; // internal state 00372 RateFunc firingRate; // our firing rate functor 00373 }; 00374 00375 // ###################################################################### 00376 // typedefs 00377 // ###################################################################### 00378 typedef 00379 LowPassFilter<RateFunctions::EmptyFunction, LowPassExpEuler> LowPass; 00380 typedef 00381 LowPassFilter<RateFunctions::RectifyFunction, LowPassExpEuler> LowPassRectify; 00382 typedef 00383 LowPassFilter<RateFunctions::FullRectifyFunction, LowPassExpEuler> LowPassFullRectify; 00384 typedef 00385 LowPassFilter<RateFunctions::StepFunction, LowPassExpEuler> LowPassStep; 00386 typedef 00387 LowPassFilter<RateFunctions::MaxRectFunction, LowPassExpEuler> LowPassMaxRect; 00388 typedef 00389 LowPassFilter<RateFunctions::LogThreshFunction, LowPassExpEuler> LowPassLog; 00390 typedef 00391 LowPassFilter<RateFunctions::SigmoidFunction, LowPassExpEuler> LowPassSigmoid; 00392 00393 // ###################################################################### 00394 // register our objects 00395 // ###################################################################### 00396 namespace 00397 { 00398 typedef SimUnit::Factory LPFactory; 00399 typedef SimUnit::Creator LPCreator; 00400 //define creation functions 00401 struct RegisterLowPassFilter 00402 { 00403 RegisterLowPassFilter() 00404 { 00405 const double tau = 50.0; 00406 const SimTime time = SimTime::MSECS(1.0); 00407 LPFactory::instance().add("LowPass", 00408 LPCreator::make<LowPass>(tau, -0.5, time)); 00409 LPFactory::instance().add("LowPassRectify", 00410 LPCreator::make<LowPassRectify>(tau, -0.5, 0.0, time)); 00411 LPFactory::instance().add("LowPassFullRectify", 00412 LPCreator::make<LowPassFullRectify>(tau, 0.0, time)); 00413 LPFactory::instance().add("LowPassStep", 00414 LPCreator::make<LowPassStep>(tau, -0.5, 0.0, 1.0, time)); 00415 LPFactory::instance().add("LowPassMaxRect", 00416 LPCreator::make<LowPassMaxRect>(tau, -0.5, 0.0, 1.0, time)); 00417 LPFactory::instance().add("LowPassLog", 00418 LPCreator::make<LowPassLog>(tau, 0.0, 0.1, time)); 00419 LPFactory::instance().add("LowPassSigmoid", 00420 LPCreator::make<LowPassSigmoid>(tau, -0.5, 0.55, 12.0, time)); 00421 } 00422 }; 00423 static RegisterLowPassFilter registerlpf; 00424 } 00425 00426 00427 // ###################################################################### 00428 // ##### implementation for LowPassFilter 00429 // ###################################################################### 00430 // default case rate function takes 0 params 00431 // ###################################################################### 00432 template <class RateFunc, class IntType> inline 00433 LowPassFilter<RateFunc, IntType>::LowPassFilter(const double& tau, 00434 const double& h, 00435 const SimTime& timestep, 00436 const std::string& name, 00437 const std::string& units) : 00438 SimUnit(timestep, IntType::RateType, name+RateFunc::name(), units), 00439 IntType(timestep.msecs(), h, tau), itsG(h), firingRate() { }; 00440 00441 // ###################################################################### 00442 // default case rate function takes 1 params 00443 // ###################################################################### 00444 template <class RateFunc, class IntType> inline 00445 LowPassFilter<RateFunc, IntType>::LowPassFilter(const double& tau, 00446 const double& h, 00447 const double& param1, 00448 const SimTime& timestep, 00449 const std::string& name, 00450 const std::string& units) : 00451 SimUnit(timestep, IntType::RateType, name+RateFunc::name(), units), 00452 IntType(timestep.msecs(), h, tau), itsG(h), firingRate(param1) { }; 00453 00454 // ###################################################################### 00455 // default case rate function takes 2 params 00456 // ###################################################################### 00457 template <class RateFunc, class IntType> inline 00458 LowPassFilter<RateFunc, IntType>::LowPassFilter(const double& tau, 00459 const double& h, 00460 const double& param1, 00461 const double& param2, 00462 const SimTime& timestep, 00463 const std::string& name, 00464 const std::string& units) : 00465 SimUnit(timestep, IntType::RateType, name+RateFunc::name(), units), 00466 IntType(timestep.msecs(), h, tau), itsG(h), firingRate(param1, param2) { }; 00467 00468 // ###################################################################### 00469 template <class RateFunc, class IntType> inline 00470 const double LowPassFilter<RateFunc, IntType>::getDisplayOutput() const 00471 { 00472 return itsG; 00473 } 00474 00475 // ###################################################################### 00476 template <class RateFunc, class IntType> inline 00477 const double LowPassFilter<RateFunc, IntType>::doIntegrate(const SimTime& dt, 00478 const double& ine, 00479 const double& inh) 00480 { 00481 IntType::update(ine + inh, itsG);//update inherited from template parameter 00482 return firingRate(itsG); 00483 } 00484 00485 // ###################################################################### 00486 template <class RateFunc, class IntType> inline 00487 void LowPassFilter<RateFunc, IntType>::doInit() 00488 { 00489 itsG = IntType::H; 00490 } 00491 00492 // ###################################################################### 00493 template <class RateFunc, class IntType> inline 00494 LowPassFilter<RateFunc, IntType>* 00495 LowPassFilter<RateFunc, IntType>::doClone() const 00496 { 00497 return new LowPassFilter<RateFunc, IntType>(*this); 00498 } 00499 00500 #endif 00501 // ###################################################################### 00502 /* So things look consistent in everyone's emacs... */ 00503 /* Local Variables: */ 00504 /* indent-tabs-mode: nil */ 00505 /* End: */