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: */