softwarePLL.cpp
Go to the documentation of this file.
1 /*
2 ====================================================================================================
3 File: softwarePLL.cpp
4 ====================================================================================================
5 */
6 #include "softwarePLL.h"
7 #include <iostream>
8 // #include <chrono>
9 // #include <thread>
10 #include <math.h>
11 #include <iterator>
12 #include <iostream>
13 #include <fstream>
14 #include <sstream>
15 #include <vector>
16 #include <string>
17 
18 
19 
20 const double SoftwarePLL::MaxAllowedTimeDeviation = 0.001;
21 const uint32_t SoftwarePLL::MaxExtrapolationCounter = 5;
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  std::size_t size() const
33  {
34  return m_data.size();
35  }
36  void readNextRow(std::istream& str)
37  {
38  std::string line;
39  std::getline(str, line);
40 
41  std::stringstream lineStream(line);
42  std::string cell;
43 
44  m_data.clear();
45  while(std::getline(lineStream, cell, ';'))
46  {
47  m_data.push_back(cell);
48  }
49  // This checks for a trailing comma with no data after it.
50  if (!lineStream && cell.empty())
51  {
52  // If there was a trailing comma then add an empty element.
53  m_data.push_back("");
54  }
55  }
56 private:
57  std::vector<std::string> m_data;
58 };
59 
60 std::istream& operator>>(std::istream& str, CSVRow& data)
61 {
62  data.readNextRow(str);
63  return str;
64 }
65 
66 
67 
68 bool SoftwarePLL::pushIntoFifo(double curTimeStamp, uint32_t curtick)
69 // update tick fifo and update clock (timestamp) fifo
70 {
71  for (int i = 0; i < fifoSize - 1; i++)
72  {
73  tickFifo[i] = tickFifo[i + 1];
74  clockFifo[i] = clockFifo[i + 1];
75  }
76  tickFifo[fifoSize - 1] = curtick; // push most recent tick and timestamp into fifo
77  clockFifo[fifoSize - 1] = curTimeStamp;
78 
79  if (numberValInFifo < fifoSize)
80  {
81  numberValInFifo++; // remember the number of valid number in fifo
82  }
83  FirstTick(tickFifo[0]);
84  FirstTimeStamp(clockFifo[0]);
85 
86  return(true);
87 }
88 
90 {
91  uint32_t tempTick = tick;
92  tempTick -= (uint32_t)(0xFFFFFFFF & FirstTick());
93  double timeDiff = tempTick * this->InterpolationSlope();
94  return(timeDiff);
95 
96 }
97 
98 int SoftwarePLL::findDiffInFifo(double diff, double tol)
99 {
100  int numFnd = 0;
101  double minAllowedDiff = (1.0 - tol) * diff;
102  double maxAllowedDiff = (1.0 + tol) * diff;
103 
104  for (int i = 0; i < numberValInFifo - 1; i++)
105  {
106  double diffTime = this->clockFifo[i+1] - clockFifo[i];
107  if ((diffTime >= minAllowedDiff) && (diffTime <= maxAllowedDiff))
108  {
109  numFnd++;
110  }
111  }
112 
113  return(numFnd);
114 }
115 
124 bool SoftwarePLL::updatePLL(uint32_t sec, uint32_t nanoSec, uint32_t curtick)
125 {
126  double start = sec + nanoSec * 1E-9;
127  bool bRet = true;
128 
129  if (false == IsInitialized())
130  {
131  pushIntoFifo(start, curtick);
132  bool bCheck = this->updateInterpolationSlope();
133  if (bCheck)
134  {
135  IsInitialized(true);
136  }
137  }
138 
139  if (IsInitialized() == false)
140  {
141  return(false);
142  }
143 
144  double relTimeStamp = extraPolateRelativeTimeStamp(curtick); // evtl. hier wg. Ueberlauf noch einmal pruefen
145  double cmpTimeStamp = start - this->FirstTimeStamp();
146 
147  bool timeStampVerified = false;
148  if (nearSameTimeStamp(relTimeStamp, cmpTimeStamp) == true)// if timestamp matches prediction update FIFO
149  {
150  timeStampVerified = true;
151  pushIntoFifo(start, curtick);
152  updateInterpolationSlope();
153  ExtrapolationDivergenceCounter(0);
154  }
155 
156  if (timeStampVerified == false)
157  {
158  // BEGIN HANDLING Extrapolation divergence
159  uint32_t tmp = ExtrapolationDivergenceCounter();
160  tmp++;
161  ExtrapolationDivergenceCounter(tmp);
162  if (ExtrapolationDivergenceCounter() >= SoftwarePLL::MaxExtrapolationCounter)
163  {
164  IsInitialized(false); // reset FIFO - maybe happened due to abrupt change of time base
165  }
166  // END HANDLING Extrapolation divergence
167  }
168 
169  return(true);
170 }
171 //TODO Kommentare
172 bool SoftwarePLL::getCorrectedTimeStamp(uint32_t& sec, uint32_t& nanoSec, uint32_t curtick)
173 {
174  if (IsInitialized() == false)
175  {
176  return(false);
177  }
178 
179  double relTimeStamp = extraPolateRelativeTimeStamp(curtick); // evtl. hier wg. Ueberlauf noch einmal pruefen
180  double corrTime = relTimeStamp + this->FirstTimeStamp();
181  sec = (uint32_t)corrTime;
182  double frac = corrTime - sec;
183  nanoSec = (uint32_t)(1E9 * frac);
184  return(true);
185 }
186 
187 bool SoftwarePLL::nearSameTimeStamp(double relTimeStamp1, double relTimeStamp2)
188 {
189  double dTAbs = fabs(relTimeStamp1 - relTimeStamp2);
190  if (dTAbs < AllowedTimeDeviation())
191  {
192  return(true);
193  }
194  else
195  {
196  return(false);
197  }
198 }
199 
200 bool SoftwarePLL::updateInterpolationSlope() // fifo already updated
201 {
202 
203  if (numberValInFifo < fifoSize)
204  {
205  return(false);
206  }
207  std::vector<uint64_t> tickFifoUnwrap;
208  std::vector<double> clockFifoUnwrap;
209  clockFifoUnwrap.resize(fifoSize);
210  tickFifoUnwrap.resize(fifoSize);
211  uint64_t tickOffset = 0;
212  clockFifoUnwrap[0] = 0.00;
213  tickFifoUnwrap[0] = 0;
214  FirstTimeStamp(this->clockFifo[0]);
215  FirstTick(this->tickFifo[0]);
216 
217  uint64_t tickDivisor = 0x100000000;
218 
219 
220 
221  for (int i = 1; i < fifoSize; i++) // typical 643 for 20ms -> round about 32150 --> near to 32768 standard clock in many watches
222  {
223  if (tickFifo[i] < tickFifo[i - 1]) // Overflow
224  {
225  tickOffset += tickDivisor;
226  }
227  tickFifoUnwrap[i] = tickOffset + tickFifo[i] - FirstTick();
228  clockFifoUnwrap[i] = (this->clockFifo[i] - FirstTimeStamp());
229  }
230 
231  double sum_xy = 0.0;
232  double sum_x = 0.0;
233  double sum_y = 0.0;
234  double sum_xx = 0.0;
235  for (int i = 0; i < fifoSize; i++)
236  {
237  sum_xy += tickFifoUnwrap[i] * clockFifoUnwrap[i];
238  sum_x += tickFifoUnwrap[i];
239  sum_y += clockFifoUnwrap[i];
240  sum_xx += tickFifoUnwrap[i] * tickFifoUnwrap[i];
241  }
242 
243  // calculate slope of regression line, interception is 0 by construction
244  double m = (fifoSize * sum_xy - sum_x * sum_y) / (fifoSize * sum_xx - sum_x*sum_x);
245 
246  int matchCnt = 0;
247  for (int i = 0; i < fifoSize; i++)
248  {
249  double yesti = m * tickFifoUnwrap[i];
250  if (this->nearSameTimeStamp(yesti, clockFifoUnwrap[i]))
251  {
252  matchCnt++;
253  }
254  }
255 
256  bool retVal = false;
257  if (matchCnt == fifoSize)
258  {
259  InterpolationSlope(m);
260  retVal = true;
261  }
262 
263  return(retVal);
264 }
265 
266 #if 0
267 bool SoftwarePLL::getDemoFileData(std::string fileName, std::vector<uint32_t>& tickVec,std::vector<uint32_t>& secVec, std::vector<uint32_t>& nanoSecVec )
268 {
269  std::ifstream file(fileName);
270 
271  CSVRow row;
272  tickVec.clear();
273  secVec.clear();
274  nanoSecVec.clear();
275  int lineCnt = 0;
276  while (file >> row) {
277  if (lineCnt > 0)
278  {
279  uint32_t tickVal = (uint32_t)std::stoi(row[0]);
280  uint32_t secVal = (uint32_t)std::stoi(row[1]);
281  uint32_t nanoSecVal = (uint32_t)std::stoi(row[2]);
282  tickVec.push_back(tickVal);
283  secVec.push_back(secVal);
284  nanoSecVec.push_back(nanoSecVal);
285  }
286  lineCnt++;
287  }
288  if (lineCnt <= 1)
289  return false;
290  else
291  return true;
292 }
293 #endif
294 
295 //TODO update testbed
297 {
298  std::cout << "Running testbed for SofwarePLL" << std::endl;
299  uint32_t curtick = 0;
300  int cnt = 0;
301 
302  SoftwarePLL testPll;
303  uint32_t sec = 9999;
304  uint32_t nanoSec = 0;
305  double tickPerSec = 1E6;
306  uint32_t tickInc = 1000;
307  int maxLoop = 20;
308 
309  std::vector<uint32_t> tickVec;
310  std::vector<uint32_t> secVec;
311  std::vector<uint32_t> nanoSecVec;
312  bool bRet = false;
313 
314  bool testWithDataFile = true;
315  if (testWithDataFile)
316  {
317  // commented for trusty bRet = testPll.getDemoFileData("/home/rosuser/dumpimu3.csv", tickVec, secVec, nanoSecVec);
318  maxLoop = tickVec.size();
319  }
320 
321  for (int i = 0; i < maxLoop; i++)
322  {
323  if (testWithDataFile)
324  {
325  curtick = tickVec[i];
326  sec = secVec[i];
327  nanoSec = nanoSecVec[i];
328  }
329  else
330  {
331  cnt++;
332  curtick += tickInc; // increment tick counter
333  double deltaT = tickInc / tickPerSec;
334  nanoSec += (int)(deltaT * 1E9);
335  if (nanoSec >= 1E9)
336  {
337  nanoSec = 0;
338  sec++;
339  }
340  if (cnt >= 8)
341  {
342  sec++;
343  }
344  }
345  printf("Before correction: %3d.%09d\n", sec, nanoSec);
346  uint32_t org_sec = sec;
347  uint32_t org_nanoSec = nanoSec;
348 
349  bool bRet = testPll.getCorrectedTimeStamp(sec, nanoSec, curtick);
350 
351  bool corrected = false;
352  if ((nanoSec != org_nanoSec) || (sec != org_sec))
353  {
354  corrected =true;
355  }
356  printf("After correction : %3d.%09d %s %s\n", sec, nanoSec, bRet ? "OK " : "DISMISS", corrected ? "MODI." : "OK ");
357  }
358 
359  return;
360 }
361 
362 
363 
364 #ifdef softwarePLL_MAINTEST
365 int main(int argc, char **argv)
366 {
367  printf("Test for softwarePLL-Class\n");
368  printf("\n");
370 }
371 #endif
372 
373 
374 
375 /*
376 Example CMakeLists.txt to generate test-binary-file for testing this class
377 --- CUT ---
378 #
379 #
380 # softwarePLL
381 #
382 #
383 cmake_minimum_required(VERSION 2.8)
384 cmake_policy(SET CMP0015 NEW)
385 project( softwarePLL )
386 #
387 #
388 add_definitions(-D${PROJECT_NAME}_MAINTEST)
389 
390 MESSAGE( STATUS "CMKAKE for " ${PROJECT_NAME} )
391 
392 include_directories( inc)
393 file( GLOB LIB_SOURCES src/ *.cpp )
394 
395 if(WIN32)
396 else()
397 set(CMAKE_CXX_STANDARD 11)
398 endif()
399 
400 add_executable( ${PROJECT_NAME} ${LIB_SOURCES} inc/${PROJECT_NAME}.h)
401 target_link_libraries( ${PROJECT_NAME})
402 --- CUT ---
403 
404 */
bool getDemoFileData(std::string fileName, std::vector< uint32_t > &tickVec, std::vector< uint32_t > &secVec, std::vector< uint32_t > &nanoSecVec)
void readNextRow(std::istream &str)
Definition: softwarePLL.cpp:36
double extraPolateRelativeTimeStamp(uint32_t tick)
Definition: softwarePLL.cpp:89
std::string const & operator[](std::size_t index) const
Definition: softwarePLL.cpp:28
bool getCorrectedTimeStamp(uint32_t &sec, uint32_t &nanoSec, uint32_t tick)
bool pushIntoFifo(double curTimeStamp, uint32_t curtick)
Definition: softwarePLL.cpp:68
int main(int argc, char **argv)
Startup routine - if called with no argmuments we assume debug session. Set scanner name variable by ...
std::istream & operator>>(std::istream &str, CSVRow &data)
Definition: softwarePLL.cpp:60
static void testbed()
static const uint32_t MaxExtrapolationCounter
Definition: softwarePLL.h:54
static const double MaxAllowedTimeDeviation
Definition: softwarePLL.h:53
bool nearSameTimeStamp(double relTimeStamp1, double relTimeStamp2)
int findDiffInFifo(double diff, double tol)
Definition: softwarePLL.cpp:98
bool updateInterpolationSlope()
std::vector< std::string > m_data
Definition: softwarePLL.cpp:57
std::size_t size() const
Definition: softwarePLL.cpp:32
bool updatePLL(uint32_t sec, uint32_t nanoSec, uint32_t curtick)
Updates PLL internale State should be called only with network send timestamps.


sick_scan
Author(s): Michael Lehning , Jochen Sprickerhof , Martin Günther
autogenerated on Tue Jul 9 2019 04:55:32