Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
testSPC.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 * Description:
31 * Test various Statistical Process Control methods.
32 */
33
38
39#include <iostream>
40#include <string>
41
42#include <visp3/core/vpStatisticalTestEWMA.h>
43#include <visp3/core/vpStatisticalTestHinkley.h>
44#include <visp3/core/vpStatisticalTestMeanAdjustedCUSUM.h>
45#include <visp3/core/vpStatisticalTestShewhart.h>
46#include <visp3/core/vpStatisticalTestSigma.h>
47
48#ifdef ENABLE_VISP_NAMESPACE
49using namespace VISP_NAMESPACE_NAME;
50#endif
51
52bool initializeShewhartTest(const float &mean, const float &stdev, const bool &verbose, const std::string &testName, vpStatisticalTestShewhart &tester);
53void usage(const char *name);
54bool getOptions(int argc, const char **argv, float &opt_mean, float &opt_stdev, bool &opt_verbose);
55
56bool initializeShewhartTest(const float &mean, const float &stdev, const bool &verbose, const std::string &testName, vpStatisticalTestShewhart &tester)
57{
58 const bool activateWECOrules = true;
59 tester.init(activateWECOrules, vpStatisticalTestShewhart::CONST_ALL_WECO_ACTIVATED, mean, stdev);
60 bool isInitOK = true;
63 unsigned int i = 0;
64 while ((i < vpStatisticalTestShewhart::NB_DATA_SIGNAL - 1) && isInitOK) {
65 drift = tester.testDownUpwardMeanDrift(mean);
66 isInitOK = (drift == EXPECTED_DRIFT_INIT);
67 if (isInitOK) {
68 ++i;
69 }
70 }
71 if (!isInitOK) {
72 if (verbose) {
73 std::cerr << "\t" << testName << " test initialization failed: " << std::endl;
74 std::cerr << "\t\ts(t) = " << tester.getSignal() << std::endl;
75 float limitDown = 0.f, limitUp = 0.f;
76 tester.getLimits(limitDown, limitUp);
77 std::cerr << "\t\tlim_- = " << limitDown << std::endl;
78 std::cerr << "\t\tlim_+ = " << limitUp << std::endl;
79 std::cerr << "\t\tdetected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl;
80 std::cerr << "\t\texpected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(EXPECTED_DRIFT_INIT) << std::endl;
81 }
82 }
83 return isInitOK;
84}
85
86void usage(const char *name)
87{
88 std::cout << "SYNOPSIS " << std::endl;
89 std::cout << name << "[--mean <value>] [--stdev <value>] [-v, --verbose] [-h, --help]" << std::endl;
90 std::cout << "\nOPTIONS" << std::endl;
91 std::cout << " --mean" << std::endl;
92 std::cout << " Permits to set the mean of the input signal." << std::endl;
93 std::cout << std::endl;
94 std::cout << " --stdev" << std::endl;
95 std::cout << " Permits to set the standard deviation of the input signal." << std::endl;
96 std::cout << std::endl;
97 std::cout << " -v, --verbose" << std::endl;
98 std::cout << " Activate verbose mode." << std::endl;
99 std::cout << std::endl;
100 std::cout << " -h, --help" << std::endl;
101 std::cout << " Display the help." << std::endl;
102 std::cout << std::endl;
103}
104
105bool getOptions(int argc, const char **argv, float &opt_mean, float &opt_stdev, bool &opt_verbose)
106{
107 int i = 1;
108 while (i < argc) {
109 std::string argname(argv[i]);
110 if ((argname == "--mean") && ((i + 1) < argc)) {
111 opt_mean = static_cast<float>(std::atof(argv[i + 1]));
112 ++i;
113 }
114 else if ((argname == "--stdev") && ((i + 1) < argc)) {
115 opt_stdev = static_cast<float>(std::atof(argv[i + 1]));
116 ++i;
117 }
118 else if ((argname == "-v") || (argname == "--verbose")) {
119 opt_verbose = true;
120 }
121 else if ((argname == "-h") || (argname == "--help")) {
122 usage(argv[0]);
123 return false;
124 }
125 else if ((argname == "-c") || (argname == "-d")) {
126 // Arguments given by CTest by default, do nothing
127 }
128 else {
129 usage(argv[0]);
130 std::cerr << "Error: unrecognised argument \"" << argv[i] << "\"" << std::endl;
131 return false;
132 }
133 ++i;
134 }
135 return true;
136}
137
138int main(int argc, const char **argv)
139{
140 float opt_mean = 0.f;
141 float opt_stdev = 1.f;
142 bool opt_verbose = false;
143
144 bool isParsingOk = getOptions(argc, argv, opt_mean, opt_stdev, opt_verbose);
145 if (!isParsingOk) {
146 return EXIT_FAILURE;
147 }
148
149 bool success = true;
150
151 // vpStatisticalTestEWMA tests
152 {
153 if (opt_verbose) {
154 std::cout << "------ vpStatisticalTestEWMA tests ------" << std::endl;
155 }
156 const float alpha = 0.1f;
157 vpStatisticalTestEWMA tester(alpha);
158
159 // ---- Upward drift test ----
160 {
161 tester.init(alpha, opt_mean, opt_stdev);
162
163 // w(t = 1) >= mu + 3 sigma sqrt(alpha / (2 - alpha))
164 // <=> alpha s(t=1) + (1 - alpha) mu >= mu + 3 sigma sqrt(alpha / (2 - alpha))
165 // <=> s(t=1) >= (1 / alpha) (alpha mu + 3 sigma sqrt(alpha / (2 - alpha))
166 float signal = (1.f / alpha) * (alpha * opt_mean + 3.f * opt_stdev * std::sqrt(alpha / (2.f - alpha)));
167 signal += 0.5f; // To be sure we are greater than the threshold
170 success = false;
171 if (opt_verbose) {
172 std::cerr << "Upward drift test failed: " << std::endl;
173 std::cerr << "\tw(t) = " << tester.getWt() << std::endl;
174 float limitDown = 0.f, limitUp = 0.f;
175 tester.getLimits(limitDown, limitUp);
176 std::cerr << "\tlimit_up = " << limitUp << std::endl;
177 }
178 }
179 else if (opt_verbose) {
180 std::cout << "Upward drift test succeeded." << std::endl;
181 }
182 }
183
184 // ---- Downward drift test ----
185 {
186 tester.init(alpha, opt_mean, opt_stdev);
187 // w(t = 1) <= mu - 3 sigma sqrt(alpha / (2 - alpha))
188 // <=> alpha s(t=1) + (1 - alpha) mu <= mu - 3 sigma sqrt(alpha / (2 - alpha))
189 // <=> s(t=1) <= (1 / alpha) (alpha mu - 3 sigma sqrt(alpha / (2 - alpha))
190 float signal = (1.f / alpha) * (alpha * opt_mean - 3.f * opt_stdev * std::sqrt(alpha / (2.f - alpha)));
191 signal -= 0.5f; // To be sure we are greater than the threshold
194 success = false;
195 if (opt_verbose) {
196 std::cerr << "Downward drift test failed: " << std::endl;
197 std::cerr << "\tw(t) = " << tester.getWt() << std::endl;
198 float limitDown = 0.f, limitUp = 0.f;
199 tester.getLimits(limitDown, limitUp);
200 std::cerr << "\tlimit_down = " << limitDown << std::endl;
201 }
202 }
203 else if (opt_verbose) {
204 std::cout << "Downward drift test succeeded." << std::endl;
205 }
206 }
207 }
208
209 // vpStatisticalTestHinkley tests
210 {
211 if (opt_verbose) {
212 std::cout << "------ vpStatisticalTestHinkley tests ------" << std::endl;
213 }
214
215 const float h = 4.76f, k = 1.f;
216 vpStatisticalTestHinkley tester(h, k, opt_mean, opt_stdev);
217 const unsigned int HINKLEY_NB_DATA = 4;
218 const float HINKLEY_SAMPLE = 2.f * opt_stdev;
219
220 // Hinkley's test upward drift
221 {
222 const float HINKLEY_DATA[HINKLEY_NB_DATA] = { HINKLEY_SAMPLE, HINKLEY_SAMPLE, HINKLEY_SAMPLE, HINKLEY_SAMPLE };
224 bool isTestOk = true;
225 unsigned int id = 0;
227 while ((id < HINKLEY_NB_DATA) && isTestOk) {
228 drift = tester.testDownUpwardMeanDrift(HINKLEY_DATA[id]);
229 isTestOk = (drift == HINKLEY_EXPECTED_RES[id]);
230 if (isTestOk) {
231 ++id;
232 }
233 }
234 if (!isTestOk) {
235 success = false;
236 if (opt_verbose) {
237 std::cerr << "Upward drift test failed: " << std::endl;
238 float Tk = tester.getTk(), Nk = tester.getNk();
239 std::cerr << "T(k) = " << Tk << " | N(k) = " << Nk << " => S+(k) = " << Tk - Nk << std::endl;
240 float limitDown = 0.f, limitUp = 0.f;
241 tester.getLimits(limitDown, limitUp);
242 std::cerr << "lim_+ = " << limitUp << std::endl;
243 std::cerr << "drift type : " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl;
244 std::cerr << "expected drift type : " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(HINKLEY_EXPECTED_RES[id]) << std::endl;
245 }
246 }
247 else if (opt_verbose) {
248 std::cout << "Upward drift test succeeded." << std::endl;
249 }
250 }
251
252 // Hinkley's test downward drift
253 {
254 const float HINKLEY_DATA[HINKLEY_NB_DATA] = { -1.f * HINKLEY_SAMPLE, -1.f * HINKLEY_SAMPLE, -1.f * HINKLEY_SAMPLE, -1.f * HINKLEY_SAMPLE };
256 bool isTestOk = true;
257 unsigned int id = 0;
259 while ((id < HINKLEY_NB_DATA) && isTestOk) {
260 drift = tester.testDownUpwardMeanDrift(HINKLEY_DATA[id]);
261 isTestOk = (drift == HINKLEY_EXPECTED_RES[id]);
262 if (isTestOk) {
263 ++id;
264 }
265 }
266 if (!isTestOk) {
267 success = false;
268 if (opt_verbose) {
269 std::cerr << "Downward drift test failed: " << std::endl;
270 float Sk = tester.getSk(), Mk = tester.getMk();
271 std::cerr << "S(k) = " << Sk << " | M(k) = " << Mk << " => S+(k) = " << Mk - Sk << std::endl;
272 float limitDown = 0.f, limitUp = 0.f;
273 tester.getLimits(limitDown, limitUp);
274 std::cerr << "lim_- = " << limitDown << std::endl;
275 std::cerr << "drift type : " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl;
276 std::cerr << "expected drift type : " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(HINKLEY_EXPECTED_RES[id]) << std::endl;
277 }
278 }
279 else if (opt_verbose) {
280 std::cout << "Downward drift test succeeded." << std::endl;
281 }
282 }
283 }
284
285 // vpStatisticalTestMeanAdjustedCUSUM tests
286 {
287 if (opt_verbose) {
288 std::cout << "------ vpStatisticalTestMeanAdjustedCUSUM tests ------" << std::endl;
289 }
290
291 const float h = 4.76f, k = 1.f;
293 tester.init(h, k, opt_mean, opt_stdev);
294 const unsigned int CUSUM_NB_DATA = 4;
295 const float CUSUM_SAMPLE = 2.f * opt_stdev;
296
297 // Mean adjusted CUSUM test upward drift
298 {
299 const float CUSUM_DATA[CUSUM_NB_DATA] = { CUSUM_SAMPLE, CUSUM_SAMPLE, CUSUM_SAMPLE, CUSUM_SAMPLE };
301 bool isTestOk = true;
302 unsigned int id = 0;
304 while ((id < CUSUM_NB_DATA) && isTestOk) {
305 drift = tester.testDownUpwardMeanDrift(CUSUM_DATA[id]);
306 isTestOk = (drift == CUSUM_EXPECTED_RES[id]);
307 if (isTestOk) {
308 ++id;
309 }
310 }
311 if (!isTestOk) {
312 success = false;
313 if (opt_verbose) {
314 std::cerr << "Upward drift test failed: " << std::endl;
315 std::cerr << "\tS+(k) = " << tester.getTestSignalPlus() << std::endl;
316 float limitDown = 0.f, limitUp = 0.f;
317 tester.getLimits(limitDown, limitUp);
318 std::cerr << "\tlim_+ = " << limitUp << std::endl;
319 std::cerr << "\tdrift type : " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl;
320 std::cerr << "\texpected drift type : " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(CUSUM_EXPECTED_RES[id]) << std::endl;
321 }
322 }
323 else if (opt_verbose) {
324 std::cout << "Upward drift test succeeded." << std::endl;
325 }
326 }
327
328 // Mean adjusted CUSUM test upward drift
329 {
330 const float CUSUM_DATA[CUSUM_NB_DATA] = { -1.f * CUSUM_SAMPLE, -1.f * CUSUM_SAMPLE, -1.f * CUSUM_SAMPLE, -1.f * CUSUM_SAMPLE };
332 bool isTestOk = true;
333 unsigned int id = 0;
335 while ((id < CUSUM_NB_DATA) && isTestOk) {
336 drift = tester.testDownUpwardMeanDrift(CUSUM_DATA[id]);
337 isTestOk = (drift == CUSUM_EXPECTED_RES[id]);
338 if (isTestOk) {
339 ++id;
340 }
341 }
342 if (!isTestOk) {
343 success = false;
344 if (opt_verbose) {
345 std::cerr << "Downward drift test failed: " << std::endl;
346 std::cerr << "\tS-(k) = " << tester.getTestSignalMinus() << std::endl;
347 float limitDown = 0.f, limitUp = 0.f;
348 tester.getLimits(limitDown, limitUp);
349 std::cerr << "\tlim_- = " << limitDown << std::endl;
350 std::cerr << "\tdrift type : " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl;
351 std::cerr << "\texpected drift type : " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(CUSUM_EXPECTED_RES[id]) << std::endl;
352 }
353 }
354 else if (opt_verbose) {
355 std::cout << "Downward drift test succeeded." << std::endl;
356 }
357 }
358 }
359
360 // vpStatisticalTestShewhart tests
361 {
362 if (opt_verbose) {
363 std::cout << "------ vpStatisticalTestShewhart tests ------" << std::endl;
364 }
365 const bool activateWECOrules = true;
366 vpStatisticalTestShewhart tester(activateWECOrules, vpStatisticalTestShewhart::CONST_ALL_WECO_ACTIVATED, opt_mean, opt_stdev);
367
368 // Upward drift test
369 {
370 if (opt_verbose) {
371 std::cout << "Upward drift tests" << std::endl;
372 }
373
374 // 3-sigma test
375 {
376 bool isInitOK = initializeShewhartTest(opt_mean, opt_stdev, opt_verbose, "3-sigma", tester);
377 if (!isInitOK) {
378 success = false;
379 }
380 else {
381 const float signal = 3.5f * opt_stdev;
386 if ((drift != EXPECTED_DRIFT) || (alarm != EXPECTED_ALARM)) {
387 success = false;
388 if (opt_verbose) {
389 std::cerr << "\t3-sigma test failed: " << std::endl;
390 std::vector<float> s = tester.getSignals();
391 std::cerr << "\t\ts(t) = [ ";
392 for (size_t i = 0; i < s.size(); ++i) {
393 std::cerr << s[i] << " ";
394 }
395 std::cerr << "]" << std::endl;
396 float limitDown = 0.f, limitUp = 0.f;
397 tester.getLimits(limitDown, limitUp);
398 std::cerr << "\t\tlim_+ = " << limitUp << std::endl;
399 std::cerr << "\t\tdetected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl;
400 std::cerr << "\t\texpected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(EXPECTED_DRIFT) << std::endl;
401 std::cerr << "\t\tdetected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(alarm) << std::endl;
402 std::cerr << "\t\texpected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(EXPECTED_ALARM) << std::endl;
403 }
404 }
405 else if (opt_verbose) {
406 std::cout << "\t3-sigma test succeeded " << std::endl;
407 }
408 }
409 }
410
411 // 2-sigma test
412 {
413 bool isInitOK = initializeShewhartTest(opt_mean, opt_stdev, opt_verbose, "2-sigma", tester);
414 if (!isInitOK) {
415 success = false;
416 }
417 else {
418 const unsigned int NB_SAMPLES = 3;
419 const float DATA[NB_SAMPLES] = { 2.75f * opt_stdev, 1.5f * opt_stdev, 2.5f * opt_stdev };
424 unsigned int i = 0;
425 bool isTestOk = true;
426 while ((i < NB_SAMPLES) && isTestOk) {
427 drift = tester.testDownUpwardMeanDrift(DATA[i]);
428 alarm = tester.getAlarm();
429 isTestOk = ((drift == EXPECTED_DRIFT[i]) && (alarm == EXPECTED_ALARM[i]));
430 if (isTestOk) {
431 ++i;
432 }
433 }
434
435 if (!isTestOk) {
436 success = false;
437 if (opt_verbose) {
438 std::cerr << "\t2-sigma test failed: " << std::endl;
439 std::vector<float> s = tester.getSignals();
440 std::cerr << "\t\ts(t) = [ ";
441 for (size_t j = 0; j < s.size(); ++j) {
442 std::cerr << s[j] << " ";
443 }
444 std::cerr << "]" << std::endl;
445 float limitDown = 0.f, limitUp = 0.f;
446 tester.getLimits(limitDown, limitUp);
447 std::cerr << "\t\tlim_+ = " << limitUp << std::endl;
448 std::cerr << "\t\tdetected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl;
449 std::cerr << "\t\texpected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(EXPECTED_DRIFT[i]) << std::endl;
450 std::cerr << "\t\tdetected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(alarm) << std::endl;
451 std::cerr << "\t\texpected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(EXPECTED_ALARM[i]) << std::endl;
452 }
453 }
454 else if (opt_verbose) {
455 std::cout << "\t2-sigma test succeeded " << std::endl;
456 }
457 }
458 }
459
460 // 1-sigma test
461 {
462 bool isInitOK = initializeShewhartTest(opt_mean, opt_stdev, opt_verbose, "1-sigma", tester);
463 if (!isInitOK) {
464 success = false;
465 }
466 else {
467 const unsigned int NB_SAMPLES = 5;
468 const float DATA[NB_SAMPLES] = { 2.75f * opt_stdev, 1.5f * opt_stdev, 0.5f * opt_stdev, 1.5f * opt_stdev, 2.5f * opt_stdev };
473 unsigned int i = 0;
474 bool isTestOk = true;
475 while ((i < NB_SAMPLES) && isTestOk) {
476 drift = tester.testDownUpwardMeanDrift(DATA[i]);
477 alarm = tester.getAlarm();
478 isTestOk = ((drift == EXPECTED_DRIFT[i]) && (alarm == EXPECTED_ALARM[i]));
479 if (isTestOk) {
480 ++i;
481 }
482 }
483
484 if (!isTestOk) {
485 success = false;
486 if (opt_verbose) {
487 std::cerr << "\t1-sigma test failed: " << std::endl;
488 std::vector<float> s = tester.getSignals();
489 std::cerr << "\t\ts(t) = [ ";
490 for (size_t j = 0; j < s.size(); ++j) {
491 std::cerr << s[j] << " ";
492 }
493 std::cerr << "]" << std::endl;
494 float limitDown = 0.f, limitUp = 0.f;
495 tester.getLimits(limitDown, limitUp);
496 std::cerr << "\t\tlim_+ = " << limitUp << std::endl;
497 std::cerr << "\t\tdetected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl;
498 std::cerr << "\t\texpected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(EXPECTED_DRIFT[i]) << std::endl;
499 std::cerr << "\t\tdetected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(alarm) << std::endl;
500 std::cerr << "\t\texpected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(EXPECTED_ALARM[i]) << std::endl;
501 }
502 }
503 else if (opt_verbose) {
504 std::cout << "\t1-sigma test succeeded " << std::endl;
505 }
506 }
507 }
508
509 // Same-side test
510 {
511 bool isInitOK = initializeShewhartTest(opt_mean, opt_stdev, opt_verbose, "Same-side", tester);
512 if (!isInitOK) {
513 success = false;
514 }
515 else {
516 const unsigned int NB_SAMPLES = 8;
517 const float DATA[NB_SAMPLES] = { 2.75f * opt_stdev, 0.5f * opt_stdev, 1.5f * opt_stdev, 0.5f * opt_stdev, 2.75f * opt_stdev, 0.5f * opt_stdev, 1.5f * opt_stdev, 0.5f * opt_stdev };
522 unsigned int i = 0;
523 bool isTestOk = true;
524 while ((i < NB_SAMPLES) && isTestOk) {
525 drift = tester.testDownUpwardMeanDrift(DATA[i]);
526 alarm = tester.getAlarm();
527 isTestOk = ((drift == EXPECTED_DRIFT[i]) && (alarm == EXPECTED_ALARM[i]));
528 if (isTestOk) {
529 ++i;
530 }
531 }
532
533 if (!isTestOk) {
534 success = false;
535 if (opt_verbose) {
536 std::cerr << "\tSame-side test failed: " << std::endl;
537 std::vector<float> s = tester.getSignals();
538 std::cerr << "\t\ts(t) = [ ";
539 for (size_t j = 0; j < s.size(); ++j) {
540 std::cerr << s[j] << " ";
541 }
542 std::cerr << "]" << std::endl;
543 float limitDown = 0.f, limitUp = 0.f;
544 tester.getLimits(limitDown, limitUp);
545 std::cerr << "\t\tlim_+ = " << limitUp << std::endl;
546 std::cerr << "\t\tdetected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl;
547 std::cerr << "\t\texpected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(EXPECTED_DRIFT[i]) << std::endl;
548 std::cerr << "\t\tdetected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(alarm) << std::endl;
549 std::cerr << "\t\texpected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(EXPECTED_ALARM[i]) << std::endl;
550 }
551 }
552 else if (opt_verbose) {
553 std::cout << "\tSame-side test succeeded " << std::endl;
554 }
555 }
556 }
557 }
558
559 // Downward drift test
560 {
561 if (opt_verbose) {
562 std::cout << "Downward drift tests" << std::endl;
563 }
564
565 // 3-sigma test
566 {
567 bool isInitOK = initializeShewhartTest(opt_mean, opt_stdev, opt_verbose, "3-sigma", tester);
568 if (!isInitOK) {
569 success = false;
570 }
571 else {
572 const float signal = -3.5f * opt_stdev;
577 if ((drift != EXPECTED_DRIFT) || (alarm != EXPECTED_ALARM)) {
578 success = false;
579 if (opt_verbose) {
580 std::cerr << "\t3-sigma test failed: " << std::endl;
581 std::vector<float> s = tester.getSignals();
582 std::cerr << "\t\ts(t) = [ ";
583 for (size_t j = 0; j < s.size(); ++j) {
584 std::cerr << s[j] << " ";
585 }
586 std::cerr << "]" << std::endl;
587 float limitDown = 0.f, limitUp = 0.f;
588 tester.getLimits(limitDown, limitUp);
589 std::cerr << "\t\tlim_- = " << limitDown << std::endl;
590 std::cerr << "\t\tlim_+ = " << limitUp << std::endl;
591 std::cerr << "\t\tdetected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl;
592 std::cerr << "\t\texpected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(EXPECTED_DRIFT) << std::endl;
593 std::cerr << "\t\tdetected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(alarm) << std::endl;
594 std::cerr << "\t\texpected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(EXPECTED_ALARM) << std::endl;
595 }
596 }
597 else if (opt_verbose) {
598 std::cout << "\t3-sigma test succeeded " << std::endl;
599 }
600 }
601 }
602
603 // 2-sigma test
604 {
605 bool isInitOK = initializeShewhartTest(opt_mean, opt_stdev, opt_verbose, "2-sigma", tester);
606 if (!isInitOK) {
607 success = false;
608 }
609 else {
610 const unsigned int NB_SAMPLES = 3;
611 const float DATA[NB_SAMPLES] = { -2.75f * opt_stdev, -1.5f * opt_stdev, -2.5f * opt_stdev };
616 unsigned int i = 0;
617 bool isTestOk = true;
618 while ((i < NB_SAMPLES) && isTestOk) {
619 drift = tester.testDownUpwardMeanDrift(DATA[i]);
620 alarm = tester.getAlarm();
621 isTestOk = ((drift == EXPECTED_DRIFT[i]) && (alarm == EXPECTED_ALARM[i]));
622 if (isTestOk) {
623 ++i;
624 }
625 }
626
627 if (!isTestOk) {
628 success = false;
629 if (opt_verbose) {
630 std::cerr << "\t2-sigma test failed: " << std::endl;
631 std::vector<float> s = tester.getSignals();
632 std::cerr << "\t\ts(t) = [ ";
633 for (size_t j = 0; j < s.size(); ++j) {
634 std::cerr << s[j] << " ";
635 }
636 std::cerr << "]" << std::endl;
637 float limitDown = 0.f, limitUp = 0.f;
638 tester.getLimits(limitDown, limitUp);
639 std::cerr << "\t\tlim_- = " << limitDown << std::endl;
640 std::cerr << "\t\tlim_+ = " << limitUp << std::endl;
641 std::cerr << "\t\tdetected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl;
642 std::cerr << "\t\texpected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(EXPECTED_DRIFT[i]) << std::endl;
643 std::cerr << "\t\tdetected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(alarm) << std::endl;
644 std::cerr << "\t\texpected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(EXPECTED_ALARM[i]) << std::endl;
645 }
646 }
647 else if (opt_verbose) {
648 std::cout << "\t2-sigma test succeeded " << std::endl;
649 }
650 }
651 }
652
653 // 1-sigma test
654 {
655 bool isInitOK = initializeShewhartTest(opt_mean, opt_stdev, opt_verbose, "1-sigma", tester);
656 if (!isInitOK) {
657 success = false;
658 }
659 else {
660 const unsigned int NB_SAMPLES = 5;
661 const float DATA[NB_SAMPLES] = { -2.75f * opt_stdev, -1.5f * opt_stdev, 1.5f * opt_stdev, -1.5f * opt_stdev, -2.5f * opt_stdev };
666 unsigned int i = 0;
667 bool isTestOk = true;
668 while ((i < NB_SAMPLES) && isTestOk) {
669 drift = tester.testDownUpwardMeanDrift(DATA[i]);
670 alarm = tester.getAlarm();
671 isTestOk = ((drift == EXPECTED_DRIFT[i]) && (alarm == EXPECTED_ALARM[i]));
672 if (isTestOk) {
673 ++i;
674 }
675 }
676
677 if (!isTestOk) {
678 success = false;
679 if (opt_verbose) {
680 std::cerr << "\t1-sigma test failed: " << std::endl;
681 std::vector<float> s = tester.getSignals();
682 std::cerr << "\t\ts(t) = [ ";
683 for (size_t j = 0; j < s.size(); ++j) {
684 std::cerr << s[j] << " ";
685 }
686 std::cerr << "]" << std::endl;
687 float limitDown = 0.f, limitUp = 0.f;
688 tester.getLimits(limitDown, limitUp);
689 std::cerr << "\t\tlim_- = " << limitDown << std::endl;
690 std::cerr << "\t\tlim_+ = " << limitUp << std::endl;
691 std::cerr << "\t\tdetected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl;
692 std::cerr << "\t\texpected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(EXPECTED_DRIFT[i]) << std::endl;
693 std::cerr << "\t\tdetected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(alarm) << std::endl;
694 std::cerr << "\t\texpected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(EXPECTED_ALARM[i]) << std::endl;
695 }
696 }
697 else if (opt_verbose) {
698 std::cout << "\t1-sigma test succeeded " << std::endl;
699 }
700 }
701 }
702
703 // Same-side test
704 {
705 bool isInitOK = initializeShewhartTest(opt_mean, opt_stdev, opt_verbose, "Same-side", tester);
706 if (!isInitOK) {
707 success = false;
708 }
709 else {
710 const unsigned int NB_SAMPLES = 8;
711 const float DATA[NB_SAMPLES] = { -2.75f * opt_stdev, -0.5f * opt_stdev, -1.5f * opt_stdev, -0.5f * opt_stdev, -2.75f * opt_stdev, -0.5f * opt_stdev, -1.5f * opt_stdev, -0.5f * opt_stdev };
716 unsigned int i = 0;
717 bool isTestOk = true;
718 while ((i < NB_SAMPLES) && isTestOk) {
719 drift = tester.testDownUpwardMeanDrift(DATA[i]);
720 alarm = tester.getAlarm();
721 isTestOk = ((drift == EXPECTED_DRIFT[i]) && (alarm == EXPECTED_ALARM[i]));
722 if (isTestOk) {
723 ++i;
724 }
725 }
726
727 if (!isTestOk) {
728 success = false;
729 if (opt_verbose) {
730 std::cerr << "\tSame-side test failed: " << std::endl;
731 std::vector<float> s = tester.getSignals();
732 std::cerr << "\t\ts(t) = [ ";
733 for (size_t j = 0; j < s.size(); ++j) {
734 std::cerr << s[j] << " ";
735 }
736 std::cerr << "]" << std::endl;
737 float limitDown = 0.f, limitUp = 0.f;
738 tester.getLimits(limitDown, limitUp);
739 std::cerr << "\t\tlim_+ = " << limitUp << std::endl;
740 std::cerr << "\t\tlim_- = " << limitDown << std::endl;
741 std::cerr << "\t\tdetected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl;
742 std::cerr << "\t\texpected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(EXPECTED_DRIFT[i]) << std::endl;
743 std::cerr << "\t\tdetected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(alarm) << std::endl;
744 std::cerr << "\t\texpected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(EXPECTED_ALARM[i]) << std::endl;
745 }
746 }
747 else if (opt_verbose) {
748 std::cout << "\tSame-side test succeeded " << std::endl;
749 }
750 }
751 }
752 }
753 }
754
755 // vpStatisticalTestSigma tests
756 {
757 if (opt_verbose) {
758 std::cout << "------ vpStatisticalTestSigma tests ------" << std::endl;
759 }
760 const float h = 3.f;
761 vpStatisticalTestSigma tester(h, opt_mean, opt_stdev);
762
763 // Upward drift test
764 {
765 const float signal = 3.5f * opt_stdev;
768 if (drift != EXPECTED_DRIFT) {
769 success = false;
770 if (opt_verbose) {
771 std::cerr << "Upward drift test failed: " << std::endl;
772 std::cerr << "\ts(t) = " << tester.getSignal() << std::endl;
773 float limitDown = 0.f, limitUp = 0.f;
774 tester.getLimits(limitDown, limitUp);
775 std::cerr << "\tlim_+ = " << limitUp << std::endl;
776 std::cerr << "\tdetected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl;
777 std::cerr << "\texpected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(EXPECTED_DRIFT) << std::endl;
778 }
779 }
780 else if (opt_verbose) {
781 std::cout << "Upward drift test succeeded " << std::endl;
782 }
783 }
784
785 // Downward drift test
786 {
787 const float signal = -3.5f * opt_stdev;
790 if (drift != EXPECTED_DRIFT) {
791 success = false;
792 if (opt_verbose) {
793 std::cerr << "Downward drift test failed: " << std::endl;
794 std::cerr << "\ts(t) = " << tester.getSignal() << std::endl;
795 float limitDown = 0.f, limitUp = 0.f;
796 tester.getLimits(limitDown, limitUp);
797 std::cerr << "\tlim_- = " << limitDown << std::endl;
798 std::cerr << "\tdetected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl;
799 std::cerr << "\texpected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(EXPECTED_DRIFT) << std::endl;
800 }
801 }
802 else if (opt_verbose) {
803 std::cout << "Downward drift test succeeded " << std::endl;
804 }
805 }
806 }
807
808 if (success) {
809 std::cout << "Test succeed" << std::endl;
810 }
811 else {
812 std::cout << "Test failed" << std::endl;
813 return EXIT_FAILURE;
814 }
815 return EXIT_SUCCESS;
816}
static std::string vpMeanDriftTypeToString(const vpMeanDriftType &type)
Cast a vpMeanDriftType into a string.
vpMeanDriftType
Enum that indicates if a drift of the mean occurred.
void getLimits(float &limitDown, float &limitUp) const
Get the upper and lower limits of the test signal.
vpMeanDriftType testDownUpwardMeanDrift(const float &signal)
Test if a downward or an upward mean drift occurred according to the new value of the signal.
Class that permits to perform Exponentially Weighted Moving Average mean drft tests.
This class implements the Hinkley's cumulative sum test.
Class that permits to perform a mean adjusted Cumulative Sum test.
Class that permits a Shewhart's test.
void init(const bool &activateWECOrules, const std::vector< bool > &activatedRules=CONST_ALL_WECO_ACTIVATED, const unsigned int &nbSamplesForStats=30)
(Re)Initialize the test.
static const unsigned int NB_DATA_SIGNAL
static VP_ATTRIBUTE_NO_DESTROY const std::vector< bool > CONST_ALL_WECO_ACTIVATED
vpWecoRulesAlarm getAlarm() const
Get the alarm raised by the last test due to the WECO's rules.
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 float getSignal() const override
Get the last value of the 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.