Visual Servoing Platform  version 3.6.1 under development (2024-05-03)
vpStatisticalTestShewhart.cpp
1 /****************************************************************************
2  *
3  * ViSP, open source Visual Servoing Platform software.
4  * Copyright (C) 2005 - 2024 by Inria. All rights reserved.
5  *
6  * This software is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  * See the file LICENSE.txt at the root directory of this source
11  * distribution for additional information about the GNU GPL.
12  *
13  * For using ViSP with software that can not be combined with the GNU
14  * GPL, please contact Inria about acquiring a ViSP Professional
15  * Edition License.
16  *
17  * See https://visp.inria.fr for more information.
18  *
19  * This software was developed at:
20  * Inria Rennes - Bretagne Atlantique
21  * Campus Universitaire de Beaulieu
22  * 35042 Rennes Cedex
23  * France
24  *
25  * If you have questions regarding the use of this file, please contact
26  * Inria at visp@inria.fr
27  *
28  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
29  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
30  */
31 
40 #include <visp3/core/vpStatisticalTestShewhart.h>
41 
42 #include<cstring>
43 
44 #include <visp3/core/vpMath.h>
45 
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  }
99  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 (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 (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  }
171  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 (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 (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 (int i = 0; i < NB_DATA_SIGNAL; ++i) {
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 }
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:175
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.
virtual vpMeanDriftType detectUpwardMeanDrift() override
Detects if an upward mean drift occured 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 occured.
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.