QDaq  0.2.6
Qt-based Data Aqcuisition
 All Classes Functions Variables Typedefs Enumerations Enumerator Properties Groups Pages
math_util.h
1 #ifndef _math_util_h_
2 #define _math_util_h_
3 
4 // #include <cmath>
5 
6 #include <QVector>
7 #include <QExplicitlySharedDataPointer>
8 
9 
10 namespace math {
11 
30 template<class T>
32 {
33 public:
34  typedef circular_buffer<T> self_t;
35 
36 private:
37  // buffer capacity
38  unsigned int cap_;
39  // index of the first element
40  unsigned int head_;
41  // index bit mask
42  unsigned int mask_;
43  // memory buffer
44  T* buff_;
45 
46  void inc(unsigned int& i)
47  {
48  i++;
49  i &= mask_;
50  }
51  void dec(unsigned int& i)
52  {
53  i--;
54  i &= mask_;
55  }
56  T* at(int i) const
57  {
58  return buff_ + ((head_ + i) & mask_);
59  }
60 public:
62  explicit circular_buffer(unsigned int nmax = 1) : buff_(0)
63  {
64  if (nmax < 1) nmax = 1;
65  alloc(nmax);
66  }
68  {
69  if (buff_) delete [] buff_;
70  }
72  /* Previously stored elements are lost! */
73  void alloc(unsigned int nmax)
74  {
75  // find a number 2^N so that 2^N>nmax
76  cap_ = 1;
77  while (cap_ < nmax) cap_ <<= 1;
78  // re-allocate memory
79  if (buff_) delete [] buff_;
80  buff_ = new T[cap_];
81  mask_ = cap_ - 1;
82  head_ = 0;
83  }
85  void push(const T& v)
86  {
87  dec(head_);
88  buff_[head_] = v;
89  }
91  self_t& operator<< (const T& v)
92  {
93  push(v); return (*this);
94  }
96  void pop()
97  {
98  inc(head_);
99  }
101  T& operator[](int i)
102  {
103  return *(at(i));
104  }
106  const T& operator[](int i) const
107  {
108  return *(at(i));
109  }
111  const T& last() const
112  {
113  return buff_[head_];
114  }
116  unsigned int capacity() const
117  {
118  return cap_;
119  }
120 };
121 
122 template<class T, int N>
123 class running_average
124 {
125  T data[N];
126  T* p,*pend;
127 public:
128  explicit running_average(const T& v = 0)
129  {
130  p = &data[0];
131  pend = p + N;
132  while (p!=pend) *p++ = v;
133  p = &data[0];
134  }
135  running_average& operator<<(const T& v)
136  {
137  *p++ = v;
138  if (p==pend) p = &data[0];
139  return *this;
140  }
141  T operator()()
142  {
143  T m = 0;
144  for(int i = 0; i<N; ++i) m += data[i];
145  return m/N;
146  }
147  void clear()
148  {
149  for(int i=0; i<N; ++i) data[i]=0;
150  }
151 };
152 
153 
154 
155 template<class T>
156 class buffer : public QSharedData
157 {
158 public:
159  typedef QVector<T> container_t;
160 
161 private:
162  typedef buffer<T> _Self;
163 
165  container_t mem;
167  int sz;
169  int cp;
171  bool circular_;
173  int tail;
175  T x1, x2;
177  bool recalcBounds;
178 
179 
180  // make the buffer continous in memory and starting at mem[0]
181  void normalize_()
182  {
183  if (circular_ && sz && sz!=tail)
184  {
185  T* head = mem.data(); // pointer to buffer start address
186  T* temp = head + cp; // pointer to start of temp area
187  int ntemp = mem.size() - cp; // capacity of the temp area
188  if (sz==cp) {
189  int m = sz-tail;
190  if (tail<=ntemp)
191  {
192  memcpy(temp,head,tail*sizeof(T));
193  memmove(head,head+tail,m*sizeof(T));
194  memcpy(head + m,temp,tail*sizeof(T));
195  }
196  else
197  {
198  memcpy(temp,head+tail,m*sizeof(T));
199  memmove(head+m,head,tail*sizeof(T));
200  memcpy(head,temp,m*sizeof(T));
201  }
202  tail = 0;
203  } else if (tail > sz) { // contigous buffer
204  memmove(head, head + tail - sz, sz*sizeof(T));
205  tail = sz;
206  } else if (tail == 0) { // contigous buffer
207  memmove(head, head + cp - sz, sz*sizeof(T));
208  tail = sz;
209  } else { // split buffer
210  int nfront = tail;
211  int nback = sz - tail;
212  if (nfront <= ntemp) {
213  memcpy(temp,head,nfront*sizeof(T)); // copy the front to the temp area
214  memmove(head,head + (cp - nback),nback*sizeof(T)); // move the back to the start
215  memcpy(head + nback,temp,nfront*sizeof(T)); // copy from temp to the end
216  } else {
217  memcpy(temp, head + (cp - nback),nback*sizeof(T)); // copy the back to the temp area
218  memmove(head+nback,head,nfront*sizeof(T)); // move the front to the back
219  memcpy(head,temp,nback*sizeof(T)); // copy from temp to the start
220  }
221  tail = sz;
222  }
223  }
224  }
225 
226  // index takes care of circular buffers
227  int idx_(int i) const
228  {
229  return circular_ ? (tail - sz + i + cp) % cp : i;
230  }
231  // store a value
232  void set_(int i, const T& v)
233  {
234  mem[i] = v;
235  }
236  // calculated min/max
237  void calcBounds_()
238  {
239  int n(size());
240  if (n>0)
241  {
242  x1 = x2 = get(0);
243  for(int i=1; i<n; ++i)
244  {
245  double v = get(i);
246  if (v<x1) x1 = v;
247  if (v>x2) x2 = v;
248  }
249  }
250  else x1 = x2 = 0.;
251  recalcBounds = false;
252  }
253 
254 public:
255  explicit buffer(int acap = 0) : mem((int)acap),
256  sz(0), cp(acap), circular_(false), tail(0),
257  x1(0), x2(0), recalcBounds(true)
258  {
259  }
260  buffer(const _Self& rhs) : QSharedData(rhs), mem(rhs.mem),
261  sz(rhs.sz), cp(rhs.cp), circular_(rhs.circular_), tail(rhs.tail),
262  x1(rhs.x1), x2(rhs.x2), recalcBounds(rhs.recalcBounds)
263  {
264  }
265  ~buffer(void)
266  {
267  }
268 
269  _Self& operator=(const _Self& rhs)
270  {
271  mem = rhs.mem;
272  sz = rhs.sz;
273  cp = rhs.cp;
274  circular_ = rhs.circular_;
275  tail = rhs.tail;
276  x1 = rhs.x1;
277  x2 = rhs.x2;
278  recalcBounds = rhs.recalcBounds;
279  return (*this);
280  }
281 
282  bool operator == (const _Self& rhs) const
283  {
284  if (sz != rhs.sz) return false;
285 
286  if (mem.constData() == rhs.mem.constData()) return true;
287 
288  for(int i=0; i<size(); i++)
289  if ((*this)[i]!=rhs[i]) return false;
290 
291  return true;
292  }
293  bool operator != (const _Self& rhs) const
294  {
295  return !((*this)==rhs);
296  }
297 
298  int size() const { return (int)sz; }
299 
300  bool isCircular() const { return circular_; }
301  void setCircular(bool on)
302  {
303  if (on==circular_) return;
304  normalize_();
305  mem.resize(on ? cp + cp/2 : cp); // extra 0.5 size needed to swap mem during normalize_()
306  circular_ = on;
307  }
308 
309  int capacity() const { return (int)cp; }
310 
311  void setCapacity(int c)
312  {
313  if (c==cp) return;
314 
315  normalize_();
316 
317  if (circular_) {
318  mem.resize(c + c/2);
319  if (c>cp)
320  {
321  if (sz==cp) tail = sz;
322  }
323  else // (c<cp)
324  {
325  if (sz>c)
326  {
327  sz = c; tail = 0;
328  recalcBounds = true;
329  }
330  }
331  } else {
332  mem.resize(c);
333  if (sz>c) sz = c;
334  recalcBounds = true;
335  }
336  cp = c;
337  }
338  void setSize(int n)
339  {
340  if (n==sz) return;
341  if (n>cp) setCapacity(n);
342  else normalize_();
343  if (n>sz) ::memset(mem.data()+sz,0,n*sizeof(T));
344  sz = n;
345  tail = sz % cp;
346  }
347 
348  void clear()
349  {
350  sz = 0;
351  tail = 0;
352  recalcBounds = true;
353  }
354 
355 
356  T& operator[](int i)
357  {
358  return mem[idx_(i)];
359  }
360  const T& operator[](int i) const
361  {
362  return get(i);
363  }
364  const T& get(int i) const
365  {
366  return mem[idx_(i)];
367  }
368  void push(const T& v)
369  {
370  if (circular_) {
371  set_(tail++,v);
372  if (sz<cp) sz++;
373  tail %= cp;
374  } else {
375  if (sz==cp) mem.resize(++cp);
376  set_(sz++,v);
377  }
378  recalcBounds = true;
379  }
380  void push(const T* v, int n)
381  {
382  if (n<1) return;
383 
384  if (circular_) {
385  if (n>=cp) {
386  memcpy(mem.data(),v+n-cp,cp*sizeof(T));
387  tail = 0;
388  sz = cp;
389  }
390  else if (n<=cp-tail) {
391  memcpy(mem.data()+tail,v,n*sizeof(T));
392  tail += n;
393  if (sz<cp) sz += n;
394  if (sz==cp) tail %= cp;
395  } else {
396  int m = cp-tail;
397  memcpy(mem.data()+tail,v,m*sizeof(T));
398  v += m; n -= m;
399  memcpy(mem.data(),v,n*sizeof(T));
400  tail = n;
401  sz = cp;
402  }
403  } else {
404  if (sz+n>cp) { cp = sz+n; mem.resize(cp); }
405  memcpy(mem.data()+sz,v,n*sizeof(T));
406  sz += n;
407  }
408  recalcBounds = true;
409  }
410  void pop()
411  {
412  if (sz==0) return;
413  sz--;
414  if (circular_) tail = (tail - 1) % sz;
415  recalcBounds = true;
416  }
417  const T* constData() const
418  {
419  const_cast< _Self * >( this )->normalize_();
420  return mem.constData();
421  }
422  T* data()
423  {
424  normalize_();
425  return mem.data();
426  }
427  container_t vector() const
428  {
429  const_cast< _Self * >( this )->normalize_();
430  return mem.mid(0,sz);
431  }
432  double vmin() const
433  {
434  if (recalcBounds)
435  const_cast< _Self * >( this )->calcBounds_();
436  return x1;
437  }
438  double vmax() const
439  {
440  if (recalcBounds)
441  const_cast< _Self * >( this )->calcBounds_();
442  return x2;
443  }
444  double mean() const
445  {
446  double s(0.0);
447  int n(size());
448  for(int i=0; i<n; ++i) s += get(i);
449  return s/n;
450  }
451  double std() const
452  {
453  double s1(0.0), s2(0.0);
454  int n(size());
455  for(int i=0; i<n; ++i) {
456  double v = get(i);
457  s1 += v; s2 += v*v;
458  }
459  s1 /= n;
460  s2 /= n;
461  s1 = s2 - s1*s1;
462  if (s1<=0.0) return 0.0;
463  else return sqrt(s1);
464  }
465 };
466 
467 } // namespace math
468 #endif
469 
circular_buffer(unsigned int nmax=1)
Construct a circular_buffer with capacity nmax.
Definition: math_util.h:62
unsigned int capacity() const
return the buffer&#39;s capacity
Definition: math_util.h:116
void push(const T &v)
insert an element.
Definition: math_util.h:85
const T & last() const
const ref to last element inserted
Definition: math_util.h:111
const T & operator[](int i) const
const ref to the i-th element
Definition: math_util.h:106
T & operator[](int i)
ref to the i-th element
Definition: math_util.h:101
A circular LIFO buffer class.
Definition: math_util.h:31
void pop()
remove the last inserted element
Definition: math_util.h:96
self_t & operator<<(const T &v)
insertion operator is the same as push()
Definition: math_util.h:91
void alloc(unsigned int nmax)
allocate memory for nmax elements (nmax is adjusted to 2^N).
Definition: math_util.h:73