softwarePLL.cpp
Go to the documentation of this file.
1 /*
2 ====================================================================================================
3 File: softwarePLL.cpp
4 ====================================================================================================
5 */
6 #include "softwarePLL.h"
7 #include <algorithm>
8 #include <iostream>
9 // #include <chrono>
10 // #include <thread>
11 #include <math.h>
12 #include <iterator>
13 #include <iostream>
14 #include <fstream>
15 #include <sstream>
16 #include <vector>
17 #include <string>
18 
19 
20 const double SoftwarePLL::MaxAllowedTimeDeviation = 0.1;
21 const uint32_t SoftwarePLL::MaxExtrapolationCounter = 20;
22 
23 // Helper class for reading csv file with test data
24 
25 class CSVRow
26 {
27 public:
28  std::string const &operator[](std::size_t index) const
29  {
30  return m_data[index];
31  }
32 
33  std::size_t size() const
34  {
35  return m_data.size();
36  }
37 
38  void readNextRow(std::istream &str)
39  {
40  std::string line;
41  std::getline(str, line);
42 
43  std::stringstream lineStream(line);
44  std::string cell;
45 
46  m_data.clear();
47  while (std::getline(lineStream, cell, ';'))
48  {
49  m_data.push_back(cell);
50  }
51  // This checks for a trailing comma with no data after it.
52  if (!lineStream && cell.empty())
53  {
54  // If there was a trailing comma then add an empty element.
55  m_data.push_back("");
56  }
57  }
58 
59 private:
60  std::vector<std::string> m_data;
61 };
62 
63 std::istream &operator>>(std::istream &str, CSVRow &data)
64 {
65  data.readNextRow(str);
66  return str;
67 }
68 
69 
70 bool SoftwarePLL::pushIntoFifo(double curTimeStamp, uint64_t curtick)
71 // update tick fifo and update clock (timestamp) fifo
72 {
73  for (int i = 0; i < fifoSize - 1; i++)
74  {
75  tickFifo[i] = tickFifo[i + 1];
76  clockFifo[i] = clockFifo[i + 1];
77  }
78  tickFifo[fifoSize - 1] = curtick; // push most recent tick and timestamp into fifo
79  clockFifo[fifoSize - 1] = curTimeStamp;
80 
82  {
83  numberValInFifo++; // remember the number of valid number in fifo
84  }
85  FirstTick(tickFifo[0]);
87 
88  return (true);
89 }
90 
92 {
93  uint64_t tempTick = tick - FirstTick();
94  double timeDiff = tempTick * this->InterpolationSlope();
95  return (timeDiff);
96 
97 }
98 
99 int SoftwarePLL::findDiffInFifo(double diff, double tol)
100 {
101  int numFnd = 0;
102  double minAllowedDiff = (1.0 - tol) * diff;
103  double maxAllowedDiff = (1.0 + tol) * diff;
104 
105  for (int i = 0; i < numberValInFifo - 1; i++)
106  {
107  double diffTime = this->clockFifo[i + 1] - clockFifo[i];
108  if ((diffTime >= minAllowedDiff) && (diffTime <= maxAllowedDiff))
109  {
110  numFnd++;
111  }
112  }
113 
114  return (numFnd);
115 }
116 
125 bool SoftwarePLL::updatePLL(uint32_t sec, uint32_t nanoSec, uint64_t curtick)
126 {
128  {
129  // Store first timestamp and ticks for optional TICKS_TO_MICROSEC_OFFSET_TIMESTAMP
131  offsetTimestampFirstSystemMicroSec = nanoSec / 1000;
133  }
134 
135  if (curtick != this->lastcurtick)
136  {
137  this->lastcurtick = curtick;
138  double start = sec + nanoSec * 1E-9;
139  bool bRet = true;
140 
141  if (false == IsInitialized())
142  {
143  pushIntoFifo(start, curtick);
144  bool bCheck = this->updateInterpolationSlope();
145  if (bCheck)
146  {
147  IsInitialized(true);
148  }
149  }
150 
151  if (IsInitialized() == false)
152  {
153  return (false);
154  }
155 
156  double relTimeStamp = extraPolateRelativeTimeStamp(curtick); // evtl. hier wg. Ueberlauf noch einmal pruefen
157  double cmpTimeStamp = start - this->FirstTimeStamp();
158 
159  bool timeStampVerified = false;
160  double delta_time_abs = 0;
161  if (nearSameTimeStamp(relTimeStamp, cmpTimeStamp, delta_time_abs) == true)// if timestamp matches prediction update FIFO
162  {
163  timeStampVerified = true;
164  pushIntoFifo(start, curtick);
167  }
168 
169  if (timeStampVerified == false)
170  {
171  // BEGIN HANDLING Extrapolation divergence
172  uint32_t tmp = ExtrapolationDivergenceCounter();
173  tmp++;
176  {
177  IsInitialized(false); // reset FIFO - maybe happened due to abrupt change of time base
178  }
179  // END HANDLING Extrapolation divergence
180  }
181  return (true);
182  }
183  else
184  {
185  return (false);
186  //this curtick has been updated allready
187  }
188 
189 }
190 
191 bool SoftwarePLL::updatePLL(uint32_t sec, uint32_t nanoSec, uint32_t curtick)
192 {
193  return updatePLL(sec, nanoSec, (uint64_t)curtick);
194 }
195 
196 //TODO Kommentare
197 bool SoftwarePLL::getCorrectedTimeStamp(uint32_t &sec, uint32_t &nanoSec, uint64_t curtick)
198 {
199  if (ticksToTimestampMode == TICKS_TO_LIDAR_TIMESTAMP) // optional tick-mode: convert lidar ticks in microseconds directly into a lidar timestamp by sec = tick/1000000, nsec = 1000 * (tick % 1000000)
200  {
201  sec = (uint32_t)(curtick / 1000000);
202  nanoSec = (uint32_t)(1000 * (curtick % 1000000));
203  return true;
204  }
205  if (IsInitialized() == false)
206  {
207  return (false);
208  }
209  double corrTime = 0;
210  if (ticksToTimestampMode == TICKS_TO_MICROSEC_OFFSET_TIMESTAMP) // optional tick-mode: convert lidar ticks in microseconds to timestamp by 1.0e-6*(curtick-firstTick)+firstSystemTimestamp
211  {
213  }
214  else // default: convert lidar ticks in microseconds to system timestamp by software-pll
215  {
216  double relTimeStamp = extraPolateRelativeTimeStamp(curtick); // evtl. hier wg. Ueberlauf noch einmal pruefen
217  corrTime = relTimeStamp + this->FirstTimeStamp();
218  }
219  sec = (uint32_t) corrTime;
220  double frac = corrTime - sec;
221  nanoSec = (uint32_t) (1E9 * frac);
222  // std::cout << "SoftwarePLL::getCorrectedTimeStamp(): timestamp_mode=" << (int)ticksToTimestampMode << ", curticks = " << curtick << " [microsec], system time = " << std::fixed << std::setprecision(9) << (sec + 1.0e-9 * nanoSec) << " [sec]" << std::endl;
223  return (true);
224 }
225 
226 bool SoftwarePLL::getCorrectedTimeStamp(uint32_t &sec, uint32_t &nanoSec, uint32_t curtick)
227 {
228  return getCorrectedTimeStamp(sec, nanoSec, (uint64_t)curtick);
229 }
230 
231 // converts a system timestamp to lidar ticks, computes the inverse to getCorrectedTimeStamp().
232 bool SoftwarePLL::convSystemtimeToLidarTimestamp(uint32_t systemtime_sec, uint32_t systemtime_nanosec, uint64_t& tick)
233 {
234  if (ticksToTimestampMode == TICKS_TO_LIDAR_TIMESTAMP) // optional tick-mode: convert lidar ticks in microseconds directly into a lidar timestamp
235  {
236  tick = 1000000 * (uint64_t)systemtime_sec + (uint64_t)systemtime_nanosec / 1000; // tick in micro seconds
237  return true;
238  }
239  if (IsInitialized() == false)
240  {
241  return (false);
242  }
243  if (ticksToTimestampMode == TICKS_TO_MICROSEC_OFFSET_TIMESTAMP) // optional tick-mode: convert lidar ticks in microseconds to timestamp by 1.0e-6*(curtick-firstTick)+firstSystemTimestamp
244  {
245  double relSystemTimestamp = (systemtime_sec + 1.0e-9 * systemtime_nanosec) - (offsetTimestampFirstSystemSec + 1.0e-6 * offsetTimestampFirstSystemMicroSec);
246  double relTicks = 1.0e6 * relSystemTimestamp;
247  tick = (uint64_t)std::round(relTicks + offsetTimestampFirstLidarTick);
248  }
249  else // default: convert lidar ticks in microseconds to system timestamp by software-pll
250  {
251  double systemTimestamp = (double)systemtime_sec + 1.0e-9 * (double)systemtime_nanosec; // systemTimestamp := corrTime in getCorrectedTimeStamp
252  // getCorrectedTimeStamp(): corrTime = relTimeStamp + this->FirstTimeStamp()
253  // => inverse: relSystemTimestamp = systemTimestamp - this->FirstTimeStamp()
254  double relSystemTimestamp = systemTimestamp - this->FirstTimeStamp();
255  // getCorrectedTimeStamp(): relSystemTimestamp = (tick - (uint32_t) (0xFFFFFFFF & FirstTick())) * this->InterpolationSlope()
256  //=> inverse: tick = (relSystemTimestamp / this->InterpolationSlope()) + (uint32_t) (0xFFFFFFFF & FirstTick())
257  double relTicks = relSystemTimestamp / this->InterpolationSlope();
258  uint32_t tick_offset = (uint32_t)(0xFFFFFFFF & FirstTick());
259  tick = (uint64_t)std::round(relTicks + tick_offset);
260  }
261  return (true);
262 }
263 
264 bool SoftwarePLL::convSystemtimeToLidarTimestamp(uint32_t systemtime_sec, uint32_t systemtime_nanosec, uint32_t& tick)
265 {
266  uint64_t lidar_ticks = 0;
267  bool success = convSystemtimeToLidarTimestamp(systemtime_sec, systemtime_nanosec, lidar_ticks);
268  tick = (uint32_t)lidar_ticks;
269  return success;
270 }
271 
272 bool SoftwarePLL::nearSameTimeStamp(double relTimeStamp1, double relTimeStamp2, double& delta_time_abs)
273 {
274  delta_time_abs = fabs(relTimeStamp1 - relTimeStamp2);
275  if (delta_time_abs < AllowedTimeDeviation())
276  {
277  return (true);
278  }
279  else
280  {
281  return (false);
282  }
283 }
284 
285 bool SoftwarePLL::updateInterpolationSlope() // fifo already updated
286 {
287 
289  {
290  return (false);
291  }
292  std::vector<uint64_t> tickFifoUnwrap;
293  std::vector<double> clockFifoUnwrap;
294  clockFifoUnwrap.resize(fifoSize);
295  tickFifoUnwrap.resize(fifoSize);
296  uint64_t tickOffset = 0;
297  clockFifoUnwrap[0] = 0.00;
298  tickFifoUnwrap[0] = 0;
299  FirstTimeStamp(this->clockFifo[0]);
300  FirstTick(this->tickFifo[0]);
301 
302  uint64_t tickDivisor = 0x100000000;
303 
304 
305  for (int i = 1;
306  i < fifoSize; i++) // typical 643 for 20ms -> round about 32150 --> near to 32768 standard clock in many watches
307  {
308  if (tickFifo[i] < tickFifo[i - 1]) // Overflow
309  {
310  tickOffset += tickDivisor;
311  }
312  tickFifoUnwrap[i] = tickOffset + tickFifo[i] - FirstTick();
313  clockFifoUnwrap[i] = (this->clockFifo[i] - FirstTimeStamp());
314  }
315 
316  double sum_xy = 0.0;
317  double sum_x = 0.0;
318  double sum_y = 0.0;
319  double sum_xx = 0.0;
320  for (int i = 0; i < fifoSize; i++)
321  {
322  sum_xy += tickFifoUnwrap[i] * clockFifoUnwrap[i];
323  sum_x += tickFifoUnwrap[i];
324  sum_y += clockFifoUnwrap[i];
325  sum_xx += tickFifoUnwrap[i] * tickFifoUnwrap[i];
326  }
327 
328  // calculate slope of regression line, interception is 0 by construction
329  double m = (fifoSize * sum_xy - sum_x * sum_y) / (fifoSize * sum_xx - sum_x * sum_x);
330 
331  int matchCnt = 0;
332  max_abs_delta_time = 0;
333  for (int i = 0; i < fifoSize; i++)
334  {
335  double yesti = m * tickFifoUnwrap[i];
336  double abs_delta_time = 0;
337  if (this->nearSameTimeStamp(yesti, clockFifoUnwrap[i], abs_delta_time))
338  {
339  matchCnt++;
340  }
341  max_abs_delta_time = std::max(max_abs_delta_time, abs_delta_time);
342  // std::cout << "SoftwarePLL::updateInterpolationSlope(): matchCnt=" << matchCnt << "/" << fifoSize << ", yesti=" << yesti << ", clockFifoUnwrap=" << clockFifoUnwrap[i] << ", tickFifoUnwrap=" << tickFifoUnwrap[i] << std::endl;
343  }
344 
345  bool retVal = false;
346  if (matchCnt == fifoSize)
347  {
349  retVal = true;
350  }
351  // else
352  // {
353  // std::cerr << "SoftwarePLL::updateInterpolationSlope(): matchCnt=" << matchCnt << "/" << fifoSize << ", max_abs_delta_time=" << max_abs_delta_time << " sec." << std::endl;
354  // }
355 
356  return (retVal);
357 }
358 
359 #if 0
360 bool SoftwarePLL::getDemoFileData(std::string fileName, std::vector<uint32_t>& tickVec,std::vector<uint32_t>& secVec, std::vector<uint32_t>& nanoSecVec )
361 {
362  std::ifstream file(fileName);
363 
364  CSVRow row;
365  tickVec.clear();
366  secVec.clear();
367  nanoSecVec.clear();
368  int lineCnt = 0;
369  while (file >> row) {
370  if (lineCnt > 0)
371  {
372  uint32_t tickVal = (uint32_t)std::stoi(row[0]);
373  uint32_t secVal = (uint32_t)std::stoi(row[1]);
374  uint32_t nanoSecVal = (uint32_t)std::stoi(row[2]);
375  tickVec.push_back(tickVal);
376  secVec.push_back(secVal);
377  nanoSecVec.push_back(nanoSecVal);
378  }
379  lineCnt++;
380  }
381  if (lineCnt <= 1)
382  return false;
383  else
384  return true;
385 }
386 #endif
387 
388 //TODO update testbed
390 {
391  std::cout << "Running testbed for SofwarePLL" << std::endl;
392  uint32_t curtick = 0;
393  int cnt = 0;
394 
395  SoftwarePLL testPll;
396  uint32_t sec = 9999;
397  uint32_t nanoSec = 0;
398  double tickPerSec = 1E6;
399  uint32_t tickInc = 1000;
400  int maxLoop = 20;
401 
402  std::vector<uint32_t> tickVec;
403  std::vector<uint32_t> secVec;
404  std::vector<uint32_t> nanoSecVec;
405  //bool bRet = false;
406 
407  bool testWithDataFile = true;
408  if (testWithDataFile)
409  {
410  // commented for trusty bRet = testPll.getDemoFileData("/home/rosuser/dumpimu3.csv", tickVec, secVec, nanoSecVec);
411  maxLoop = (int)tickVec.size();
412  }
413 
414  for (int i = 0; i < maxLoop; i++)
415  {
416  if (testWithDataFile)
417  {
418  curtick = tickVec[i];
419  sec = secVec[i];
420  nanoSec = nanoSecVec[i];
421  }
422  else
423  {
424  cnt++;
425  curtick += tickInc; // increment tick counter
426  double deltaT = tickInc / tickPerSec;
427  nanoSec += (int) (deltaT * 1E9);
428  if (nanoSec >= 1E9)
429  {
430  nanoSec = 0;
431  sec++;
432  }
433  if (cnt >= 8)
434  {
435  sec++;
436  }
437  }
438  printf("Before correction: %3d.%09d\n", sec, nanoSec);
439  uint32_t org_sec = sec;
440  uint32_t org_nanoSec = nanoSec;
441 
442  bool bRet = testPll.getCorrectedTimeStamp(sec, nanoSec, curtick);
443 
444  bool corrected = false;
445  if ((nanoSec != org_nanoSec) || (sec != org_sec))
446  {
447  corrected = true;
448  }
449  printf("After correction : %3d.%09d %s %s\n", sec, nanoSec, bRet ? "OK " : "DISMISS",
450  corrected ? "MODI." : "OK ");
451  }
452 
453  return;
454 }
455 
456 
457 #ifdef softwarePLL_MAINTEST
458 int main(int argc, char **argv)
459 {
460  printf("Test for softwarePLL-Class\n");
461  printf("\n");
463 }
464 #endif
465 
466 
467 
468 /*
469 Example CMakeLists.txt to generate test-binary-file for testing this class
470 --- CUT ---
471 #
472 #
473 # softwarePLL
474 #
475 #
476 cmake_minimum_required(VERSION 2.8)
477 cmake_policy(SET CMP0015 NEW)
478 project( softwarePLL )
479 #
480 #
481 add_definitions(-D${PROJECT_NAME}_MAINTEST)
482 
483 MESSAGE( STATUS "CMKAKE for " ${PROJECT_NAME} )
484 
485 include_directories( inc)
486 file( GLOB LIB_SOURCES src/ *.cpp )
487 
488 if(WIN32)
489 else()
490 set(CMAKE_CXX_STANDARD 11)
491 endif()
492 
493 add_executable( ${PROJECT_NAME} ${LIB_SOURCES} inc/${PROJECT_NAME}.h)
494 target_link_libraries( ${PROJECT_NAME})
495 --- CUT ---
496 
497 */
SoftwarePLL
class SoftwarePLL implements synchronisation between ticks and timestamp. See https://github....
Definition: softwarePLL.h:21
CSVRow::m_data
std::vector< std::string > m_data
Definition: softwarePLL.cpp:60
SoftwarePLL::AllowedTimeDeviation
double AllowedTimeDeviation() const
Definition: softwarePLL.h:84
SoftwarePLL::getDemoFileData
bool getDemoFileData(std::string fileName, std::vector< uint32_t > &tickVec, std::vector< uint32_t > &secVec, std::vector< uint32_t > &nanoSecVec)
SoftwarePLL::updatePLL
bool updatePLL(uint32_t sec, uint32_t nanoSec, uint32_t curtick)
Definition: softwarePLL.cpp:191
SoftwarePLL::lastcurtick
uint64_t lastcurtick
Definition: softwarePLL.h:125
SoftwarePLL::max_abs_delta_time
double max_abs_delta_time
Definition: softwarePLL.h:104
SoftwarePLL::FirstTick
uint64_t FirstTick() const
Definition: softwarePLL.h:66
SoftwarePLL::ticksToTimestampMode
TICKS_TO_TIMESTAMP_MODE ticksToTimestampMode
Definition: softwarePLL.h:139
SoftwarePLL::convSystemtimeToLidarTimestamp
bool convSystemtimeToLidarTimestamp(uint32_t systemtime_sec, uint32_t systemtime_nanosec, uint32_t &tick)
Definition: softwarePLL.cpp:264
SoftwarePLL::getCorrectedTimeStamp
bool getCorrectedTimeStamp(uint32_t &sec, uint32_t &nanoSec, uint32_t tick)
Definition: softwarePLL.cpp:226
data
data
CSVRow::readNextRow
void readNextRow(std::istream &str)
Definition: softwarePLL.cpp:38
softwarePLL.h
operator>>
std::istream & operator>>(std::istream &str, CSVRow &data)
Definition: softwarePLL.cpp:63
SoftwarePLL::numberValInFifo
int numberValInFifo
Definition: softwarePLL.h:112
CSVRow
Definition: softwarePLL.cpp:25
SoftwarePLL::offsetTimestampFirstSystemMicroSec
uint32_t offsetTimestampFirstSystemMicroSec
Definition: softwarePLL.h:141
SoftwarePLL::MaxExtrapolationCounter
static const uint32_t MaxExtrapolationCounter
Definition: softwarePLL.h:114
SoftwarePLL::offsetTimestampFirstSystemSec
uint32_t offsetTimestampFirstSystemSec
Definition: softwarePLL.h:140
SoftwarePLL::ExtrapolationDivergenceCounter
uint32_t ExtrapolationDivergenceCounter() const
Definition: softwarePLL.h:90
sec
uint32_t sec(const rosTime &time)
Definition: sick_ros_wrapper.h:174
imu_delay_tester.line
line
Definition: imu_delay_tester.py:135
SoftwarePLL::TICKS_TO_MICROSEC_OFFSET_TIMESTAMP
@ TICKS_TO_MICROSEC_OFFSET_TIMESTAMP
Definition: softwarePLL.h:134
SoftwarePLL::testbed
static void testbed()
Definition: softwarePLL.cpp:389
SoftwarePLL::clockFifo
double clockFifo[fifoSize]
Definition: softwarePLL.h:116
SoftwarePLL::nearSameTimeStamp
bool nearSameTimeStamp(double relTimeStamp1, double relTimeStamp2, double &delta_time_abs)
Definition: softwarePLL.cpp:272
SoftwarePLL::offsetTimestampFirstLidarTick
uint64_t offsetTimestampFirstLidarTick
Definition: softwarePLL.h:142
SoftwarePLL::FirstTimeStamp
double FirstTimeStamp() const
Definition: softwarePLL.h:72
SoftwarePLL::extraPolateRelativeTimeStamp
double extraPolateRelativeTimeStamp(uint64_t tick)
Definition: softwarePLL.cpp:91
SoftwarePLL::MaxAllowedTimeDeviation
static const double MaxAllowedTimeDeviation
Definition: softwarePLL.h:113
SoftwarePLL::tickFifo
uint64_t tickFifo[fifoSize]
Definition: softwarePLL.h:115
SoftwarePLL::TICKS_TO_LIDAR_TIMESTAMP
@ TICKS_TO_LIDAR_TIMESTAMP
Definition: softwarePLL.h:135
SoftwarePLL::IsInitialized
bool IsInitialized() const
Definition: softwarePLL.h:47
CSVRow::size
std::size_t size() const
Definition: softwarePLL.cpp:33
SoftwarePLL::updateInterpolationSlope
bool updateInterpolationSlope()
Definition: softwarePLL.cpp:285
SoftwarePLL::pushIntoFifo
bool pushIntoFifo(double curTimeStamp, uint64_t curtick)
Definition: softwarePLL.cpp:70
roswrap::start
ROSCPP_DECL void start()
Actually starts the internals of the node (spins up threads, starts the network polling and xmlrpc lo...
main
int main(int argc, char **argv)
Startup routine - if called with no argmuments we assume debug session. Set scanner name variable by ...
Definition: sick_generic_caller.cpp:96
SoftwarePLL::findDiffInFifo
int findDiffInFifo(double diff, double tol)
Definition: softwarePLL.cpp:99
SoftwarePLL::fifoSize
static const int fifoSize
Definition: softwarePLL.h:101
SoftwarePLL::InterpolationSlope
double InterpolationSlope() const
Definition: softwarePLL.h:78
CSVRow::operator[]
const std::string & operator[](std::size_t index) const
Definition: softwarePLL.cpp:28


sick_scan_xd
Author(s): Michael Lehning , Jochen Sprickerhof , Martin Günther
autogenerated on Fri Oct 25 2024 02:47:12