Visual Servoing Platform  version 3.6.1 under development (2024-11-15)
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 
43 #include <visp3/core/vpMath.h>
44 
45 BEGIN_VISP_NAMESPACE
48 
50 {
51  std::string name;
52  switch (alarm) {
53  case THREE_SIGMA_WECO:
54  name = "3-sigma alarm";
55  break;
56  case TWO_SIGMA_WECO:
57  name = "2-sigma alarm";
58  break;
59  case ONE_SIGMA_WECO:
60  name = "1-sigma alarm";
61  break;
62  case SAME_SIDE_WECO:
63  name = "Same-side alarm";
64  break;
65  case NONE_WECO:
66  name = "No alarm";
67  break;
68  default:
69  name = "Unknown WECO alarm";
70  }
71  return name;
72 }
73 
75 {
76  float delta = 3.f * m_stdev;
77  m_limitDown = m_mean - delta;
78  m_limitUp = m_mean + delta;
83 }
84 
86 {
89  }
93  }
94  if (!m_activateWECOrules) {
96  }
98  unsigned int id = vpMath::modulo(m_idCurrentData - (NB_DATA_SIGNAL - 1), NB_DATA_SIGNAL);
99  unsigned int i = 0;
100  unsigned int nbAboveMean = 0;
101  unsigned int nbAbove2SigmaLimit = 0;
102  unsigned int nbAbove1SigmaLimit = 0;
103  while (i < NB_DATA_SIGNAL) {
104  // Reinit for next iteration
105  nbAbove2SigmaLimit = 0;
106  nbAbove1SigmaLimit = 0;
108  // Single-side test
109  ++nbAboveMean;
110  }
111  if (i > 3 && m_activatedWECOrules[TWO_SIGMA_WECO]) {
112  // Two sigma test
113  for (unsigned int idPrev = vpMath::modulo(id - 2, NB_DATA_SIGNAL); idPrev != id; idPrev = vpMath::modulo(idPrev + 1, NB_DATA_SIGNAL)) {
114  if (m_signal[idPrev] <= m_twoSigmaNegLim) {
115  ++nbAbove2SigmaLimit;
116  }
117  }
118  if (m_signal[id] <= m_twoSigmaNegLim) {
119  ++nbAbove2SigmaLimit;
120  }
121  if (nbAbove2SigmaLimit >= 2) {
122  break;
123  }
124  }
125  if (i > 5 && m_activatedWECOrules[ONE_SIGMA_WECO]) {
126  // One sigma test
127  for (unsigned int idPrev = vpMath::modulo(id - 4, NB_DATA_SIGNAL); idPrev != id; idPrev = vpMath::modulo(idPrev + 1, NB_DATA_SIGNAL)) {
128  if (m_signal[idPrev] <= m_oneSigmaNegLim) {
129  ++nbAbove1SigmaLimit;
130  }
131  }
132  if (m_signal[id] <= m_oneSigmaNegLim) {
133  ++nbAbove1SigmaLimit;
134  }
135  if (nbAbove1SigmaLimit >= 4) {
136  break;
137  }
138  }
139  id = vpMath::modulo(id + 1, NB_DATA_SIGNAL);
140  ++i;
141  }
142  if (nbAboveMean == NB_DATA_SIGNAL) {
144  result = MEAN_DRIFT_DOWNWARD;
145  }
146  else if (nbAbove2SigmaLimit >= 2) {
148  result = MEAN_DRIFT_DOWNWARD;
149  }
150  else if (nbAbove1SigmaLimit >= 4) {
152  result = MEAN_DRIFT_DOWNWARD;
153  }
154  return result;
155 }
156 
158 {
161  }
165  }
166  if (!m_activateWECOrules) {
168  }
170  unsigned int id = vpMath::modulo(m_idCurrentData - (NB_DATA_SIGNAL - 1), NB_DATA_SIGNAL);
171  unsigned int i = 0;
172  unsigned int nbAboveMean = 0;
173  unsigned int nbAbove2SigmaLimit = 0;
174  unsigned int nbAbove1SigmaLimit = 0;
175  while (i < NB_DATA_SIGNAL) {
176  // Reinit for next iteration
177  nbAbove2SigmaLimit = 0;
178  nbAbove1SigmaLimit = 0;
180  // Single-side test
181  ++nbAboveMean;
182  }
183  if (i > 3 && m_activatedWECOrules[TWO_SIGMA_WECO]) {
184  // Two sigma test
185  for (unsigned int idPrev = vpMath::modulo(id - 2, NB_DATA_SIGNAL); idPrev != id; idPrev = vpMath::modulo(idPrev + 1, NB_DATA_SIGNAL)) {
186  if (m_signal[idPrev] >= m_twoSigmaPosLim) {
187  ++nbAbove2SigmaLimit;
188  }
189  }
190  if (m_signal[id] >= m_twoSigmaPosLim) {
191  ++nbAbove2SigmaLimit;
192  }
193  if (nbAbove2SigmaLimit >= 2) {
194  break;
195  }
196  }
197  if (i > 5 && m_activatedWECOrules[ONE_SIGMA_WECO]) {
198  // One sigma test
199  for (unsigned int idPrev = vpMath::modulo(id - 4, NB_DATA_SIGNAL); idPrev != id; idPrev = vpMath::modulo(idPrev + 1, NB_DATA_SIGNAL)) {
200  if (m_signal[idPrev] >= m_oneSigmaPosLim) {
201  ++nbAbove1SigmaLimit;
202  }
203  }
204  if (m_signal[id] >= m_oneSigmaPosLim) {
205  ++nbAbove1SigmaLimit;
206  }
207  if (nbAbove1SigmaLimit >= 4) {
208  break;
209  }
210  }
211  id = vpMath::modulo(id + 1, NB_DATA_SIGNAL);
212  ++i;
213  }
214  if (nbAboveMean == NB_DATA_SIGNAL) {
216  result = MEAN_DRIFT_UPWARD;
217  }
218  else if (nbAbove2SigmaLimit >= 2) {
220  result = MEAN_DRIFT_UPWARD;
221  }
222  else if (nbAbove1SigmaLimit >= 4) {
224  result = MEAN_DRIFT_UPWARD;
225  }
226  return result;
227 }
228 
230 {
231  bool areStatsAvailable = vpStatisticalTestAbstract::updateStatistics(signal);
232  updateTestSignals(signal); // Store the signal in the circular buffer too.
233  if (areStatsAvailable) {
234  computeLimits();
235  }
236  return areStatsAvailable;
237 }
238 
240 {
242  m_signal[m_idCurrentData] = signal;
245  }
246 }
247 
248 vpStatisticalTestShewhart::vpStatisticalTestShewhart(const bool &activateWECOrules, const bool activatedRules[COUNT_WECO - 1], const unsigned int &nbSamplesForStats)
249  : vpStatisticalTestSigma(3, nbSamplesForStats)
250  , m_nbDataInBuffer(0)
251  , m_activateWECOrules(activateWECOrules)
252  , m_idCurrentData(0)
253  , m_alarm(NONE_WECO)
254  , m_oneSigmaNegLim(0.f)
255  , m_oneSigmaPosLim(0.f)
256  , m_twoSigmaNegLim(0.f)
257  , m_twoSigmaPosLim(0.f)
258 {
259  init(activateWECOrules, activatedRules, nbSamplesForStats);
260 }
261 
262 vpStatisticalTestShewhart::vpStatisticalTestShewhart(const bool &activateWECOrules, const bool activatedRules[COUNT_WECO - 1], const float &mean, const float &stdev)
264  , m_nbDataInBuffer(0)
265  , m_activateWECOrules(activateWECOrules)
266  , m_idCurrentData(0)
267  , m_alarm(NONE_WECO)
268  , m_oneSigmaNegLim(0.f)
269  , m_oneSigmaPosLim(0.f)
270  , m_twoSigmaNegLim(0.f)
271  , m_twoSigmaPosLim(0.f)
272 {
273  init(activateWECOrules, activatedRules, mean, stdev);
274 }
275 
276 std::vector<float> vpStatisticalTestShewhart::getSignals() const
277 {
278  std::vector<float> signals;
279  for (unsigned int i = 0; i < NB_DATA_SIGNAL; ++i) {
280  unsigned int id = vpMath::modulo(m_idCurrentData - (NB_DATA_SIGNAL - i - 1), NB_DATA_SIGNAL);
281  signals.push_back(m_signal[id]);
282  }
283  return signals;
284 }
285 
286 void vpStatisticalTestShewhart::init(const bool &activateWECOrules, const bool activatedRules[COUNT_WECO - 1], const unsigned int &nbSamplesForStats)
287 {
288  vpStatisticalTestSigma::init(3.f, nbSamplesForStats);
289  m_nbDataInBuffer = 0;
290  memset(m_signal, 0, NB_DATA_SIGNAL * sizeof(float));
291  m_activateWECOrules = activateWECOrules;
292  std::memcpy(m_activatedWECOrules, activatedRules, (COUNT_WECO - 1) * sizeof(bool));
293  m_idCurrentData = 0;
294  m_alarm = NONE_WECO;
295  m_oneSigmaNegLim = 0.f;
296  m_oneSigmaPosLim = 0.f;
297  m_twoSigmaNegLim = 0.f;
298  m_twoSigmaPosLim = 0.f;
299 }
300 
301 void vpStatisticalTestShewhart::init(const bool &activateWECOrules, const bool activatedRules[COUNT_WECO - 1], const float &mean, const float &stdev)
302 {
303  vpStatisticalTestShewhart::init(activateWECOrules, activatedRules, 30);
304  m_mean = mean;
305  m_stdev = stdev;
306  computeLimits();
308 }
309 END_VISP_NAMESPACE
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...
bool m_activatedWECOrules[COUNT_WECO - 1]
vpStatisticalTestShewhart(const bool &activateWECOrules=true, const bool activatedRules[COUNT_WECO - 1]=CONST_ALL_WECO_ACTIVATED, const unsigned int &nbSamplesForStats=30)
Construct a new vpStatisticalTestShewhart object.
virtual void computeLimits() override
Compute the upper and lower limits of the test signal.
static const unsigned int NB_DATA_SIGNAL
virtual vpMeanDriftType detectUpwardMeanDrift() override
Detects if an upward mean drift occurred on the mean.
std::vector< float > getSignals() const
Get the NB_DATA_SIGNAL last signal values, sorted from the latest [0] to the newest [NB_DATA_SIGNAL -...
virtual vpMeanDriftType detectDownwardMeanDrift() override
Detects if a downward mean drift occurred.
virtual void updateTestSignals(const float &signal) override
Update the test signals.
virtual bool updateStatistics(const float &signal) override
Update m_s and if enough values are available, compute the mean, the standard deviation and the limit...
static const bool CONST_ALL_WECO_ACTIVATED[COUNT_WECO - 1]
static std::string vpWecoRulesAlarmToString(const vpWecoRulesAlarm &alarm)
Class that permits a simple test comparing the current value to the standard deviation of the signal.