Visual Servoing Platform  version 3.6.1 under development (2025-03-13)
vpStatisticalTestHinkley.cpp
1 /*
2  * ViSP, open source Visual Servoing Platform software.
3  * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
4  *
5  * This software is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  * See the file LICENSE.txt at the root directory of this source
10  * distribution for additional information about the GNU GPL.
11  *
12  * For using ViSP with software that can not be combined with the GNU
13  * GPL, please contact Inria about acquiring a ViSP Professional
14  * Edition License.
15  *
16  * See https://visp.inria.fr for more information.
17  *
18  * This software was developed at:
19  * Inria Rennes - Bretagne Atlantique
20  * Campus Universitaire de Beaulieu
21  * 35042 Rennes Cedex
22  * France
23  *
24  * If you have questions regarding the use of this file, please contact
25  * Inria at visp@inria.fr
26  *
27  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
28  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
29  */
30 
39 #include <visp3/core/vpStatisticalTestHinkley.h>
40 #include <visp3/core/vpMath.h>
41 
42 #include <cmath> // std::fabs
43 #include <iostream>
44 #include <limits> // numeric_limits
45 #include <stdio.h>
46 #include <stdlib.h>
47 
48 BEGIN_VISP_NAMESPACE
51  , m_dmin2(0.1f)
52  , m_alpha(0.2f)
53  , m_Sk(0.f)
54  , m_Mk(0.f)
55  , m_Tk(0.f)
56  , m_Nk(0.f)
57  , m_computeDeltaAndAlpha(false)
58  , m_h(4.76f)
59  , m_k(1.f)
60 {
61  init();
62 }
63 
64 vpStatisticalTestHinkley::vpStatisticalTestHinkley(const float &alpha, const float &delta_val, const unsigned int &nbSamplesForInit)
66  , m_dmin2(delta_val / 2.f)
67  , m_alpha(alpha)
68  , m_Sk(0.f)
69  , m_Mk(0.f)
70  , m_Tk(0.f)
71  , m_Nk(0.f)
72  , m_computeDeltaAndAlpha(false)
73  , m_h(4.76f)
74  , m_k(1.f)
75 {
76  init(alpha, delta_val, nbSamplesForInit);
77 }
78 
79 vpStatisticalTestHinkley::vpStatisticalTestHinkley(const float &h, const float &k, const bool &computeAlphaDeltaFromStdev, const unsigned int &nbSamplesForInit)
81 {
82  init(h, k, computeAlphaDeltaFromStdev, nbSamplesForInit);
83 }
84 
85 vpStatisticalTestHinkley::vpStatisticalTestHinkley(const float &h, const float &k, const float &mean, const float &stdev)
87 {
88  init(h, k, mean, stdev);
89 }
90 
92 {
96 
97  m_Sk = 0.f;
98  m_Mk = 0.f;
99 
100  m_Tk = 0.f;
101  m_Nk = 0.f;
102 
103  m_computeDeltaAndAlpha = false;
104 }
105 
106 void vpStatisticalTestHinkley::init(const float &alpha, const float &delta_val, const unsigned int &nbSamplesForInit)
107 {
108  init();
109  setNbSamplesForStat(nbSamplesForInit);
110  setAlpha(alpha);
111  setDelta(delta_val);
112  m_computeDeltaAndAlpha = false;
113 }
114 
115 void vpStatisticalTestHinkley::init(const float &alpha, const float &delta_val, const float &mean)
116 {
117  init();
118  setAlpha(alpha);
119  setDelta(delta_val);
120  m_mean = mean;
121  m_computeDeltaAndAlpha = false;
123 }
124 
125 void vpStatisticalTestHinkley::init(const float &h, const float &k, const bool &computeAlphaDeltaFromStdev, const unsigned int &nbSamples)
126 {
127  if (!computeAlphaDeltaFromStdev) {
128  throw(vpException(vpException::badValue, "computeAlphaDeltaFromStdev must be true, or use another init function"));
129  }
130  init();
131  setNbSamplesForStat(nbSamples);
132  m_h = h;
133  m_k = k;
134  m_computeDeltaAndAlpha = true;
135 }
136 
137 void vpStatisticalTestHinkley::init(const float &h, const float &k, const float &mean, const float &stdev)
138 {
139  init();
140  m_mean = mean;
141  m_stdev = stdev;
142  m_h = h;
143  m_k = k;
144  m_computeDeltaAndAlpha = true;
147 }
148 
150 
151 void vpStatisticalTestHinkley::setDelta(const float &delta) { m_dmin2 = delta / 2.f; }
152 
153 void vpStatisticalTestHinkley::setAlpha(const float &alpha)
154 {
155  this->m_alpha = alpha;
157  m_limitUp = m_alpha;
158 }
159 
161 {
162  float delta = m_k * m_stdev;
163  setDelta(delta);
164  float alpha = m_h * m_stdev;
165  setAlpha(alpha);
166 }
167 
169 {
170  // When the mean slowly increases or decreases, especially after an abrupt change of the mean,
171  // the means tends to drift. To reduce the drift of the mean
172  // it is updated with the current value of the signal only if
173  // a beginning of a mean drift is not detected,
174  // i.e. if ( ((m_Mk-m_Sk) == 0) && ((m_Tk-m_Nk) == 0) )
175  if ((std::fabs(m_Mk - m_Sk) <= std::fabs(vpMath::maximum(m_Mk, m_Sk)) * std::numeric_limits<double>::epsilon()) &&
176  (std::fabs(m_Tk - m_Nk) <= std::fabs(vpMath::maximum(m_Tk, m_Nk)) * std::numeric_limits<double>::epsilon())) {
177  m_mean = (m_mean * (m_count - 1) + static_cast<float>(signal)) / (m_count);
178  }
179 }
180 
182 {
183  m_Sk += static_cast<float>(signal) - m_mean + m_dmin2;
184 }
185 
187 {
188  if (m_Sk > m_Mk) {
189  m_Mk = m_Sk;
190  }
191 }
192 
194 {
195  m_Tk += static_cast<float>(signal) - m_mean - m_dmin2;
196 }
197 
199 {
200  if (m_Tk < m_Nk) {
201  m_Nk = m_Tk;
202  }
203 }
204 
206 {
208  if ((m_Mk - m_Sk) > m_alpha) {
209  shift = MEAN_DRIFT_DOWNWARD;
210  }
211  return shift;
212 }
213 
215 {
217  if ((m_Tk - m_Nk) > m_alpha) {
218  shift = MEAN_DRIFT_UPWARD;
219  }
220  return shift;
221 }
222 
224 {
225  bool updateStats = vpStatisticalTestAbstract::updateStatistics(signal);
227  // If needed, compute alpha and delta
230  }
231  // Initialize the test signals
232  m_Mk = 0.f;
233  m_Nk = 0.f;
234  m_Sk = 0.f;
235  m_Tk = 0.f;
236  }
237  return updateStats;
238 }
239 
241 {
242  computeSk(signal);
243  computeTk(signal);
244 
245  computeMk();
246  computeNk();
247 
248  ++m_count;
249  computeMean(signal);
250 }
251 END_VISP_NAMESPACE
error that can be emitted by ViSP classes.
Definition: vpException.h:60
@ badValue
Used to indicate that a value is not in the allowed range.
Definition: vpException.h:73
static Type maximum(const Type &a, const Type &b)
Definition: vpMath.h:254
Base class for methods detecting the drift of the mean of a process.
vpMeanDriftType
Enum that indicates if a drift of the mean occurred.
void init()
(Re)Initialize the algorithm.
virtual bool updateStatistics(const float &signal)
Update m_s and if enough values are available, compute the mean, the standard deviation and the limit...
void setNbSamplesForStat(const unsigned int &nbSamples)
Set the number of samples required to compute the mean and standard deviation of the signal and alloc...
vpStatisticalTestHinkley()
Construct a new vpStatisticalTestHinkley object. Call init() to initialise the Hinkley's test and set...
void setAlpha(const float &alpha)
The threshold indicating that a mean drift occurs.
virtual vpMeanDriftType detectDownwardMeanDrift() VP_OVERRIDE
Detects if a downward mean drift occurred.
virtual ~vpStatisticalTestHinkley()
Destroy the vpStatisticalTestHinkley object.
virtual void computeAlphaDelta()
Compute and from the standard deviation of the signal.
void setDelta(const float &delta)
Set the drift minimal magnitude that we want to detect.
void computeTk(double signal)
Compute .
void computeMk()
Compute , the maximum value of .
virtual vpMeanDriftType detectUpwardMeanDrift() VP_OVERRIDE
Detects if an upward mean drift occurred on the mean.
void computeNk()
Compute , the minimum value of .
virtual bool updateStatistics(const float &signal) VP_OVERRIDE
Update m_s and if enough values are available, compute the mean, the standard deviation and the limit...
void computeSk(double signal)
Compute .
void init()
Initialise the Hinkley's test by setting the mean signal value to zero as well as .
void computeMean(double signal)
Compute the mean value of the signal. The mean value must be computed before the mean drift is estim...
virtual void updateTestSignals(const float &signal) VP_OVERRIDE
Update the test signals.