Main MRPT website > C++ reference for MRPT 1.9.9
CObservationGasSensors.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2017, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "obs-precomp.h" // Precompiled headers
11 
13 #include <mrpt/utils/CStream.h>
14 #include <mrpt/system/os.h>
15 
16 using namespace mrpt::obs;
17 using namespace mrpt::utils;
18 using namespace mrpt::poses;
19 using namespace mrpt::math;
20 using namespace std;
21 
22 // This must be added to any CSerializable class implementation file.
24 
25 /** Constructor
26  */
28 /*---------------------------------------------------------------
29  Implements the writing to a CStream capability of CSerializable objects
30  ---------------------------------------------------------------*/
32  mrpt::utils::CStream& out, int* version) const
33 {
34  if (version)
35  *version = 5;
36  else
37  {
38  uint32_t i, n = m_readings.size();
39  out << n;
40 
41  for (i = 0; i < n; i++)
42  {
43  out << CPose3D(m_readings[i].eNosePoseOnTheRobot);
44  out << m_readings[i].readingsVoltage;
45  out << m_readings[i].sensorTypes;
46  out << m_readings[i].hasTemperature;
47  if (m_readings[i].hasTemperature) out << m_readings[i].temperature;
48  }
49 
50  out << sensorLabel << timestamp;
51  }
52 }
53 
54 /*---------------------------------------------------------------
55  Implements the reading from a CStream capability of CSerializable objects
56  ---------------------------------------------------------------*/
58  mrpt::utils::CStream& in, int version)
59 {
60  switch (version)
61  {
62  case 2:
63  case 3:
64  case 4:
65  case 5:
66  {
67  // A general set of e-nose descriptors:
68  uint32_t i, n;
69 
70  in >> n;
71  m_readings.resize(n);
72 
73  CPose3D aux;
74 
75  for (i = 0; i < n; i++)
76  {
77  in >> aux;
78  m_readings[i].eNosePoseOnTheRobot = aux;
79  in >> m_readings[i].readingsVoltage;
80  in >> m_readings[i].sensorTypes;
81  if (version >= 3)
82  {
83  in >> m_readings[i].hasTemperature;
84  if (m_readings[i].hasTemperature)
85  in >> m_readings[i].temperature;
86  }
87  else
88  {
89  m_readings[i].hasTemperature = false;
90  m_readings[i].temperature = 0;
91  }
92  }
93 
94  if (version >= 4)
95  in >> sensorLabel;
96  else
97  sensorLabel = "";
98 
99  if (version >= 5)
100  in >> timestamp;
101  else
102  timestamp = INVALID_TIMESTAMP;
103  }
104  break;
105  case 0:
106  case 1:
107  {
108  TObservationENose eNose;
109 
110  m_readings.clear();
111 
112  // There was a single set of 16 values from "Sancho" (DEC-2006)
113  CVectorFloat readings;
114  in >> readings;
115 
116  ASSERT_(readings.size() == 16);
117 
118  // There was TWO e-noses:
119  // (1)
120  eNose.eNosePoseOnTheRobot =
121  CPose3D(0.20f, -0.15f, 0.10f); // (x,y,z) only
122  eNose.readingsVoltage.resize(4);
123  eNose.readingsVoltage[0] = readings[2];
124  eNose.readingsVoltage[1] = readings[4];
125  eNose.readingsVoltage[2] = readings[5];
126  eNose.readingsVoltage[3] = readings[6];
127 
128  eNose.sensorTypes.clear();
129  eNose.sensorTypes.resize(4, 0);
130  m_readings.push_back(eNose);
131 
132  // (2)
133  eNose.eNosePoseOnTheRobot =
134  CPose3D(0.20f, 0.15f, 0.10f); // (x,y,z) only
135  eNose.readingsVoltage.resize(4);
136  eNose.readingsVoltage[0] = readings[8];
137  eNose.readingsVoltage[1] = readings[10];
138  eNose.readingsVoltage[2] = readings[12];
139  eNose.readingsVoltage[3] = readings[14];
140 
141  eNose.sensorTypes.clear();
142  eNose.sensorTypes.resize(4, 0);
143  m_readings.push_back(eNose);
144  }
145  break;
146  default:
148  };
149 }
150 
151 /*---------------------------------------------------------------
152  getSensorPose
153  ---------------------------------------------------------------*/
155 {
156  if (!m_readings.empty())
157  out_sensorPose = CPose3D(m_readings[0].eNosePoseOnTheRobot);
158  else
159  out_sensorPose = CPose3D(0, 0, 0);
160 }
161 
162 /*---------------------------------------------------------------
163  setSensorPose
164  ---------------------------------------------------------------*/
166 {
167  size_t i, n = m_readings.size();
168  if (n)
169  for (i = 0; i < n; i++)
170  m_readings[i].eNosePoseOnTheRobot =
171  mrpt::math::TPose3D(newSensorPose);
172 }
173 
174 /*---------------------------------------------------------------
175  CMOSmodel
176  ---------------------------------------------------------------*/
177 /** Constructor
178  */
179 
181  : winNoise_size(30),
182  decimate_value(6),
183  a_rise(0),
184  b_rise(0),
185  a_decay(0),
186  b_decay(0),
187  save_maplog(false),
188  last_Obs(),
189  temporal_Obs(),
190  m_debug_dump(nullptr),
191  decimate_count(1),
192  fixed_incT(0),
193  first_incT(true),
194  min_reading(10),
195  first_iteration(true)
196 {
197 }
198 
200 /*---------------------------------------------------------------
201  get_GasDistribution_estimation
202  ---------------------------------------------------------------*/
204  float& reading, mrpt::system::TTimeStamp& timestamp)
205 {
206  try
207  {
208  // Noise filtering
209  noise_filtering(reading, timestamp);
210 
211  // Decimate
212  if (decimate_count != decimate_value)
213  {
214  decimate_count++;
215  return false;
216  }
217 
218  // Gas concentration estimation based on FIRST ORDER + NONLINEAR
219  // COMPENSATIONS DYNAMICS
220  inverse_MOSmodeling(
221  m_antiNoise_window[winNoise_size / 2].reading_filtered,
222  m_antiNoise_window[winNoise_size / 2].timestamp);
223  decimate_count = 1;
224 
225  // update (output)
226  reading = last_Obs.estimation;
227  timestamp = last_Obs.timestamp;
228 
229  // Save data map in log file for Matlab visualization
230  if (save_maplog)
231  save_log_map(
232  last_Obs.timestamp, last_Obs.reading, last_Obs.estimation,
233  last_Obs.tau);
234 
235  return true;
236  }
237  catch (...)
238  {
239  cout << "Error when decimating \n";
241  return false;
242  }
243 }
244 
245 /*---------------------------------------------------------------
246  noise_filtering (smooth)
247  ---------------------------------------------------------------*/
249  const float& reading, const mrpt::system::TTimeStamp& timestamp)
250 {
251  try
252  {
253  // Store values in the temporal Observation
254  temporal_Obs.reading = reading;
255  temporal_Obs.timestamp = timestamp;
256 
257  // If first reading from E-nose
258  if (m_antiNoise_window.empty())
259  {
260  // use default values
261  temporal_Obs.reading_filtered = reading;
262 
263  // Populate the noise window
264  m_antiNoise_window.assign(winNoise_size, temporal_Obs);
265  }
266  else
267  {
268  // Erase the first element (the oldest), and add the new one
269  m_antiNoise_window.erase(m_antiNoise_window.begin());
270  m_antiNoise_window.push_back(temporal_Obs);
271  }
272 
273  // Average data to reduce noise (Noise Filtering)
274  float partial_sum = 0;
275  for (size_t i = 0; i < m_antiNoise_window.size(); i++)
276  partial_sum += m_antiNoise_window.at(i).reading;
277 
278  m_antiNoise_window.at(winNoise_size / 2).reading_filtered =
279  partial_sum / winNoise_size;
280  }
281  catch (...)
282  {
283  cout << "Error when filtering noise from readings \n";
285  }
286 }
287 
288 /*---------------------------------------------------------------
289  inverse_MOSmodeling
290  ---------------------------------------------------------------*/
292  const float& reading, const mrpt::system::TTimeStamp& timestamp)
293 {
294  try
295  {
296  // Keep the minimum reading value as an approximation to the basline
297  // level
298  if (reading < min_reading) min_reading = reading;
299 
300  // Check if estimation posible (not possible in the first iteration)
301  if (!first_iteration)
302  {
303  // Assure the samples are provided at constant rate (important for
304  // the correct gas distribution estimation)
305  double incT =
306  mrpt::system::timeDifference(last_Obs.timestamp, timestamp);
307 
308  if ((incT > 0) & (!first_incT))
309  { // not the same sample due to initialization of buffers
310  if (fixed_incT == 0)
311  fixed_incT = incT;
312  else
313  // ASSERT_(fabs(incT - fixed_incT) < (double)(0.05));
314  if (fabs(incT - fixed_incT) > (double)(0.05))
315  cout << "IncT is not constant by HW." << endl;
316  }
317  else
318  {
319  if (incT > 0) first_incT = false;
320  }
321 
322  // slope<0 -->Decay
323  if (reading < last_Obs.reading)
324  {
325  last_Obs.tau = a_decay * abs(reading - min_reading) + b_decay;
326  }
327  else // slope>=0 -->rise
328  {
329  last_Obs.tau = a_rise * abs(reading - min_reading) + b_rise;
330  } // end-if
331 
332  // New estimation values -- Ziegler-Nichols model --
333  if (incT > 0)
334  // Initially there may come repetetive values till
335  // m_antiNoise_window is full populated.
336  last_Obs.estimation =
337  ((reading - last_Obs.reading) * last_Obs.tau / incT) +
338  reading;
339  else
340  last_Obs.estimation = reading;
341 
342  // Prepare the New observation
343  last_Obs.timestamp = timestamp;
344  last_Obs.reading = reading;
345  }
346  else
347  {
348  // First filtered reading (use default values)
349  last_Obs.tau = b_rise;
350  last_Obs.reading = reading;
351  last_Obs.timestamp = timestamp;
352  last_Obs.estimation =
353  reading; // No estimation possible at this step
354  first_iteration = false;
355  } // end-if estimation values
356  }
357  catch (exception e)
358  {
359  cerr << "**Exception in "
360  "CObservationGasSensors::CMOSmodel::inverse_MOSmodeling** "
361  << e.what() << endl;
362  }
363 }
364 
365 /*---------------------------------------------------------------
366  save_log_map
367  ---------------------------------------------------------------*/
369  const mrpt::system::TTimeStamp& timestamp, const float& reading,
370  const float& estimation, const float& tau)
371 {
372  // function to save in a log file the information of the generated gas
373  // distribution estimation
374 
376  char buffer[50];
377  sprintf(buffer, "./log_MOSmodel_GasDistribution.txt");
378 
379  if (!m_debug_dump) m_debug_dump = new ofstream(buffer);
380 
381  if (m_debug_dump->is_open())
382  {
383  *m_debug_dump << format("%f \t", time);
384  *m_debug_dump << format("%f \t", reading);
385  *m_debug_dump << format("%f \t", estimation);
386  *m_debug_dump << format("%f \t", tau);
387  *m_debug_dump << "\n";
388  }
389  else
390  cout << "Unable to open file";
391 }
392 
394 {
395  using namespace std;
397 
398  for (size_t j = 0; j < m_readings.size(); j++)
399  {
400  o << format("e-nose #%u:\n", (unsigned)j);
401 
404 
405  ASSERT_(
406  m_readings[j].readingsVoltage.size() ==
407  m_readings[j].sensorTypes.size());
408 
409  for (it = m_readings[j].readingsVoltage.begin(),
410  itKind = m_readings[j].sensorTypes.begin();
411  it != m_readings[j].readingsVoltage.end(); it++, itKind++)
412  o << format("%04X: %.03f ", *itKind, *it);
413 
414  o << endl;
415 
416  o << format(
417  " Sensor pose on robot: (x,y,z)=(%.02f,%.02f,%.02f)\n",
418  m_readings[j].eNosePoseOnTheRobot.x,
419  m_readings[j].eNosePoseOnTheRobot.y,
420  m_readings[j].eNosePoseOnTheRobot.z);
421 
422  o << "Measured temperature: ";
423  if (m_readings[j].hasTemperature)
424  o << format("%.03f degC\n", m_readings[j].temperature);
425  else
426  o << "NOT AVAILABLE\n";
427  }
428 }
uint64_t TTimeStamp
A system independent time type, it holds the the number of 100-nanosecond intervals since January 1...
Definition: datetime.h:32
void readFromStream(mrpt::utils::CStream &in, int version) override
Introduces a pure virtual method responsible for loading from a CStream This can not be used directly...
Classes for serialization, sockets, ini-file manipulation, streams, list of properties-values, timewatch, extensions to STL.
void writeToStream(mrpt::utils::CStream &out, int *getVersion) const override
Introduces a pure virtual method responsible for writing to a CStream.
void noise_filtering(const float &reading, const mrpt::system::TTimeStamp &timestamp)
Reduce noise by averaging with a mobile window of specific size (winNoise_size)
GLuint buffer
Definition: glext.h:3917
#define IMPLEMENTS_SERIALIZABLE(class_name, base, NameSpace)
This must be inserted in all CSerializable classes implementation files.
GLenum GLsizei n
Definition: glext.h:5074
Column vector, like Eigen::MatrixX*, but automatically initialized to zeros since construction...
Definition: eigen_frwds.h:42
vector_int sensorTypes
The kind of sensors in the array (size of "sensorTypes" is the same that the size of "readingsVoltage...
STL namespace.
const Scalar * const_iterator
Definition: eigen_plugins.h:27
void getSensorPose(mrpt::poses::CPose3D &out_sensorPose) const override
A general method to retrieve the sensor pose on the robot.
This base class is used to provide a unified interface to files,memory buffers,..Please see the deriv...
Definition: CStream.h:41
This base provides a set of functions for maths stuff.
Definition: CArrayNumeric.h:19
math::TPose3D eNosePoseOnTheRobot
The pose of the sensors on the robot.
#define MRPT_THROW_UNKNOWN_SERIALIZATION_VERSION(__V)
For use in CSerializable implementations.
This namespace contains representation of robot actions and observations.
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
Definition: format.cpp:19
Declares a class derived from "CObservation" that represents a set of readings from gas sensors...
void setSensorPose(const mrpt::poses::CPose3D &newSensorPose) override
A general method to change the sensor pose on the robot.
Classes for 2D/3D geometry representation, both of single values and probability density distribution...
Definition: CPoint.h:17
#define INVALID_TIMESTAMP
Represents an invalid timestamp, where applicable.
Definition: datetime.h:16
void pause(const std::string &msg=std::string("Press any key to continue...")) noexcept
Shows the message "Press any key to continue" (or other custom message) to the current standard outpu...
Definition: os.cpp:427
mrpt::system::TTimeStamp timestamp
The associated UTC time-stamp.
Definition: CObservation.h:58
void save_log_map(const mrpt::system::TTimeStamp &timestamp, const float &reading, const float &estimation, const float &tau)
Save the gas distribution estiamtion into a log file for offline representation.
A class used to store a 3D pose (a 3D translation + a rotation in 3D).
Definition: CPose3D.h:88
Declares a class that represents any robot&#39;s observation.
Definition: CObservation.h:41
std::vector< TObservationENose > m_readings
One entry per e-nose on the robot.
Lightweight 3D pose (three spatial coordinates, plus three angular coordinates).
GLuint in
Definition: glext.h:7274
#define ASSERT_(f)
void inverse_MOSmodeling(const float &reading, const mrpt::system::TTimeStamp &timestamp)
Estimates the gas concentration based on readings and sensor model.
double timeDifference(const mrpt::system::TTimeStamp t_first, const mrpt::system::TTimeStamp t_later)
Returns the time difference from t1 to t2 (positive if t2 is posterior to t1), in seconds...
Definition: datetime.cpp:208
std::vector< float > readingsVoltage
The set of readings (in volts) from the array of sensors (size of "sensorTypes" is the same that the ...
void getDescriptionAsText(std::ostream &o) const override
Build a detailed, multi-line textual description of the observation contents and dump it to the outpu...
unsigned __int32 uint32_t
Definition: rptypes.h:47
double timestampTotime_t(const mrpt::system::TTimeStamp t)
Transform from TTimeStamp to standard "time_t" (actually a double number, it can contain fractions of...
Definition: datetime.cpp:55
int sprintf(char *buf, size_t bufSize, const char *format,...) noexcept MRPT_printf_format_check(3
An OS-independent version of sprintf (Notice the bufSize param, which may be ignored in some compiler...
Definition: os.cpp:188
virtual void getDescriptionAsText(std::ostream &o) const
Build a detailed, multi-line textual description of the observation contents and dump it to the outpu...
bool get_GasDistribution_estimation(float &reading, mrpt::system::TTimeStamp &timestamp)
Obtain an estimation of the gas distribution based on raw sensor readings.



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: ae4571287 Thu Nov 23 00:06:53 2017 +0100 at dom oct 27 23:51:55 CET 2019