Visual Servoing Platform  version 3.6.1 under development (2025-03-16)
vpStatisticalTestShewhart.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/vpStatisticalTestShewhart.h>
40 
41 #include<cstring>
42 #include<sstream>
43 
44 #include <visp3/core/vpException.h>
45 #include <visp3/core/vpMath.h>
46 
47 BEGIN_VISP_NAMESPACE
49 
50 #if (VISP_CXX_STANDARD < VISP_CXX_STANDARD_17)
51 const std::vector<bool> vpStatisticalTestShewhart::CONST_ALL_WECO_ACTIVATED = std::vector<bool>(vpStatisticalTestShewhart::COUNT_WECO -1, true);
52 #endif
53 
55 {
56  std::string name;
57  switch (alarm) {
58  case THREE_SIGMA_WECO:
59  name = "3-sigma alarm";
60  break;
61  case TWO_SIGMA_WECO:
62  name = "2-sigma alarm";
63  break;
64  case ONE_SIGMA_WECO:
65  name = "1-sigma alarm";
66  break;
67  case SAME_SIDE_WECO:
68  name = "Same-side alarm";
69  break;
70  case NONE_WECO:
71  name = "No alarm";
72  break;
73  default:
74  name = "Unknown WECO alarm";
75  }
76  return name;
77 }
78 
80 {
81  float delta = 3.f * m_stdev;
82  m_limitDown = m_mean - delta;
83  m_limitUp = m_mean + delta;
88 }
89 
91 {
94  }
98  }
99  if (!m_activateWECOrules) {
101  }
103  unsigned int id = vpMath::modulo(m_idCurrentData - (NB_DATA_SIGNAL - 1), NB_DATA_SIGNAL);
104  unsigned int i = 0;
105  unsigned int nbAboveMean = 0;
106  unsigned int nbAbove2SigmaLimit = 0;
107  unsigned int nbAbove1SigmaLimit = 0;
108  while (i < NB_DATA_SIGNAL) {
109  // Reinit for next iteration
110  nbAbove2SigmaLimit = 0;
111  nbAbove1SigmaLimit = 0;
113  // Single-side test
114  ++nbAboveMean;
115  }
116  if (i > 3 && m_activatedWECOrules[TWO_SIGMA_WECO]) {
117  // Two sigma test
118  for (unsigned int idPrev = vpMath::modulo(id - 2, NB_DATA_SIGNAL); idPrev != id; idPrev = vpMath::modulo(idPrev + 1, NB_DATA_SIGNAL)) {
119  if (m_signal[idPrev] <= m_twoSigmaNegLim) {
120  ++nbAbove2SigmaLimit;
121  }
122  }
123  if (m_signal[id] <= m_twoSigmaNegLim) {
124  ++nbAbove2SigmaLimit;
125  }
126  if (nbAbove2SigmaLimit >= 2) {
127  break;
128  }
129  }
130  if (i > 5 && m_activatedWECOrules[ONE_SIGMA_WECO]) {
131  // One sigma test
132  for (unsigned int idPrev = vpMath::modulo(id - 4, NB_DATA_SIGNAL); idPrev != id; idPrev = vpMath::modulo(idPrev + 1, NB_DATA_SIGNAL)) {
133  if (m_signal[idPrev] <= m_oneSigmaNegLim) {
134  ++nbAbove1SigmaLimit;
135  }
136  }
137  if (m_signal[id] <= m_oneSigmaNegLim) {
138  ++nbAbove1SigmaLimit;
139  }
140  if (nbAbove1SigmaLimit >= 4) {
141  break;
142  }
143  }
144  id = vpMath::modulo(id + 1, NB_DATA_SIGNAL);
145  ++i;
146  }
147  if (nbAboveMean == NB_DATA_SIGNAL) {
149  result = MEAN_DRIFT_DOWNWARD;
150  }
151  else if (nbAbove2SigmaLimit >= 2) {
153  result = MEAN_DRIFT_DOWNWARD;
154  }
155  else if (nbAbove1SigmaLimit >= 4) {
157  result = MEAN_DRIFT_DOWNWARD;
158  }
159  return result;
160 }
161 
163 {
166  }
170  }
171  if (!m_activateWECOrules) {
173  }
175  unsigned int id = vpMath::modulo(m_idCurrentData - (NB_DATA_SIGNAL - 1), NB_DATA_SIGNAL);
176  unsigned int i = 0;
177  unsigned int nbAboveMean = 0;
178  unsigned int nbAbove2SigmaLimit = 0;
179  unsigned int nbAbove1SigmaLimit = 0;
180  while (i < NB_DATA_SIGNAL) {
181  // Reinit for next iteration
182  nbAbove2SigmaLimit = 0;
183  nbAbove1SigmaLimit = 0;
185  // Single-side test
186  ++nbAboveMean;
187  }
188  if (i > 3 && m_activatedWECOrules[TWO_SIGMA_WECO]) {
189  // Two sigma test
190  for (unsigned int idPrev = vpMath::modulo(id - 2, NB_DATA_SIGNAL); idPrev != id; idPrev = vpMath::modulo(idPrev + 1, NB_DATA_SIGNAL)) {
191  if (m_signal[idPrev] >= m_twoSigmaPosLim) {
192  ++nbAbove2SigmaLimit;
193  }
194  }
195  if (m_signal[id] >= m_twoSigmaPosLim) {
196  ++nbAbove2SigmaLimit;
197  }
198  if (nbAbove2SigmaLimit >= 2) {
199  break;
200  }
201  }
202  if (i > 5 && m_activatedWECOrules[ONE_SIGMA_WECO]) {
203  // One sigma test
204  for (unsigned int idPrev = vpMath::modulo(id - 4, NB_DATA_SIGNAL); idPrev != id; idPrev = vpMath::modulo(idPrev + 1, NB_DATA_SIGNAL)) {
205  if (m_signal[idPrev] >= m_oneSigmaPosLim) {
206  ++nbAbove1SigmaLimit;
207  }
208  }
209  if (m_signal[id] >= m_oneSigmaPosLim) {
210  ++nbAbove1SigmaLimit;
211  }
212  if (nbAbove1SigmaLimit >= 4) {
213  break;
214  }
215  }
216  id = vpMath::modulo(id + 1, NB_DATA_SIGNAL);
217  ++i;
218  }
219  if (nbAboveMean == NB_DATA_SIGNAL) {
221  result = MEAN_DRIFT_UPWARD;
222  }
223  else if (nbAbove2SigmaLimit >= 2) {
225  result = MEAN_DRIFT_UPWARD;
226  }
227  else if (nbAbove1SigmaLimit >= 4) {
229  result = MEAN_DRIFT_UPWARD;
230  }
231  return result;
232 }
233 
235 {
236  bool areStatsAvailable = vpStatisticalTestAbstract::updateStatistics(signal);
237  updateTestSignals(signal); // Store the signal in the circular buffer too.
238  if (areStatsAvailable) {
239  computeLimits();
240  }
241  return areStatsAvailable;
242 }
243 
245 {
247  m_signal[m_idCurrentData] = signal;
250  }
251 }
252 
253 vpStatisticalTestShewhart::vpStatisticalTestShewhart(const bool &activateWECOrules, const std::vector<bool> &activatedRules, const unsigned int &nbSamplesForStats)
254  : vpStatisticalTestSigma(3, nbSamplesForStats)
255  , m_nbDataInBuffer(0)
256  , m_activateWECOrules(activateWECOrules)
257  , m_idCurrentData(0)
258  , m_alarm(NONE_WECO)
259  , m_oneSigmaNegLim(0.f)
260  , m_oneSigmaPosLim(0.f)
261  , m_twoSigmaNegLim(0.f)
262  , m_twoSigmaPosLim(0.f)
263 {
264  init(activateWECOrules, activatedRules, nbSamplesForStats);
265 }
266 
267 vpStatisticalTestShewhart::vpStatisticalTestShewhart(const bool &activateWECOrules, const std::vector<bool> &activatedRules, const float &mean, const float &stdev)
269  , m_nbDataInBuffer(0)
270  , m_activateWECOrules(activateWECOrules)
271  , m_idCurrentData(0)
272  , m_alarm(NONE_WECO)
273  , m_oneSigmaNegLim(0.f)
274  , m_oneSigmaPosLim(0.f)
275  , m_twoSigmaNegLim(0.f)
276  , m_twoSigmaPosLim(0.f)
277 {
278  init(activateWECOrules, activatedRules, mean, stdev);
279 }
280 
281 std::vector<float> vpStatisticalTestShewhart::getSignals() const
282 {
283  std::vector<float> signals;
284  for (unsigned int i = 0; i < NB_DATA_SIGNAL; ++i) {
285  unsigned int id = vpMath::modulo(m_idCurrentData - (NB_DATA_SIGNAL - i - 1), NB_DATA_SIGNAL);
286  signals.push_back(m_signal[id]);
287  }
288  return signals;
289 }
290 
291 void vpStatisticalTestShewhart::init(const bool &activateWECOrules, const std::vector<bool> &activatedRules, const unsigned int &nbSamplesForStats)
292 {
293  vpStatisticalTestSigma::init(3.f, nbSamplesForStats);
294  m_nbDataInBuffer = 0;
295  memset(m_signal, 0, NB_DATA_SIGNAL * sizeof(float));
296  m_activateWECOrules = activateWECOrules;
297  if (activatedRules.size() != COUNT_WECO - 1) {
298  std::stringstream errMsg;
299  errMsg << "Error: the expected number of rules is " << COUNT_WECO -1 << ", the number given to the method is " << activatedRules.size() << std::endl;
300  throw(vpException(vpException::dimensionError, errMsg.str()));
301  }
302  m_activatedWECOrules = activatedRules;
303  m_idCurrentData = 0;
304  m_alarm = NONE_WECO;
305  m_oneSigmaNegLim = 0.f;
306  m_oneSigmaPosLim = 0.f;
307  m_twoSigmaNegLim = 0.f;
308  m_twoSigmaPosLim = 0.f;
309 }
310 
311 void vpStatisticalTestShewhart::init(const bool &activateWECOrules, const std::vector<bool> &activatedRules, const float &mean, const float &stdev)
312 {
313  vpStatisticalTestShewhart::init(activateWECOrules, activatedRules, 30);
314  m_mean = mean;
315  m_stdev = stdev;
316  computeLimits();
318 }
319 END_VISP_NAMESPACE
error that can be emitted by ViSP classes.
Definition: vpException.h:60
@ dimensionError
Bad dimension.
Definition: vpException.h:71
static float modulo(const float &value, const float &modulo)
Gives the rest of value divided by modulo when the quotient can only be an integer.
Definition: vpMath.h:177
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...
vpStatisticalTestShewhart(const bool &activateWECOrules=true, const std::vector< bool > &activatedRules=CONST_ALL_WECO_ACTIVATED, const unsigned int &nbSamplesForStats=30)
Construct a new vpStatisticalTestShewhart object.
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...
static const unsigned int NB_DATA_SIGNAL
virtual vpMeanDriftType detectUpwardMeanDrift() VP_OVERRIDE
Detects if an upward mean drift occurred on the mean.
virtual vpMeanDriftType detectDownwardMeanDrift() VP_OVERRIDE
Detects if a downward mean drift occurred.
static const std::vector< bool > CONST_ALL_WECO_ACTIVATED
virtual void updateTestSignals(const float &signal) VP_OVERRIDE
Update the test signals.
std::vector< float > getSignals() const
Get the NB_DATA_SIGNAL last signal values, sorted from the latest [0] to the newest [NB_DATA_SIGNAL -...
std::vector< bool > m_activatedWECOrules
virtual void computeLimits() VP_OVERRIDE
Compute the upper and lower limits of the test signal.
static std::string vpWecoRulesAlarmToString(const vpWecoRulesAlarm &alarm)
Class that permits a simple test comparing the current value to the standard deviation of the signal.