MOOS 0.2375
|
00001 00002 // 00003 // MOOS - Mission Oriented Operating Suite 00004 // 00005 // A suit of Applications and Libraries for Mobile Robotics Research 00006 // Copyright (C) 2001-2005 Massachusetts Institute of Technology and 00007 // Oxford University. 00008 // 00009 // This software was written by Paul Newman and others 00010 // at MIT 2001-2002 and Oxford University 2003-2005. 00011 // email: pnewman@robots.ox.ac.uk. 00012 // 00013 // This file is part of a MOOS Basic (Common) Application. 00014 // 00015 // This program is free software; you can redistribute it and/or 00016 // modify it under the terms of the GNU General Public License as 00017 // published by the Free Software Foundation; either version 2 of the 00018 // License, or (at your option) any later version. 00019 // 00020 // This program is distributed in the hope that it will be useful, 00021 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00022 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00023 // General Public License for more details. 00024 // 00025 // You should have received a copy of the GNU General Public License 00026 // along with this program; if not, write to the Free Software 00027 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 00028 // 02111-1307, USA. 00029 // 00031 // MOOSSensorChannel.cpp: implementation of the CMOOSSensorChannel class. 00032 // 00034 #ifdef _WIN32 00035 #pragma warning(disable : 4786) 00036 #endif 00037 00038 #include "MOOSSensorChannel.h" 00039 #include "math.h" 00040 00042 // Construction/Destruction 00044 00045 CMOOSSensorChannel::CMOOSSensorChannel() 00046 { 00047 //how deep should the history be 00048 m_nHistoryDepth = 4; 00049 00050 00051 //by defualt streams are active at birth 00052 m_bActive = true; 00053 00054 //this must be set for each stream in the mission file 00055 //if it is to have an effect 00056 m_dfNoiseLimit = 10; 00057 00058 m_dfMean = 0; 00059 00060 m_dfStd = 0; 00061 00062 m_dfHistoryTimeSpan = 20; 00063 00064 m_bBuilt = false; 00065 00066 } 00067 00068 CMOOSSensorChannel::~CMOOSSensorChannel() 00069 { 00070 00071 } 00072 00073 00074 bool CMOOSSensorChannel::SetHistoryDepth(int nDepth) 00075 { 00076 m_nHistoryDepth = nDepth; 00077 return true; 00078 } 00079 00080 bool CMOOSSensorChannel::Add(CMOOSObservation &rObs) 00081 { 00082 00083 //have we already stored this observation? 00084 OBSLIST::iterator w; 00085 for(w = m_History.begin();w!=m_History.end();w++) 00086 { 00087 if(w->m_nID==rObs.m_nID) 00088 { 00089 //yes! 00090 //we do nothing (this isn't an error) 00091 return true; 00092 } 00093 } 00094 00095 //no -> store it now 00096 m_History.push_front(rObs); 00097 00098 //now sort list with biggest time at the front 00099 //default behaviour of sort is in ascending order.. 00100 m_History.sort(greater< CMOOSObservation >()); 00101 00102 00103 if(m_History.size()==m_nHistoryDepth) 00104 { 00105 AddToOutput("Working history (%d deep) for %s : BUILT", 00106 m_nHistoryDepth, 00107 m_sName.c_str()); 00108 m_bBuilt = true; 00109 } 00110 00111 00112 //now keep history a sensible length 00113 double dfSpan = m_History.front().m_dfTime-m_History.back().m_dfTime; 00114 while(m_History.size() >m_nHistoryDepth || dfSpan > m_dfHistoryTimeSpan) 00115 { 00116 m_History.pop_back(); 00117 dfSpan = m_History.front().m_dfTime-m_History.back().m_dfTime; 00118 } 00119 00120 return true; 00121 } 00122 00123 bool CMOOSSensorChannel::Agrees(CMOOSObservation &rObs) 00124 { 00125 //if small history can't make a call 00126 if(m_History.size()<m_nHistoryDepth) 00127 { 00128 return false; 00129 } 00130 00131 //set up the median filter 00132 m_MedianFilter.Initialise(0.9,0.8); 00133 00134 00135 bool bTest = false; 00136 if(bTest) 00137 { 00138 //test data 00139 double dfTest[] = {7,2,4,4,5,6,7}; 00140 00141 int i = 0; 00142 for(i =0;i<sizeof(dfTest)/sizeof(double);i++) 00143 { 00144 m_MedianFilter.AddData(i,dfTest[i],i); 00145 } 00146 00147 //calculte outliers 00148 m_MedianFilter.Calculate(); 00149 00150 //figure out how well the channel is doing (is it clean data) 00151 AutoDiagnose(); 00152 00153 for(i =0;i<sizeof(dfTest)/sizeof(double);i++) 00154 { 00155 if(!m_MedianFilter.IsInlier(i)) 00156 { 00157 MOOSTrace("Rejected fake obs %d\n",i); 00158 } 00159 } 00160 return true; 00161 } 00162 else 00163 { 00164 //add data 00165 OBSLIST::iterator p; 00166 00167 for(p = m_History.begin();p!=m_History.end();p++) 00168 { 00169 m_MedianFilter.AddData(p->m_dfTime,p->m_dfData,p->m_nID); 00170 } 00171 00172 00173 //calculte outliers 00174 m_MedianFilter.Calculate(); 00175 00176 //figure out how well the channel is doing (is it clean data) 00177 AutoDiagnose(); 00178 00179 if(m_bActive) 00180 { 00181 //previous auto-diagnose could have caused us to turn off.. 00182 return m_MedianFilter.IsInlier(rObs.m_nID); 00183 } 00184 else 00185 { 00186 //it did... 00187 return false; 00188 } 00189 } 00190 } 00191 00192 00193 bool CMOOSSensorChannel::SetNoiseLimit(double dfLimit) 00194 { 00195 m_dfNoiseLimit = dfLimit; 00196 return true; 00197 } 00198 00199 bool CMOOSSensorChannel::AutoDiagnose() 00200 { 00201 00202 00203 //figure out trajectory statistics... 00204 if(m_History.size()<m_nHistoryDepth) 00205 return true; 00206 00207 //need to fit a least medians line to data.... 00208 double dfChannelNoise; 00209 double dfOutlierRatio; 00210 double dfTotalStd; 00211 double dfMedianDistance; 00212 m_MedianFilter.GetStatus( dfChannelNoise, 00213 dfOutlierRatio, 00214 dfTotalStd, 00215 dfMedianDistance); 00216 00217 //MOOSTrace("Channel Noise = %f, OutlierRatio = %f%%\n",dfChannelNoise,dfOutlierRatio); 00218 00219 //robust stats is only good to about 50 % in ideal circumstances we'll back off a little 00220 // if((dfOutlierRatio>50 ||dfChannelNoise>=m_dfNoiseLimit) && dfTotalStd>m_dfNoiseLimit ) 00221 if((dfOutlierRatio>50 ||dfMedianDistance>=m_dfNoiseLimit)) 00222 { 00223 if(m_bActive==true) 00224 { 00225 00226 OBSLIST::iterator w; 00227 for(w = m_History.begin();w!=m_History.end();w++) 00228 { 00229 MOOSTrace("Data = %f\n",w->m_dfData); 00230 } 00231 00232 00233 string sOutput = MOOSFormat("%s is suspect %.1f percent are outliers (of %d), MedianDev = %.4f (limit %.4f): turning stream off!\n", 00234 m_sName.c_str(), 00235 dfOutlierRatio, 00236 m_nHistoryDepth, 00237 dfMedianDistance, 00238 m_dfNoiseLimit); 00239 00240 AddToOutput(sOutput); 00241 } 00242 00243 m_bActive=false; 00244 } 00245 else 00246 { 00247 if(m_bActive==false) 00248 { 00249 //tell the world we are re-enabling stream... 00250 string sOutput = MOOSFormat("Sensor Channel %s better behaved now : turning stream on!\n", 00251 m_sName.c_str()); 00252 00253 AddToOutput(sOutput); 00254 } 00255 m_bActive = true; 00256 } 00257 00258 return true; 00259 } 00260 00261 bool CMOOSSensorChannel::IsOnline() 00262 { 00263 return m_History.size()>=m_nHistoryDepth; 00264 } 00265 00266 double CMOOSSensorChannel::GetPercentFull() 00267 { 00268 return 100.0*m_History.size()/m_nHistoryDepth; 00269 } 00270 00271 void CMOOSSensorChannel::Trace() 00272 { 00273 MOOSTrace("\n*** CMOOSSensorChannel::Trace() ***\n"); 00274 m_MedianFilter.Trace(); 00275 } 00276 00277 bool CMOOSSensorChannel::IsBuilt() 00278 { 00279 return m_bBuilt; 00280 }