LoExperiment.C

00001 /**
00002    \file  Robots/LoBot/misc/LoExperiment.C
00003    \brief This file defines the non-inline member functions of the
00004    lobot::Experiment class.
00005 */
00006 
00007 // //////////////////////////////////////////////////////////////////// //
00008 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005   //
00009 // by the University of Southern California (USC) and the iLab at USC.  //
00010 // See http://iLab.usc.edu for information about this project.          //
00011 // //////////////////////////////////////////////////////////////////// //
00012 // Major portions of the iLab Neuromorphic Vision Toolkit are protected //
00013 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency //
00014 // in Visual Environments, and Applications'' by Christof Koch and      //
00015 // Laurent Itti, California Institute of Technology, 2001 (patent       //
00016 // pending; application number 09/912,225 filed July 23, 2001; see      //
00017 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status).     //
00018 // //////////////////////////////////////////////////////////////////// //
00019 // This file is part of the iLab Neuromorphic Vision C++ Toolkit.       //
00020 //                                                                      //
00021 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can   //
00022 // redistribute it and/or modify it under the terms of the GNU General  //
00023 // Public License as published by the Free Software Foundation; either  //
00024 // version 2 of the License, or (at your option) any later version.     //
00025 //                                                                      //
00026 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope  //
00027 // that it will be useful, but WITHOUT ANY WARRANTY; without even the   //
00028 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
00029 // PURPOSE.  See the GNU General Public License for more details.       //
00030 //                                                                      //
00031 // You should have received a copy of the GNU General Public License    //
00032 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write   //
00033 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,   //
00034 // Boston, MA 02111-1307 USA.                                           //
00035 // //////////////////////////////////////////////////////////////////// //
00036 //
00037 // Primary maintainer for this file: mviswana usc edu
00038 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Robots/LoBot/metlog/LoExperiment.C $
00039 // $Id: LoExperiment.C 14285 2010-12-01 17:33:15Z mviswana $
00040 //
00041 
00042 //------------------------------ HEADERS --------------------------------
00043 
00044 // lobot headers
00045 #include "Robots/LoBot/metlog/LoExperiment.H"
00046 #include "Robots/LoBot/config/LoConfigHelpers.H"
00047 #include "Robots/LoBot/util/LoFile.H"
00048 #include "Robots/LoBot/misc/LoExcept.H"
00049 #include "Robots/LoBot/misc/singleton.hh"
00050 
00051 // Standard C++ headers
00052 #include <iomanip>
00053 #include <fstream>
00054 #include <algorithm>
00055 #include <iterator>
00056 
00057 //----------------------------- NAMESPACE -------------------------------
00058 
00059 namespace lobot {
00060 
00061 //-------------------------- KNOB TWIDDLING -----------------------------
00062 
00063 namespace {
00064 
00065 // Retrieve settings from global section of config file
00066 template<typename T>
00067 inline T conf(const std::string& key, const T& default_value)
00068 {
00069    return lobot::global_conf<T>(key, default_value) ;
00070 }
00071 
00072 /// This inner class encapsulates various parameters that can be used
00073 /// to tweak different aspects of the trajectory metrics analysis.
00074 class ExperimentParams : public singleton<ExperimentParams> {
00075    /// The metlog files collected as part of the trajectory experiments
00076    /// will contain several "tracking speed" entries. Some of these speed
00077    /// entries will have negative or small values, indicating brief
00078    /// periods wherein the robot was backing up from an obstacle or
00079    /// speeding up to its normal forward driving speed.
00080    ///
00081    /// These negative and small speeds will incorrectly skew the average
00082    /// forward driving speed computation. To work around the problem, we
00083    /// ignore speed entries below a certain threshold.
00084    ///
00085    /// This setting specifies the value of the above-mentioned threshold.
00086    /// It should be a a floating point number expressed in meters per
00087    /// second.
00088    ///
00089    /// NOTE: A good way to pick this threshold is to look at the forward
00090    /// behaviour's section in the lobot config file used in conjunction
00091    /// with the experiments that yielded the dataset being used as the
00092    /// input for the lomet program and set this value to something
00093    /// reasonably close to but slightly lower than the cruising speed
00094    /// configured there.
00095    ///
00096    /// Alternatively, we can also peek at the metlogs themselves and
00097    /// decide on a suitable figure.
00098    float m_forward_speed_threshold ;
00099 
00100    /// Private constructor because this is a singleton.
00101    ExperimentParams() ;
00102 
00103    // Boilerplate code to make generic singleton design pattern work
00104    friend class singleton<ExperimentParams> ;
00105 
00106 public:
00107    /// Accessing the various parameters.
00108    //@{
00109    static float forward_speed_threshold() {
00110       return instance().m_forward_speed_threshold ;
00111    }
00112    //@}
00113 } ;
00114 
00115 // Parameters initialization
00116 ExperimentParams::ExperimentParams()
00117    : m_forward_speed_threshold(conf("forward_speed_threshold", 0.099f))
00118 {}
00119 
00120 // Shortcut
00121 typedef ExperimentParams Params ;
00122 
00123 } // end of local anonymous namespace encapsulating above helpers
00124 
00125 //-------------------------- INITIALIZATION -----------------------------
00126 
00127 Experiment* Experiment::create(const std::string& name)
00128 {
00129    return new Experiment(name) ;
00130 }
00131 
00132 Experiment::Experiment(const std::string& name)
00133    : m_name(name),
00134      m_start_time(0), m_finis_time(0),
00135      m_trajectory(300),
00136      m_emergency_stop(100),
00137      m_extricate(100),
00138      m_lgmd_extricate(100),
00139      m_bump(5),
00140      m_emstop_stats(0, 0),
00141      m_lrf_extr_stats(0, 0),
00142      m_lgmd_extr_stats(0, 0),
00143      m_total_extr_stats(0, 0),
00144      m_lgmd_success_stats(0, 0),
00145      m_duration_stats(0, 0)
00146 {
00147    m_speed.reserve(40) ;
00148 }
00149 
00150 //-------------------------- RECORDING DATA -----------------------------
00151 
00152 // Add a point to the named list
00153 void Experiment::add_point(PointListName n, int x, int y)
00154 {
00155    switch (n)
00156    {
00157       case TRAJECTORY:
00158          add_trajectory(x, y) ;
00159          break ;
00160       case EMERGENCY_STOP:
00161          add_emergency_stop(x, y) ;
00162          break ;
00163       case EXTRICATE:
00164          add_extricate(x, y) ;
00165          break ;
00166       case LGMD_EXTRICATE:
00167          add_lgmd_extricate(x, y) ;
00168          break ;
00169       case BUMP:
00170          add_bump(x, y) ;
00171          break ;
00172       default:
00173          throw misc_error(LOGIC_ERROR) ;
00174    }
00175 }
00176 
00177 // Add an entire point list instead of one piddling point at a time...
00178 void Experiment::point_list(PointListName n, const PointList& L)
00179 {
00180    switch (n)
00181    {
00182       case TRAJECTORY:
00183          m_trajectory = L ;
00184          break ;
00185       case EMERGENCY_STOP:
00186          m_emergency_stop = L ;
00187          break ;
00188       case EXTRICATE:
00189          m_extricate = L ;
00190          break ;
00191       case LGMD_EXTRICATE:
00192          m_lgmd_extricate = L ;
00193          break ;
00194       case BUMP:
00195          m_bump = L ;
00196          break ;
00197       default:
00198          throw misc_error(LOGIC_ERROR) ;
00199    }
00200 }
00201 
00202 // We are only interested in recording those speeds that correspond to
00203 // normal forward driving. To determine whether a speed qualifies for
00204 // this exalted status, we use a threshold specified in the config file.
00205 // Values below this threshold will be assumed to indicate the robot
00206 // backing up or accelerating to a "normal" forward driving speed.
00207 void Experiment::add_speed(float speed)
00208 {
00209    if (speed >= Params::forward_speed_threshold())
00210       m_speed.push_back(speed) ;
00211 }
00212 
00213 // Append an entire vector of speed readings to this object's list of
00214 // speed readings.
00215 void Experiment::speed_list(const std::vector<float>& speeds)
00216 {
00217    std::copy(speeds.begin(), speeds.end(), std::back_inserter(m_speed)) ;
00218 }
00219 
00220 //-------------------------- ACCESSING DATA -----------------------------
00221 
00222 int Experiment::size(PointListName n) const
00223 {
00224    switch (n)
00225    {
00226       case TRAJECTORY:
00227          return trajectory_size() ;
00228       case EMERGENCY_STOP:
00229          return emergency_stop_size() ;
00230       case EXTRICATE:
00231          return extricate_size() ;
00232       case LGMD_EXTRICATE:
00233          return lgmd_extricate_size() ;
00234       case BUMP:
00235          return bump_size() ;
00236    }
00237    throw misc_error(LOGIC_ERROR) ;
00238 }
00239 
00240 const PointList& Experiment::point_list(PointListName n) const
00241 {
00242    switch (n)
00243    {
00244       case TRAJECTORY:
00245          return m_trajectory ;
00246       case EMERGENCY_STOP:
00247          return m_emergency_stop ;
00248       case EXTRICATE:
00249          return m_extricate ;
00250       case LGMD_EXTRICATE:
00251          return m_lgmd_extricate ;
00252       case BUMP:
00253          return m_bump ;
00254    }
00255    throw misc_error(LOGIC_ERROR) ;
00256 }
00257 
00258 //---------------------------- SAVING DATA ------------------------------
00259 
00260 static void
00261 save_point_list(std::ostream& os, const PointList& L, const char* label)
00262 {
00263    for (PointList::iterator i = L.begin(); i != L.end(); ++i)
00264       os << label << ' ' << i->first << ' ' << i->second << '\n' ;
00265 }
00266 
00267 static std::ostream&
00268 operator<<(std::ostream& os, const generic_stats<int>& s)
00269 {
00270    os << s.n    << ' ' << s.sum << ' ' << s.ssq << ' '
00271       << s.mean << ' ' << s.stdev ;
00272    return os ;
00273 }
00274 
00275 static std::ostream&
00276 operator<<(std::ostream& os, const generic_stats<float>& s)
00277 {
00278    using std::setprecision ; using std::fixed ;
00279    os << s.n << ' '
00280       << setprecision(3) << fixed << s.sum  << ' '
00281       << setprecision(3) << fixed << s.ssq  << ' '
00282       << setprecision(3) << fixed << s.mean << ' '
00283       << setprecision(3) << fixed << s.stdev ;
00284    return os ;
00285 }
00286 
00287 bool Experiment::save() const
00288 {
00289    if (exists(m_name.c_str()))
00290       return false ;
00291 
00292    std::ofstream ofs(m_name.c_str()) ;
00293    save_point_list(ofs, m_trajectory,     "trajectory") ;
00294    save_point_list(ofs, m_emergency_stop, "emergency_stop") ;
00295    save_point_list(ofs, m_extricate,      "extricate") ;
00296    save_point_list(ofs, m_lgmd_extricate, "lgmd_extricate") ;
00297    save_point_list(ofs, m_bump,           "bump") ;
00298 
00299    ofs << "emstop_stats " << m_emstop_stats << '\n' ;
00300    ofs << "lrf_extrication_stats "   << m_lrf_extr_stats     << '\n' ;
00301    ofs << "lgmd_extrication_stats "  << m_lgmd_extr_stats    << '\n' ;
00302    ofs << "total_extrication_stats " << m_total_extr_stats   << '\n' ;
00303    ofs << "lgmd_success_rate_stats " << m_lgmd_success_stats << '\n' ;
00304    ofs << "extr_success_rate_stats " << m_extr_success_stats << '\n' ;
00305    ofs << "speed_stats "
00306        << compute_stats<float>(m_speed.begin(),m_speed.end())<< '\n' ;
00307    ofs << "duration_stats " << m_duration_stats << '\n' ;
00308 
00309    return true ;
00310 }
00311 
00312 //--------------------------- DEBUG SUPPORT -----------------------------
00313 
00314 static void
00315 dump_trajectory(std::ostream& os, const PointList& L, const char* label)
00316 {
00317    os << L.size() << ' ' << label << " points:\n\t" ;
00318 
00319    using namespace std ;
00320    for (PointList::iterator i = L.begin(); i != L.end(); ++i)
00321       os << '(' << left << setw(6) << i->first << i->second << ")\n\t" ;
00322    os << "\n\n" ;
00323 }
00324 
00325 void Experiment::dump() const
00326 {
00327    using namespace std ;
00328 
00329    ofstream ofs((m_name + ".dump").c_str()) ;
00330    ofs << "name: " << m_name << "\n\n" ;
00331 
00332    ofs << "start time: " << m_start_time    << '\n' ;
00333    ofs << "finis time: " << m_finis_time    << '\n' ;
00334    ofs << "  duration: " << setprecision(3) << fixed
00335        << (duration()/1000.0f) << " seconds\n\n" ;
00336 
00337    dump_trajectory(ofs, m_trajectory, "normal trajectory") ;
00338    dump_trajectory(ofs, m_emergency_stop, "emergency stop") ;
00339    dump_trajectory(ofs, m_extricate, "extricate") ;
00340    dump_trajectory(ofs, m_lgmd_extricate, "LGMD extricate") ;
00341    dump_trajectory(ofs, m_bump, "bump") ;
00342 
00343    std::pair<float, float> s =
00344       mean_stdev<float>(m_speed.begin(), m_speed.end()) ;
00345    ofs << "forward driving speed = "
00346        << setprecision(3) << fixed << s.first  << " m/s +/- "
00347        << setprecision(3) << fixed << s.second << " m/s from "
00348        << m_speed.size()  << " readings:\n\t" ;
00349    copy(m_speed.begin(), m_speed.end(),
00350         ostream_iterator<float>(ofs, " m/s\n\t")) ;
00351    ofs << '\n' ;
00352 }
00353 
00354 //-----------------------------------------------------------------------
00355 
00356 } // end of namespace encapsulating this file's definitions
00357 
00358 /* So things look consistent in everyone's emacs... */
00359 /* Local Variables: */
00360 /* indent-tabs-mode: nil */
00361 /* End: */
Generated on Sun May 8 08:41:30 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3