From 09b861bd89ac525779c9f03be5e94a1911020d48 Mon Sep 17 00:00:00 2001 From: rlagneau Date: Fri, 1 Mar 2024 15:13:23 +0100 Subject: [PATCH 01/12] [CORPS] Added new classes for detection of mean drift --- modules/core/include/visp3/core/vpHinkley.h | 8 +- .../visp3/core/vpStatisticalTestAbstract.h | 235 +++++++++++ .../visp3/core/vpStatisticalTestEWMA.h | 152 +++++++ .../visp3/core/vpStatisticalTestHinkley.h | 270 +++++++++++++ .../core/vpStatisticalTestMeanAdjustedCUSUM.h | 231 +++++++++++ .../visp3/core/vpStatisticalTestSigma.h | 142 +++++++ modules/core/src/math/misc/vpHinkley.cpp | 19 +- .../math/misc/vpStatisticalTestAbstract.cpp | 210 ++++++++++ .../src/math/misc/vpStatisticalTestEWMA.cpp | 129 ++++++ .../math/misc/vpStatisticalTestHinkley.cpp | 189 +++++++++ .../vpStatisticalTestMeanAdjustedCUSUM.cpp | 156 ++++++++ .../src/math/misc/vpStatisticalTestSigma.cpp | 107 +++++ tutorial/CMakeLists.txt | 1 + tutorial/mean-drift/CMakeLists.txt | 16 + tutorial/mean-drift/tutorial-meandrift.cpp | 371 ++++++++++++++++++ 15 files changed, 2225 insertions(+), 11 deletions(-) create mode 100644 modules/core/include/visp3/core/vpStatisticalTestAbstract.h create mode 100644 modules/core/include/visp3/core/vpStatisticalTestEWMA.h create mode 100644 modules/core/include/visp3/core/vpStatisticalTestHinkley.h create mode 100644 modules/core/include/visp3/core/vpStatisticalTestMeanAdjustedCUSUM.h create mode 100644 modules/core/include/visp3/core/vpStatisticalTestSigma.h create mode 100644 modules/core/src/math/misc/vpStatisticalTestAbstract.cpp create mode 100644 modules/core/src/math/misc/vpStatisticalTestEWMA.cpp create mode 100644 modules/core/src/math/misc/vpStatisticalTestHinkley.cpp create mode 100644 modules/core/src/math/misc/vpStatisticalTestMeanAdjustedCUSUM.cpp create mode 100644 modules/core/src/math/misc/vpStatisticalTestSigma.cpp create mode 100644 tutorial/mean-drift/CMakeLists.txt create mode 100644 tutorial/mean-drift/tutorial-meandrift.cpp diff --git a/modules/core/include/visp3/core/vpHinkley.h b/modules/core/include/visp3/core/vpHinkley.h index d24760c2d6..6d9ee47e07 100644 --- a/modules/core/include/visp3/core/vpHinkley.h +++ b/modules/core/include/visp3/core/vpHinkley.h @@ -40,6 +40,7 @@ */ #include +#if defined(VISP_BUILD_DEPRECATED_FUNCTIONS) /*! \class vpHinkley @@ -88,13 +89,14 @@ N_{k^{'}} = 0 \f$. */ -class VISP_EXPORT vpHinkley +class vp_deprecated vpHinkley { public: /*! \enum vpHinkleyJumpType Indicates if a jump is detected by the Hinkley test. */ - typedef enum { + typedef enum + { noJump, /*!< No jump is detected by the Hinkley test. */ downwardJump, /*!< A downward jump is detected by the Hinkley test. */ upwardJump /*!< An upward jump is detected by the Hinkley test. */ @@ -162,5 +164,5 @@ class VISP_EXPORT vpHinkley double Tk; double Nk; }; - +#endif #endif diff --git a/modules/core/include/visp3/core/vpStatisticalTestAbstract.h b/modules/core/include/visp3/core/vpStatisticalTestAbstract.h new file mode 100644 index 0000000000..a365125c71 --- /dev/null +++ b/modules/core/include/visp3/core/vpStatisticalTestAbstract.h @@ -0,0 +1,235 @@ +/**************************************************************************** + * + * ViSP, open source Visual Servoing Platform software. + * Copyright (C) 2005 - 2023 by Inria. All rights reserved. + * + * This software is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * See the file LICENSE.txt at the root directory of this source + * distribution for additional information about the GNU GPL. + * + * For using ViSP with software that can not be combined with the GNU + * GPL, please contact Inria about acquiring a ViSP Professional + * Edition License. + * + * See https://visp.inria.fr for more information. + * + * This software was developed at: + * Inria Rennes - Bretagne Atlantique + * Campus Universitaire de Beaulieu + * 35042 Rennes Cedex + * France + * + * If you have questions regarding the use of this file, please contact + * Inria at visp@inria.fr + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * +*****************************************************************************/ + +#ifndef _vpStatisticalTestAbstract_h_ +#define _vpStatisticalTestAbstract_h_ + + +#include +#include +#include + +#include + +/** + * \ingroup group_core_math_tools + * \brief Base class for methods detecting the drift of the mean of a process. + */ +class VISP_EXPORT vpStatisticalTestAbstract +{ +public: + /** + * \brief Enum that indicates if a drift of the mean occured. + */ + typedef enum vpMeanDriftType + { + NO_MEAN_DRIFT = 0, /*!< No mean drift occured*/ + MEAN_DRIFT_DOWNWARD = 1, /*!< A downward drift of the mean occured.*/ + MEAN_DRIFT_UPWARD = 2 /*!< An upward drift of the mean occured.*/ + } vpMeanDriftType; + + /** + * \brief Cast a \b vpMeanDriftType into a string. + * + * \param[in] type The type of mean drift. + * \return std::string The corresponding message. + */ + static std::string vpMeanDriftTypeToString(const vpMeanDriftType &type); + + /** + * \brief Print the message corresponding to the type of mean drift. + * + * \param[in] type The type of mean drift. + */ + static void print(const vpMeanDriftType &type); + +protected: + bool m_areStatisticsComputed; /*!< Set to true once the mean and the standard deviation are available.*/ + float m_count; /*!< Current number of data used to compute the mean and the standard deviation.*/ + float m_limitDown; /*!< Upper limit for the test signal m_wt.*/ + float m_limitUp; /*!< Lower limit for the test signal m_wt*/ + float m_mean; /*!< Mean of the monitored signal.*/ + unsigned int m_nbSamplesForStatistics; /*!< Number of samples to use to compute the mean and the standard deviation.*/ + float *m_s; /*!< Array that keeps the samples used to compute the mean and standard deviation.*/ + float m_stdev; /*!< Standard deviation of the monitored signal.*/ + float m_stdevmin; /*!< Minimum allowed standard deviation of the monitored signal.*/ + float m_sumForMean; /*!< Sum of the samples used to compute the mean and standard deviation.*/ + + /** + * \brief Detects if a downward mean drift occured. + * + * \return \b vpMeanDriftType::MEAN_DRIFT_DOWNWARD if a downward mean drift occured, \b vpMeanDriftType::NO_MEAN_DRIFT otherwise. + * + * \sa detectUpwardMeanShift() + */ + virtual vpMeanDriftType detectDownwardMeanShift() = 0; + + /** + * \brief Detects if a upward mean drift occured. + * + * \return \b vpMeanDriftType::MEAN_DRIFT_UPWARD if an upward mean drift occured, \b vpMeanDriftType::NO_MEAN_DRIFT otherwise. + * + * \sa detectDownwardMeanShift() + */ + virtual vpMeanDriftType detectUpwardMeanShift() = 0; + + /** + * \brief Update \b m_s and if enough values are available, compute the mean, the standard + * deviation and the limits. + * + * \param[in] signal The new value of the signal to monitor. + * + * \return true if the statistics have been computed, false if data are missing. + */ + virtual bool updateStatistics(const float &signal); + + /** + * \brief Update the test signals. + * + * \param[in] signal The new value of the signal to monitor. + */ + virtual void updateTestSignals(const float &signal) = 0; +public: + /** + * \brief Construct a new vpStatisticalTestAbstract object. + */ + vpStatisticalTestAbstract(); + + /** + * \brief Construct by copy a new vpStatisticalTestAbstract object. + */ + vpStatisticalTestAbstract(const vpStatisticalTestAbstract &other); + + /** + * \brief Destroy the vpStatisticalTestAbstract object. + */ + virtual ~vpStatisticalTestAbstract(); + + /** + * \brief Get the upper and lower limits of the test signal. + * + * \param[out] limitDown The lower limit. + * \param[out] limitUp The upper limit. + */ + inline void getLimits(float &limitDown, float &limitUp) const + { + limitDown = m_limitDown; + limitUp = m_limitUp; + } + + /** + * \brief Get the mean used as reference. + * + * \return float The mean. + */ + inline float getMean() const + { + return m_mean; + } + + /** + * \brief Get the standard deviation used as reference. + * + * \return float The standard deviation. + */ + inline float getStdev() const + { + return m_stdev; + } + + /** + * \brief (Re)Initialize the algorithm. + */ + void init(); + + /** + * \brief Copy operator of a vpStatisticalTestAbstract. + * + * \param[in] other The vpStatisticalTestAbstract to copy. + * \return vpStatisticalTestAbstract& *this after copy. + */ + vpStatisticalTestAbstract &operator=(const vpStatisticalTestAbstract &other); + + /** + * \brief Set the minimum value of the standard deviation that is expected. + * The computed standard deviation cannot be lower this value if set. + * + * \param[in] stdevmin The minimum value of the standard deviation that is expected. + */ + void setMinStdev(const float &stdevmin) + { + m_stdevmin = stdevmin; + } + + /** + * \brief Set the number of samples required to compute the mean and standard deviation + * of the signal and allocate the memory accordingly. + * + * \param[in] nbSamples The number of samples we want to use. + */ + void setNbSamplesForStat(const unsigned int &nbSamples); + + /** + * \brief Test if a downward or an upward mean drift occured + * according to the new value of the signal. + * + * \param[in] signal The new value of the signal. + * \return vpMeanDriftType The type of mean drift that occured. + * + * \sa testDownwardMeanShift() testUpwardMeanShift() + */ + vpMeanDriftType testDownUpwardMeanShift(const float &signal); + + /** + * \brief Test if a downward mean drift occured + * according to the new value of the signal. + * + * \param[in] signal The new value of the signal. + * \return vpMeanDriftType The type of mean drift that occured. + * + * \sa testUpwardMeanShift() + */ + vpMeanDriftType testDownwardMeanShift(const float &signal); + + /** + * \brief Test if an upward mean drift occured + * according to the new value of the signal. + * + * \param[in] signal The new value of the signal. + * \return vpMeanDriftType The type of mean drift that occured. + * + * \sa testDownwardMeanShift() + */ + vpMeanDriftType testUpwardMeanShift(const float &signal); +}; + +#endif diff --git a/modules/core/include/visp3/core/vpStatisticalTestEWMA.h b/modules/core/include/visp3/core/vpStatisticalTestEWMA.h new file mode 100644 index 0000000000..3bfa0346bf --- /dev/null +++ b/modules/core/include/visp3/core/vpStatisticalTestEWMA.h @@ -0,0 +1,152 @@ +/**************************************************************************** + * + * ViSP, open source Visual Servoing Platform software. + * Copyright (C) 2005 - 2023 by Inria. All rights reserved. + * + * This software is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * See the file LICENSE.txt at the root directory of this source + * distribution for additional information about the GNU GPL. + * + * For using ViSP with software that can not be combined with the GNU + * GPL, please contact Inria about acquiring a ViSP Professional + * Edition License. + * + * See https://visp.inria.fr for more information. + * + * This software was developed at: + * Inria Rennes - Bretagne Atlantique + * Campus Universitaire de Beaulieu + * 35042 Rennes Cedex + * France + * + * If you have questions regarding the use of this file, please contact + * Inria at visp@inria.fr + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * +*****************************************************************************/ + +#ifndef _vpStatisticalTestEWMA_h_ +#define _vpStatisticalTestEWMA_h_ + +#include + +#include + +/** + * \ingroup group_core_math_tools + * \brief Class that permits to perform Exponentially Weighted Moving Average mean shift tests. + */ +class VISP_EXPORT vpStatisticalTestEWMA : public vpStatisticalTestAbstract +{ +protected: + float m_alpha; /*!< Forgetting factor: the higher, the more weight the current signal value has.*/ + float m_wt; /*!< Test signal such as m_wt = m_alpha * y(t) + ( 1 - m_alpha ) * m_wtprev .*/ + float m_wtprev; /*!< Previous value of the test signal.*/ + + /** + * \brief Compute the upper and lower limits of the test signal. + */ + virtual void computeDeltaAndLimits(); + + /** + * \brief Detects if a downward jump occured on the mean. + * + * \return downwardJump if a downward jump occured, noJump otherwise. + */ +#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) + virtual vpMeanDriftType detectDownwardMeanShift() override; +#else + virtual vpMeanDriftType detectDownwardMeanShift(); +#endif + +/** + * \brief Detects if a upward jump occured on the mean. + * + * \return upwardJump if a upward jump occured, noJump otherwise. + */ +#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) + virtual vpMeanDriftType detectUpwardMeanShift() override; +#else + virtual vpMeanDriftType detectUpwardMeanShift(); +#endif + + /** + * \brief Update m_s and if enough values are available, compute the mean, the standard + * deviation and the limits. + * + * \param[in] signal The new value of the signal to monitor. + */ +#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) + virtual bool updateStatistics(const float &signal) override; +#else + virtual bool updateStatistics(const float &signal); +#endif + + /** + * \brief Update the test signals. + * + * \param[in] signal The new value of the signal to monitor. + */ +#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) + virtual void updateTestSignals(const float &signal) override; +#else + virtual void updateTestSignals(const float &signal); +#endif + +public: + /** + * \brief Construct a new vpStatisticalTestEWMA object. + * + * \param[in] alpha The forgetting factor. + */ + vpStatisticalTestEWMA(const float &alpha = 0.1f); + + /** + * \brief Get the forgetting factor of the algorithm. + * + * \return float The forgetting factor. + */ + inline float getAlpha() const + { + return m_alpha; + } + + /** + * \brief Get the current value of the test signal. + * + * \return float The current value of the test signal. + */ + inline float getWt() const + { + return m_wt; + } + + /** + * \brief Initialize the EWMA algorithm. + * + * \param[in] alpha The forgetting factor. + */ + void init(const float &alpha); + + /** + * \brief Initialize the EWMA algorithm. + * + * \param[in] alpha The forgetting factor. + * \param[in] mean The expected mean of the signal to monitor. + * \param[in] stdev The expected standard deviation of the signal to monitor. + */ + void init(const float &alpha, const float &mean, const float &stdev); + + /** + * \brief Set the forgetting factor. + * + * \param[in] alpha The forgetting factor. + */ + void setAlpha(const float &alpha); +}; +#endif diff --git a/modules/core/include/visp3/core/vpStatisticalTestHinkley.h b/modules/core/include/visp3/core/vpStatisticalTestHinkley.h new file mode 100644 index 0000000000..0b34bee22b --- /dev/null +++ b/modules/core/include/visp3/core/vpStatisticalTestHinkley.h @@ -0,0 +1,270 @@ +/**************************************************************************** + * + * ViSP, open source Visual Servoing Platform software. + * Copyright (C) 2005 - 2023 by Inria. All rights reserved. + * + * This software is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * See the file LICENSE.txt at the root directory of this source + * distribution for additional information about the GNU GPL. + * + * For using ViSP with software that can not be combined with the GNU + * GPL, please contact Inria about acquiring a ViSP Professional + * Edition License. + * + * See https://visp.inria.fr for more information. + * + * This software was developed at: + * Inria Rennes - Bretagne Atlantique + * Campus Universitaire de Beaulieu + * 35042 Rennes Cedex + * France + * + * If you have questions regarding the use of this file, please contact + * Inria at visp@inria.fr + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * +*****************************************************************************/ + +#ifndef _vpStatisticalTestHinkley_h_ +#define _vpStatisticalTestHinkley_h_ + +#include + +#include + +/** + * \ingroup group_core_math_tools + * \brief This class implements the Hinkley's cumulative sum test. + * + * The Hinkley's cumulative sum test is designed to detect drift in the mean + of an observed signal \f$ s(t) \f$. It is known to be robust (by + taking into account all the past of the observed quantity), + efficient, and inducing a very low computational load. The other + attractive features of this test are two-fold. First, it can + straightforwardly and accurately provide the drift instant. Secondly, + due to its formulation (cumulative sum test), it can simultaneously + handle both very abrupt and important changes, and gradual smaller + ones without adapting the involved thresholds. + + Two tests are performed in parallel to look for downwards or upwards + drifts in \f$ s(t) \f$, respectively defined by: + + \f[ S_k = \sum_{t=0}^{k} (s(t) - m_0 + \frac{\delta}{2}) \f] + \f[ M_k = \max_{0 \leq i \leq k} S_i\f] + \f[ T_k = \sum_{t=0}^{k} (s(t) - m_0 - \frac{\delta}{2}) \f] + \f[ N_k = \min_{0 \leq i \leq k} T_i\f] + + In which \f$m_o\f$ is computed on-line and corresponds to the mean + of the signal \f$ s(t) \f$ we want to detect a drift. \f$m_o\f$ is + re-initialized at zero after each drift detection. \f$\delta\f$ + denotes the drift minimal magnitude that we want to detect and + \f$\alpha\f$ is a predefined threshold. These values are set by + default to 0.2 in the default constructor vpHinkley(). To modify the + default values use setAlpha() and setDelta() or the + vpHinkley(double alpha, double delta) constructor. + + A downward drift is detected if \f$ M_k - S_k > \alpha \f$. + A upward drift is detected if \f$ T_k - N_k > \alpha \f$. + + To detect only downward drifts in \f$ s(t) \f$ use + testDownwardJump().To detect only upward drifts in \f$ s(t) \f$ use + testUpwardJump(). To detect both, downward and upward drifts use + testDownUpwardJump(). + + If a drift is detected, the drift location is given by the last instant + \f$k^{'}\f$ when \f$ M_{k^{'}} - S_{k^{'}} = 0 \f$, or \f$ T_{k^{'}} - + N_{k^{'}} = 0 \f$. + */ +class VISP_EXPORT vpStatisticalTestHinkley : public vpStatisticalTestAbstract +{ +protected: + float m_dmin2; /*!< Half of \f$\delta\f$, the drift minimal magnitude that we want to detect.*/ + float m_alpha; /*!< The \f$\alpha\f$ threshold indicating that a mean drift occurs. */ + float m_Sk; /*!< Test signal for downward mean drift.*/ + float m_Mk; /*!< Maximum of the test signal for downward mean drift \f$S_k\f$ .*/ + float m_Tk; /*!< Test signal for upward mean drift.*/ + float m_Nk; /*!< Minimum of the test signal for upward mean drift \f$T_k\f$*/ + + /** + * \brief Compute the mean value \f$m_0\f$ of the signal. The mean value must be + * computed before the mean drift is estimated on-line. + * + * \param[in] signal The new value of the signal to monitor. + */ + void computeMean(double signal); + + /** + * \brief Compute \f$S_k = \sum_{t=0}^{k} (s(t) - m_0 + \frac{\delta}{2})\f$ + * + * \param[in] signal The new value of the signal to monitor. + */ + void computeSk(double signal); + + /** + * \brief Compute \f$M_k\f$, the maximum value of \f$S_k\f$. + */ + void computeMk(); + + /** + * \brief Compute \f$T_k = \sum_{t=0}^{k} (s(t) - m_0 - \frac{\delta}{2})\f$ + * + * \param[in] signal The new value of the signal to monitor. + */ + void computeTk(double signal); + + /** + * \brief Compute \f$N_k\f$, the minimum value of \f$T_k\f$. + */ + void computeNk(); + + /** + * \brief Detects if a downward mean drift occured. + * + * \return \b vpMeanDriftType::MEAN_DRIFT_DOWNWARD if a downward mean drift occured, \b vpMeanDriftType::NO_MEAN_DRIFT otherwise. + */ +#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) + virtual vpMeanDriftType detectDownwardMeanShift() override; +#else + virtual vpMeanDriftType detectDownwardMeanShift(); +#endif + +/** + * \brief Detects if a upward mean drift occured. + * + * \return \b vpMeanDriftType::MEAN_DRIFT_UPWARD if an upward mean drift occured, \b vpMeanDriftType::NO_MEAN_DRIFT otherwise. + */ +#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) + virtual vpMeanDriftType detectUpwardMeanShift() override; +#else + virtual vpMeanDriftType detectUpwardMeanShift(); +#endif + +/** + * \brief Update the test signals. + * + * \param[in] signal The new value of the signal to monitor. + */ +#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) + virtual void updateTestSignals(const float &signal) override; +#else + virtual void updateTestSignals(const float &signal); +#endif +public: + /** + * @brief Construct a new vpStatisticalTestHinkley object. + * Call init() to initialise the Hinkley's test and set \f$\alpha\f$ + * and \f$\delta\f$ to default values. + * + * By default \f$ \delta = 0.2 \f$ and \f$ \alpha = 0.2\f$. Use + * setDelta() and setAlpha() to modify these values. + */ + vpStatisticalTestHinkley(); + + /** + * \brief Call init() to initialise the Hinkley's test and set \f$\alpha\f$ + * and \f$\delta\f$ thresholds. + * \param[in] alpha : \f$\alpha\f$ threshold indicating that a mean drift occurs. + * \param[in] delta : \f$\delta\f$ denotes the drift minimal magnitude that + * we want to detect. + * \param[in] nbSamplesForInit : number of signal samples to initialize the mean of the signal. + * + * \sa setAlpha(), setDelta() + */ + vpStatisticalTestHinkley(const float &alpha, const float &delta, const unsigned int &nbSamplesForInit = 30); + + /** + * \brief Destroy the vpStatisticalTestHinkley object. + */ + virtual ~vpStatisticalTestHinkley(); + + /** + * \brief Get the \f$\alpha\f$ threshold indicating that a mean drift occurs. + * + * \return The \f$\alpha\f$ threshold. + */ + inline float getAlpha() const { return m_alpha; } + + /*! + * \brief Get the test signal for downward mean drift. + * + * \return The value of \f$S_k = \sum_{t=0}^{k} (s(t) - m_0 + \frac{\delta}{2})\f$ . + */ + inline float getSk() const { return m_Sk; } + + /*! + * \brief Get the maximum of the test signal for downward mean drift \f$S_k\f$ . + * + * \return The value of \f$M_k\f$, the maximum value of \f$S_k\f$. + */ + inline float getMk() const { return m_Mk; } + + /*! + * \brief Get the test signal for upward mean drift.. + * + * \return The value of \f$T_k = \sum_{t=0}^{k} (s(t) - m_0 - \frac{\delta}{2})\f$ . + + */ + inline float getTk() const { return m_Tk; } + + /*! + * \brief Get the minimum of the test signal for upward mean drift \f$T_k\f$ + * + * \return The value of \f$N_k\f$, the minimum value of \f$T_k\f$. + */ + inline float getNk() const { return m_Nk; } + + /** + * \brief Initialise the Hinkley's test by setting the mean signal value + * \f$m_0\f$ to zero as well as \f$S_k, M_k, T_k, N_k\f$. + */ + void init(); + + /** + * \brief Initialise the Hinkley's test by setting the mean signal value + * \f$m_0\f$ to the expected value and \f$S_k, M_k, T_k, N_k\f$ to 0. + * + * \param[in] mean The expected value of the mean. + */ + void init(const float &mean); + + /** + * \brief Call init() to initialise the Hinkley's test and set \f$\alpha\f$ + * and \f$\delta\f$ thresholds. + * + * \param[in] alpha The threshold indicating that a mean drift occurs. + * \param[in] delta The drift minimal magnitude that we want to detect. + * \param[in] nbSamplesForInit : number of signal samples to initialize the mean of the signal. + */ + void init(const float &alpha, const float &delta, const unsigned int &nbSamplesForInit); + + /** + * \brief Call init() to initialise the Hinkley's test, set \f$\alpha\f$ + * and \f$\delta\f$ thresholds, and the mean of the signal \f$m_0\f$. + * + * \param[in] alpha The threshold indicating that a mean drift occurs. + * \param[in] delta The drift minimal magnitude that we want to detect. + * \param[in] mean The expected value of the mean. + */ + void init(const float &alpha, const float &delta, const float &mean); + + /** + * \brief Set the drift minimal magnitude that we want to detect. + * + * \param[in] delta The drift magnitude. + */ + void setDelta(const float &delta); + + /** + * \brief The threshold indicating that a mean drift occurs. + * + * \param[in] alpha The threshold. + */ + void setAlpha(const float &alpha); +}; + +#endif diff --git a/modules/core/include/visp3/core/vpStatisticalTestMeanAdjustedCUSUM.h b/modules/core/include/visp3/core/vpStatisticalTestMeanAdjustedCUSUM.h new file mode 100644 index 0000000000..2f514eee6d --- /dev/null +++ b/modules/core/include/visp3/core/vpStatisticalTestMeanAdjustedCUSUM.h @@ -0,0 +1,231 @@ +/**************************************************************************** + * + * ViSP, open source Visual Servoing Platform software. + * Copyright (C) 2005 - 2023 by Inria. All rights reserved. + * + * This software is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * See the file LICENSE.txt at the root directory of this source + * distribution for additional information about the GNU GPL. + * + * For using ViSP with software that can not be combined with the GNU + * GPL, please contact Inria about acquiring a ViSP Professional + * Edition License. + * + * See https://visp.inria.fr for more information. + * + * This software was developed at: + * Inria Rennes - Bretagne Atlantique + * Campus Universitaire de Beaulieu + * 35042 Rennes Cedex + * France + * + * If you have questions regarding the use of this file, please contact + * Inria at visp@inria.fr + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * +*****************************************************************************/ + +#ifndef _vpStatisticalTestMeanAdjustedCUSUM_h_ +#define _vpStatisticalTestMeanAdjustedCUSUM_h_ + +#include + +#include + +/** + * \ingroup group_core_math_tools + * \brief Class that permits to perform a mean adjusted Cumulative Sum test. + */ +class VISP_EXPORT vpStatisticalTestMeanAdjustedCUSUM : public vpStatisticalTestAbstract +{ +protected: + float m_delta; /*!< Slack of the CUSUM test, i.e. amplitude of mean shift we want to be able to detect.*/ + float m_h; /*!< Alarm factor that permits to determine the limit telling when a mean shift occurs: limit = m_h * m_stdev . + To have an Average Run Lenght of ~374 samples for a detection of 1 stdev, set it to 4.76f*/ + float m_half_delta; /*!< Half of the amplitude we want to detect.*/ + float m_k; /*!< Detection factor that permits to determine the slack: m_delta = m_k * m_stdev .*/ + float m_sminus; /*!< Test signal for downward mean shift: S_-(i) = max{0, S_-(i-1) - (y_i - m_mean) - m_delta/2}.*/ + float m_splus; /*!< Test signal for upward mean shift: S_+(i) = max{0, S_+(i-1) + (y_i - m_mean) - m_delta/2}.*/ + + /** + * \brief Compute the upper and lower limits of the test signal. + */ + virtual void computeDeltaAndLimits(); + +#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) + virtual vpMeanDriftType detectDownwardMeanShift() override; +#else + virtual vpMeanDriftType detectDownwardMeanShift(); +#endif + +/** + * \brief Detects if a upward jump occured on the mean. + * + * \return upwardJump if a upward jump occured, noJump otherwise. + */ +#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) + virtual vpMeanDriftType detectUpwardMeanShift() override; +#else + virtual vpMeanDriftType detectUpwardMeanShift(); +#endif + + /** + * \brief Update m_s and if enough values are available, compute the mean, the standard + * deviation and the limits. + * + * \param[in] signal The new value of the signal to monitor. + */ +#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) + virtual bool updateStatistics(const float &signal) override; +#else + virtual bool updateStatistics(const float &signal); +#endif + + /** + * \brief Update the test signals. + * + * \param[in] signal The new value of the signal to monitor. + */ +#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) + virtual void updateTestSignals(const float &signal) override; +#else + virtual void updateTestSignals(const float &signal); +#endif +public: + /** + * \brief Construct a new vpStatisticalTestMeanAdjustedCUSUM object. + * + * \param[in] h The alarm factor that permits to determine when the process is out of control from the standard + * deviation of the signal. + * \param[in] k The detection factor that permits to determine the slack of the CUSUM test, i.e. the + * minimum value of the jumps we want to detect, from the standard deviation of the signal. + * \param[in] nbPtsForStats The number of samples to use to compute the mean and the standard deviation of the signal + * to monitor. + */ + vpStatisticalTestMeanAdjustedCUSUM(const float &h = 4.f, const float &k = 1.f, const unsigned int &nbPtsForStats = 30); + + /** + * \brief Get the slack of the CUSUM test, + * i.e. amplitude of mean shift we want to be able to detect. + * + * \return float The slack of the CUSUM test. + */ + inline float getDelta() const + { + return m_delta; + } + + /** + * \brief Get the alarm factor. + * + * \return float The alarm factor. + */ + inline float getH() const + { + return m_h; + } + + /** + * \brief Get the detection factor. + * + * \return float The detection factor. + */ + inline float getK() const + { + return m_k; + } + + /** + * \brief Get the latest value of the test signal for downward jumps of the mean. + * + * \return float Its latest value. + */ + inline float getTestSignalMinus() const + { + return m_sminus; + } + + /** + * \brief Get the latest value of the test signal for upward jumps of the mean. + * + * \return float Its latest value. + */ + inline float getTestSignalPlus() const + { + return m_splus; + } + + /** + * \brief (Re)Initialize the mean adjusted CUSUM test. + * + * \param[in] h The alarm factor that permits to determine when the process is out of control from the standard + * deviation of the signal. + * \param[in] k The detection factor that permits to determine the slack of the CUSUM test, i.e. the + * minimum value of the jumps we want to detect, from the standard deviation of the signal. + * \param[in] nbPtsForStats The number of points to use to compute the mean and the standard deviation of the signal + */ + void init(const float &h, const float &k, const unsigned int &nbPtsForStats); + + /** + * \brief Initialize the mean adjusted CUSUM test. + * + * \param[in] delta The slack of the CUSUM test, i.e. the minimum value of the jumps we want to detect. + * \param[in] limitDown The lower limit of the CUSUM test, for the downward jumps. + * \param[in] limitUp The upper limit of the CUSUM test, for the upward jumps. + * \param[in] nbPtsForStats The number of points to use to compute the mean and the standard deviation of the signal + * to monitor. + */ + void init(const float &delta, const float &limitDown, const float &limitUp, const unsigned int &nbPtsForStats); + + /** + * \brief Initialize the mean adjusted CUSUM test. + * + * \param[in] h The alarm factor that permits to determine when the process is out of control from the standard + * deviation of the signal. + * \param[in] k The detection factor that permits to determine the slack of the CUSUM test, i.e. the + * minimum value of the jumps we want to detect, from the standard deviation of the signal. + * \param[in] mean The expected mean of the signal to monitor. + * \param[in] stdev The expected standard deviation of the signal to monitor. + */ + void init(const float &h, const float &k, const float &mean, const float &stdev); + + /** + * \brief Initialize the mean adjusted CUSUM test. + * + * \param[in] delta The slack of the CUSUM test, i.e. the minimum value of the jumps we want to detect. + * \param[in] limitDown The lower limit of the CUSUM test, for the downward jumps. + * \param[in] limitUp The upper limit of the CUSUM test, for the upward jumps. + * \param[in] mean The expected mean of the signal to monitor. + * \param[in] stdev The expected standard deviation of the signal to monitor. + */ + void init(const float &delta, const float &limitDown, const float &limitUp, const float &mean, const float &stdev); + + /** + * \brief Set the slack of the CUSUM test, i.e. the minimum value of the jumps we want to detect. + * + * \param[in] delta The slack of the CUSUM test. + */ + inline void setDelta(const float &delta) + { + m_delta = delta; + m_half_delta = 0.5f * delta; + } + + /** + * \brief Set the upward and downward jump limits. + * + * \param[in] limitDown The limit for the downward jumps. + * \param[in] limitUp The limit for the upward jumps. + */ + inline void setLimits(const float &limitDown, const float &limitUp) + { + m_limitDown = limitDown; + m_limitUp = limitUp; + } +}; +#endif diff --git a/modules/core/include/visp3/core/vpStatisticalTestSigma.h b/modules/core/include/visp3/core/vpStatisticalTestSigma.h new file mode 100644 index 0000000000..72036c860e --- /dev/null +++ b/modules/core/include/visp3/core/vpStatisticalTestSigma.h @@ -0,0 +1,142 @@ +/**************************************************************************** + * + * ViSP, open source Visual Servoing Platform software. + * Copyright (C) 2005 - 2023 by Inria. All rights reserved. + * + * This software is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * See the file LICENSE.txt at the root directory of this source + * distribution for additional information about the GNU GPL. + * + * For using ViSP with software that can not be combined with the GNU + * GPL, please contact Inria about acquiring a ViSP Professional + * Edition License. + * + * See https://visp.inria.fr for more information. + * + * This software was developed at: + * Inria Rennes - Bretagne Atlantique + * Campus Universitaire de Beaulieu + * 35042 Rennes Cedex + * France + * + * If you have questions regarding the use of this file, please contact + * Inria at visp@inria.fr + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * +*****************************************************************************/ + +#ifndef _vpStatisticalTestSigma_h_ +#define _vpStatisticalTestSigma_h_ + +#include + +#include + +/** + * \ingroup group_core_math_tools + * \brief Class that permits a simple test comparing the current value to the + * standard deviation of the signal. + */ + +class VISP_EXPORT vpStatisticalTestSigma : public vpStatisticalTestAbstract +{ +protected: + float m_h; /*!< The alarm factor applied to the standard deviation to compute the limits.*/ + float m_s; /*!< The last value of the signal.*/ + + /** + * \brief Compute the upper and lower limits of the test signal. + */ + virtual void computeLimits(); + +#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) + virtual vpMeanDriftType detectDownwardMeanShift() override; +#else + virtual vpMeanDriftType detectDownwardMeanShift(); +#endif + +/** + * \brief Detects if a upward jump occured on the mean. + * + * \return upwardJump if a upward jump occured, noJump otherwise. + */ +#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) + virtual vpMeanDriftType detectUpwardMeanShift() override; +#else + virtual vpMeanDriftType detectUpwardMeanShift(); +#endif + + /** + * \brief Update m_s and if enough values are available, compute the mean, the standard + * deviation and the limits. + * + * \param[in] signal The new value of the signal to monitor. + */ +#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) + virtual bool updateStatistics(const float &signal) override; +#else + virtual bool updateStatistics(const float &signal); +#endif + + /** + * \brief Update the test signals. + * + * \param[in] signal The new value of the signal to monitor. + */ +#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) + virtual void updateTestSignals(const float &signal) override; +#else + virtual void updateTestSignals(const float &signal); +#endif +public: + /** + * \brief Construct a new vpStatisticalTestSigma object. + * + * \param[in] h The alarm factor applied to the standard deviation to compute the limits. + * \param[in] nbSamplesForStats The number of samples to compute the statistics of the signal. + */ + vpStatisticalTestSigma(const float &h = 3.f, const unsigned int &nbSamplesForStats = 30); + + /** + * \brief Construct a new vpStatisticalTestSigma object. + * + * \param[in] h The alarm factor applied to the standard deviation to compute the limits. + * \param[in] mean The expected mean of the signal. + * \param[in] stdev The expected standard deviation of the signal. + */ + vpStatisticalTestSigma(const float &h, const float &mean, const float &stdev); + + /** + * \brief Get the last value of the signal. + * + * \return float The signal. + */ + inline float getS() const + { + return m_s; + } + + /** + * \brief (Re)Initialize the test. + * + * \param[in] h The alarm factor applied to the standard deviation to compute the limits. + * \param[in] nbSamplesForStats The number of samples to compute the statistics of the signal. + */ + void init(const float &h = 3.f, const unsigned int &nbSamplesForStats = 30); + + /** + * \brief (Re)Initialize the test. + * + * \param[in] h The alarm factor applied to the standard deviation to compute the limits. + * \param[in] mean The expected mean of the signal. + * \param[in] stdev The expected standard deviation of the signal. + */ + void init(const float &h, const float &mean, const float &stdev); +}; + +#endif diff --git a/modules/core/src/math/misc/vpHinkley.cpp b/modules/core/src/math/misc/vpHinkley.cpp index 40b06647ef..fc534c3e7e 100644 --- a/modules/core/src/math/misc/vpHinkley.cpp +++ b/modules/core/src/math/misc/vpHinkley.cpp @@ -42,9 +42,9 @@ */ -#include #include -//#include +#if defined(VISP_BUILD_DEPRECATED_FUNCTIONS) +#include #include #include // std::fabs @@ -70,7 +70,7 @@ setDelta() and setAlpha() to modify these values. */ -vpHinkley::vpHinkley() : dmin2(0.1), alpha(0.2), nsignal(0), mean(0), Sk(0), Mk(0), Tk(0), Nk(0) {} +vpHinkley::vpHinkley() : dmin2(0.1), alpha(0.2), nsignal(0), mean(0), Sk(0), Mk(0), Tk(0), Nk(0) { } /*! @@ -90,8 +90,7 @@ vpHinkley::vpHinkley() : dmin2(0.1), alpha(0.2), nsignal(0), mean(0), Sk(0), Mk( vpHinkley::vpHinkley(double alpha_val, double delta_val) : dmin2(delta_val / 2.), alpha(alpha_val), nsignal(0), mean(0), Sk(0), Mk(0), Tk(0), Nk(0) -{ -} +{ } /*! @@ -119,7 +118,7 @@ void vpHinkley::init(double alpha_val, double delta_val) Destructor. */ -vpHinkley::~vpHinkley() {} +vpHinkley::~vpHinkley() { } /*! @@ -305,9 +304,9 @@ vpHinkley::vpHinkleyJumpType vpHinkley::testDownUpwardJump(double signal) computeNk(); vpCDEBUG(2) << "alpha: " << alpha << " dmin2: " << dmin2 << " signal: " << signal << " Sk: " << Sk << " Mk: " << Mk - << " Tk: " << Tk << " Nk: " << Nk << std::endl; + << " Tk: " << Tk << " Nk: " << Nk << std::endl; - // teste si les variables cumulees excedent le seuil +// teste si les variables cumulees excedent le seuil if ((Mk - Sk) > alpha) jump = downwardJump; else if ((Tk - Nk) > alpha) @@ -433,3 +432,7 @@ void vpHinkley::print(vpHinkley::vpHinkleyJumpType jump) break; } } +#elif !defined(VISP_BUILD_SHARED_LIBS) + // Work around to avoid warning: libvisp_core.a(vpHinkley.cpp.o) has no symbols +void dummy_vpRHinkley() { }; +#endif diff --git a/modules/core/src/math/misc/vpStatisticalTestAbstract.cpp b/modules/core/src/math/misc/vpStatisticalTestAbstract.cpp new file mode 100644 index 0000000000..591674dd77 --- /dev/null +++ b/modules/core/src/math/misc/vpStatisticalTestAbstract.cpp @@ -0,0 +1,210 @@ +/**************************************************************************** + * + * ViSP, open source Visual Servoing Platform software. + * Copyright (C) 2005 - 2023 by Inria. All rights reserved. + * + * This software is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * See the file LICENSE.txt at the root directory of this source + * distribution for additional information about the GNU GPL. + * + * For using ViSP with software that can not be combined with the GNU + * GPL, please contact Inria about acquiring a ViSP Professional + * Edition License. + * + * See https://visp.inria.fr for more information. + * + * This software was developed at: + * Inria Rennes - Bretagne Atlantique + * Campus Universitaire de Beaulieu + * 35042 Rennes Cedex + * France + * + * If you have questions regarding the use of this file, please contact + * Inria at visp@inria.fr + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * +*****************************************************************************/ + +/** +* +* \file vpStatisticalTestAbstract.cpp +* +* \brief Definition of the vpStatisticalTestAbstract base class. +*/ + +#include + +std::string vpStatisticalTestAbstract::vpMeanDriftTypeToString(const vpStatisticalTestAbstract::vpMeanDriftType &type) +{ + std::string name; + switch (type) { + case NO_MEAN_DRIFT: + name = " No jump"; + break; + case MEAN_DRIFT_DOWNWARD: + name = " Jump downward"; + break; + case MEAN_DRIFT_UPWARD: + name = " Jump upward"; + break; + default: + name = " Undefined jump"; + break; + } + return name; +} + +void vpStatisticalTestAbstract::print(const vpStatisticalTestAbstract::vpMeanDriftType &type) +{ + std::cout << vpMeanDriftTypeToString(type) << " detected" << std::endl; +} + +bool vpStatisticalTestAbstract::updateStatistics(const float &signal) +{ + m_s[static_cast(m_count)] = signal; + m_count += 1.f; + m_sumForMean += signal; + if (static_cast (m_count) >= m_nbSamplesForStatistics) { + // Computation of the mean + m_mean = m_sumForMean / m_count; + + // Computation of the stdev + float sumSquaredDiff = 0.f; + unsigned int count = static_cast(m_nbSamplesForStatistics); + for (unsigned int i = 0; i < count; ++i) { + sumSquaredDiff += (m_s[i] - m_mean) * (m_s[i] - m_mean); + } + float stdev = std::sqrt(sumSquaredDiff / m_count); + if (m_stdevmin < 0) { + m_stdev = stdev; + } + else { + m_stdev = std::max(m_stdev, m_stdevmin); + } + + m_areStatisticsComputed = true; + } + return m_areStatisticsComputed; +} + +vpStatisticalTestAbstract::vpStatisticalTestAbstract() + : m_areStatisticsComputed(false) + , m_count(0.f) + , m_limitDown(0.f) + , m_limitUp(0.f) + , m_mean(0.f) + , m_nbSamplesForStatistics(0) + , m_s(nullptr) + , m_stdev(0.f) + , m_stdevmin(-1.f) + , m_sumForMean(0.f) +{ } + +vpStatisticalTestAbstract::vpStatisticalTestAbstract(const vpStatisticalTestAbstract &other) +{ + *this = other; +} + +vpStatisticalTestAbstract::~vpStatisticalTestAbstract() +{ + if (m_s != nullptr) { + delete m_s; + m_s = nullptr; + } +} + +void vpStatisticalTestAbstract::init() +{ + m_areStatisticsComputed = false; + m_count = 0.f; + m_limitDown = 0.f; + m_limitUp = 0.f; + m_mean = 0.f; + m_nbSamplesForStatistics = 0; + if (m_s != nullptr) { + delete m_s; + m_s = nullptr; + } + m_stdev = 0.f; + m_sumForMean = 0.f; +} + +vpStatisticalTestAbstract &vpStatisticalTestAbstract::operator=(const vpStatisticalTestAbstract &other) +{ + m_areStatisticsComputed = other.m_areStatisticsComputed; + m_count = other.m_count; + m_limitDown = other.m_limitDown; + m_limitUp = other.m_limitUp; + m_mean = other.m_mean; + if (other.m_nbSamplesForStatistics > 0) { + setNbSamplesForStat(other.m_nbSamplesForStatistics); + } + else if (m_s != nullptr) { + m_nbSamplesForStatistics = 0; + delete m_s; + m_s = nullptr; + } + m_stdev = 0.f; + m_sumForMean = 0.f; + return *this; +} + +void vpStatisticalTestAbstract::setNbSamplesForStat(const unsigned int &nbSamples) +{ + m_nbSamplesForStatistics = nbSamples; + if (m_s != nullptr) { + delete m_s; + } + m_s = new float[nbSamples]; +} + +vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestAbstract::testDownUpwardMeanShift(const float &signal) +{ + if (m_areStatisticsComputed) { + updateTestSignals(signal); + vpMeanDriftType jumpDown = detectDownwardMeanShift(); + vpMeanDriftType jumpUp = detectUpwardMeanShift(); + if (jumpDown != NO_MEAN_DRIFT) { + return jumpDown; + } + else if (jumpUp != NO_MEAN_DRIFT) { + return jumpUp; + } + else { + return NO_MEAN_DRIFT; + } + } + else { + updateStatistics(signal); + return NO_MEAN_DRIFT; + } +} + +vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestAbstract::testDownwardMeanShift(const float &signal) +{ + if (m_areStatisticsComputed) { + updateTestSignals(signal); + return detectDownwardMeanShift(); + } + else { + updateStatistics(signal); + return NO_MEAN_DRIFT; + } +} + +vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestAbstract::testUpwardMeanShift(const float &signal) +{ + if (m_areStatisticsComputed) { + updateTestSignals(signal); + return detectUpwardMeanShift(); + } + else { + updateStatistics(signal); + return NO_MEAN_DRIFT; + } +} diff --git a/modules/core/src/math/misc/vpStatisticalTestEWMA.cpp b/modules/core/src/math/misc/vpStatisticalTestEWMA.cpp new file mode 100644 index 0000000000..d4dd6a5e28 --- /dev/null +++ b/modules/core/src/math/misc/vpStatisticalTestEWMA.cpp @@ -0,0 +1,129 @@ +/**************************************************************************** + * + * ViSP, open source Visual Servoing Platform software. + * Copyright (C) 2005 - 2023 by Inria. All rights reserved. + * + * This software is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * See the file LICENSE.txt at the root directory of this source + * distribution for additional information about the GNU GPL. + * + * For using ViSP with software that can not be combined with the GNU + * GPL, please contact Inria about acquiring a ViSP Professional + * Edition License. + * + * See https://visp.inria.fr for more information. + * + * This software was developed at: + * Inria Rennes - Bretagne Atlantique + * Campus Universitaire de Beaulieu + * 35042 Rennes Cedex + * France + * + * If you have questions regarding the use of this file, please contact + * Inria at visp@inria.fr + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * +*****************************************************************************/ + +/** +* +* \file vpStatisticalTestEWMA.cpp +* +* \brief Definition of the vpStatisticalTestEWMA class that implements Exponentially Weighted Moving Average +* mean drift test. +*/ + +#include + +void vpStatisticalTestEWMA::computeDeltaAndLimits() +{ + float delta = 3.f * m_stdev * std::sqrt(m_alpha / (2.f - m_alpha)); + m_limitDown = m_mean - delta; + m_limitUp = m_mean + delta; +} + +vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestEWMA::detectDownwardMeanShift() +{ + if (m_wt <= m_limitDown) { + return MEAN_DRIFT_DOWNWARD; + } + else { + return NO_MEAN_DRIFT; + } +} + +vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestEWMA::detectUpwardMeanShift() +{ + if (m_wt >= m_limitUp) { + return MEAN_DRIFT_UPWARD; + } + else { + return NO_MEAN_DRIFT; + } +} + +bool vpStatisticalTestEWMA::updateStatistics(const float &signal) +{ + bool areStatsReady = vpStatisticalTestAbstract::updateStatistics(signal); + if (areStatsReady) { + // Computation of the limits + computeDeltaAndLimits(); + + // Initialize first value + m_wt = m_mean; + } + return areStatsReady; +} + +void vpStatisticalTestEWMA::updateTestSignals(const float &signal) +{ + // Update last value + m_wtprev = m_wt; +// w(t) = alpha * s(t) + (1 - alpha) * w(t- 1); + m_wt = m_wtprev + m_alpha * (signal - m_wtprev); +} + +vpStatisticalTestEWMA::vpStatisticalTestEWMA(const float &alpha) + : vpStatisticalTestAbstract() + , m_alpha(0.f) + , m_wt(0.f) + , m_wtprev(0.f) +{ + init(alpha); +} + +void vpStatisticalTestEWMA::init(const float &alpha) +{ + vpStatisticalTestAbstract::init(); + m_alpha = alpha; + unsigned int nbRequiredSamples = static_cast(std::ceil(3.f / m_alpha)); + setNbSamplesForStat(nbRequiredSamples); + m_wt = 0.f; + m_wtprev = 0.f; +} + +void vpStatisticalTestEWMA::init(const float &alpha, const float &mean, const float &stdev) +{ + vpStatisticalTestAbstract::init(); + m_alpha = alpha; + m_mean = mean; + unsigned int nbRequiredSamples = static_cast(std::ceil(3.f / m_alpha)); + setNbSamplesForStat(nbRequiredSamples); + m_stdev = stdev; + m_wt = mean; + m_wtprev = 0.f; + + // Computation of the limits + computeDeltaAndLimits(); + m_areStatisticsComputed = true; +} + +void vpStatisticalTestEWMA::setAlpha(const float &alpha) +{ + init(alpha); +} diff --git a/modules/core/src/math/misc/vpStatisticalTestHinkley.cpp b/modules/core/src/math/misc/vpStatisticalTestHinkley.cpp new file mode 100644 index 0000000000..b001d010b6 --- /dev/null +++ b/modules/core/src/math/misc/vpStatisticalTestHinkley.cpp @@ -0,0 +1,189 @@ +/**************************************************************************** + * + * ViSP, open source Visual Servoing Platform software. + * Copyright (C) 2005 - 2023 by Inria. All rights reserved. + * + * This software is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * See the file LICENSE.txt at the root directory of this source + * distribution for additional information about the GNU GPL. + * + * For using ViSP with software that can not be combined with the GNU + * GPL, please contact Inria about acquiring a ViSP Professional + * Edition License. + * + * See https://visp.inria.fr for more information. + * + * This software was developed at: + * Inria Rennes - Bretagne Atlantique + * Campus Universitaire de Beaulieu + * 35042 Rennes Cedex + * France + * + * If you have questions regarding the use of this file, please contact + * Inria at visp@inria.fr + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * +*****************************************************************************/ + +#include + +/** +* +* \file vpStatisticalTestHinkley.cpp +* +* \brief Definition of the vpStatisticalTestHinkley class corresponding to the Hinkley's +* cumulative sum test. +*/ + +#include +#include + +#include // std::fabs +#include +#include // numeric_limits +#include +#include + +vpStatisticalTestHinkley::vpStatisticalTestHinkley() + : vpStatisticalTestAbstract() + , m_dmin2(0.1f) + , m_alpha(0.2f) + , m_Sk(0.f) + , m_Mk(0.f) + , m_Tk(0.f) + , m_Nk(0.f) +{ + init(); +} + +vpStatisticalTestHinkley::vpStatisticalTestHinkley(const float &alpha, const float &delta_val, const unsigned int &nbSamplesForInit) + : vpStatisticalTestAbstract() + , m_dmin2(delta_val / 2.f) + , m_alpha(alpha) + , m_Sk(0.f) + , m_Mk(0.f) + , m_Tk(0.f) + , m_Nk(0.f) +{ + init(alpha, delta_val, nbSamplesForInit); +} + +void vpStatisticalTestHinkley::init(const float &alpha, const float &delta_val, const unsigned int &nbSamplesForInit) +{ + init(); + setNbSamplesForStat(nbSamplesForInit); + setAlpha(alpha); + setDelta(delta_val); +} + +void vpStatisticalTestHinkley::init(const float &alpha, const float &delta_val, const float &mean) +{ + init(); + setAlpha(alpha); + setDelta(delta_val); + m_mean = mean; + m_areStatisticsComputed = true; +} + +vpStatisticalTestHinkley::~vpStatisticalTestHinkley() { } + +void vpStatisticalTestHinkley::init() +{ + vpStatisticalTestAbstract::init(); + setNbSamplesForStat(30); + setAlpha(m_alpha); + + m_Sk = 0.f; + m_Mk = 0.f; + + m_Tk = 0.f; + m_Nk = 0.f; +} + +void vpStatisticalTestHinkley::init(const float &mean) +{ + vpStatisticalTestHinkley::init(); + m_mean = mean; + m_areStatisticsComputed = true; +} + +void vpStatisticalTestHinkley::setDelta(const float &delta) { m_dmin2 = delta / 2.f; } + +void vpStatisticalTestHinkley::setAlpha(const float &alpha) +{ + this->m_alpha = alpha; + m_limitDown = m_alpha; + m_limitUp = m_alpha; +} + +void vpStatisticalTestHinkley::computeMean(double signal) +{ + // When the mean slowly increases or decreases, especially after an abrupt change of the mean, + // the means tends to drift. To reduce the drift of the mean + // it is updated with the current value of the signal only if + // a beginning of a mean drift is not detected, + // i.e. if ( ((m_Mk-m_Sk) == 0) && ((m_Tk-m_Nk) == 0) ) + if ((std::fabs(m_Mk - m_Sk) <= std::fabs(vpMath::maximum(m_Mk, m_Sk)) * std::numeric_limits::epsilon()) && + (std::fabs(m_Tk - m_Nk) <= std::fabs(vpMath::maximum(m_Tk, m_Nk)) * std::numeric_limits::epsilon())) { + m_mean = (m_mean * (m_count - 1) + signal) / (m_count); + } +} + +void vpStatisticalTestHinkley::computeSk(double signal) +{ + m_Sk += signal - m_mean + m_dmin2; +} + +void vpStatisticalTestHinkley::computeMk() +{ + if (m_Sk > m_Mk) { + m_Mk = m_Sk; + } +} + +void vpStatisticalTestHinkley::computeTk(double signal) +{ + m_Tk += signal - m_mean - m_dmin2; +} + +void vpStatisticalTestHinkley::computeNk() +{ + if (m_Tk < m_Nk) { + m_Nk = m_Tk; + } +} + +vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestHinkley::detectDownwardMeanShift() +{ + vpStatisticalTestAbstract::vpMeanDriftType shift = NO_MEAN_DRIFT; + if ((m_Mk - m_Sk) > m_alpha) { + shift = MEAN_DRIFT_DOWNWARD; + } + return shift; +} + +vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestHinkley::detectUpwardMeanShift() +{ + vpStatisticalTestAbstract::vpMeanDriftType shift = NO_MEAN_DRIFT; + if ((m_Tk - m_Nk) > m_alpha) { + shift = MEAN_DRIFT_UPWARD; + } + return shift; +} + +void vpStatisticalTestHinkley::updateTestSignals(const float &signal) +{ + computeSk(signal); + computeTk(signal); + + computeMk(); + computeNk(); + + ++m_count; + computeMean(signal); +} diff --git a/modules/core/src/math/misc/vpStatisticalTestMeanAdjustedCUSUM.cpp b/modules/core/src/math/misc/vpStatisticalTestMeanAdjustedCUSUM.cpp new file mode 100644 index 0000000000..a60cf77798 --- /dev/null +++ b/modules/core/src/math/misc/vpStatisticalTestMeanAdjustedCUSUM.cpp @@ -0,0 +1,156 @@ +/**************************************************************************** + * + * ViSP, open source Visual Servoing Platform software. + * Copyright (C) 2005 - 2023 by Inria. All rights reserved. + * + * This software is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * See the file LICENSE.txt at the root directory of this source + * distribution for additional information about the GNU GPL. + * + * For using ViSP with software that can not be combined with the GNU + * GPL, please contact Inria about acquiring a ViSP Professional + * Edition License. + * + * See https://visp.inria.fr for more information. + * + * This software was developed at: + * Inria Rennes - Bretagne Atlantique + * Campus Universitaire de Beaulieu + * 35042 Rennes Cedex + * France + * + * If you have questions regarding the use of this file, please contact + * Inria at visp@inria.fr + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * +*****************************************************************************/ + +/** +* +* \file vpStatisticalTestMeanAdjustedCUSUM.cpp +* +* \brief Definition of the vpStatisticalTestMeanAdjustedCUSUM class that implements mean adjusted Cumulative Sum +* mean drift test. +*/ + +#include + +void vpStatisticalTestMeanAdjustedCUSUM::computeDeltaAndLimits() +{ + setDelta(m_k * m_stdev); + float limitDown = m_h * m_stdev; + float limitUp = limitDown; + setLimits(limitDown, limitUp); +} + +vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestMeanAdjustedCUSUM::detectDownwardMeanShift() +{ + if (m_sminus >= m_limitDown) { + return MEAN_DRIFT_DOWNWARD; + } + else { + return NO_MEAN_DRIFT; + } +} + +vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestMeanAdjustedCUSUM::detectUpwardMeanShift() +{ + if (m_splus >= m_limitUp) { + return MEAN_DRIFT_UPWARD; + } + else { + return NO_MEAN_DRIFT; + } +} + +bool vpStatisticalTestMeanAdjustedCUSUM::updateStatistics(const float &signal) +{ + bool areStatsAvailable = vpStatisticalTestAbstract::updateStatistics(signal); + if (areStatsAvailable) { + // Computation of the limits + if ((m_limitDown < 0.f) && (m_limitUp < 0.f)) { + computeDeltaAndLimits(); + } + + // Initialize first values + m_sminus = 0.f; + m_splus = 0.f; + } + return areStatsAvailable; +} + +void vpStatisticalTestMeanAdjustedCUSUM::updateTestSignals(const float &signal) +{ + m_sminus = std::max(0.f, m_sminus - (signal - m_mean) - m_half_delta); + m_splus = std::max(0.f, m_splus + (signal - m_mean) - m_half_delta); +} + +vpStatisticalTestMeanAdjustedCUSUM::vpStatisticalTestMeanAdjustedCUSUM(const float &h, const float &k, const unsigned int &nbPtsForStats) + : vpStatisticalTestAbstract() + , m_delta(-1.f) + , m_h(h) + , m_half_delta(-1.f) + , m_k(k) + , m_sminus(0.f) + , m_splus(0.f) +{ + init(h, k, nbPtsForStats); +} + +void vpStatisticalTestMeanAdjustedCUSUM::init(const float &h, const float &k, const unsigned int &nbPtsForStats) +{ + vpStatisticalTestAbstract::init(); + setNbSamplesForStat(nbPtsForStats); + m_delta = -1.f; + m_half_delta = -1.f; + setLimits(-1.f, -1.f); // To compute automatically the limits once the signal statistics are available. + m_h = h; + m_k = k; + m_mean = 0.f; + m_sminus = 0.f; + m_splus = 0.f; + m_stdev = 0.f; +} + +void vpStatisticalTestMeanAdjustedCUSUM::init(const float &delta, const float &limitDown, const float &limitUp, const unsigned int &nbPtsForStats) +{ + vpStatisticalTestAbstract::init(); + setDelta(delta); + setLimits(limitDown, limitUp); + setNbSamplesForStat(nbPtsForStats); + m_sminus = 0.f; + m_splus = 0.f; +} + +void vpStatisticalTestMeanAdjustedCUSUM::init(const float &h, const float &k, const float &mean, const float &stdev) +{ + vpStatisticalTestAbstract::init(); + setLimits(-1.f, -1.f); // To compute automatically the limits once the signal statistics are available. + m_h = h; + m_k = k; + m_mean = mean; + m_sminus = 0.f; + m_splus = 0.f; + m_stdev = stdev; + // Compute delta and limits from m_h, m_k and m_stdev + computeDeltaAndLimits(); + m_areStatisticsComputed = true; +} + +void vpStatisticalTestMeanAdjustedCUSUM::init(const float &delta, const float &limitDown, const float &limitUp, const float &mean, const float &stdev) +{ + vpStatisticalTestAbstract::init(); + setDelta(delta); + setLimits(limitDown, limitUp); + m_mean = mean; + m_sminus = 0.f; + m_splus = 0.f; + m_stdev = stdev; + m_sumForMean = 0.f; + m_areStatisticsComputed = true; +} diff --git a/modules/core/src/math/misc/vpStatisticalTestSigma.cpp b/modules/core/src/math/misc/vpStatisticalTestSigma.cpp new file mode 100644 index 0000000000..65dd6a1d2b --- /dev/null +++ b/modules/core/src/math/misc/vpStatisticalTestSigma.cpp @@ -0,0 +1,107 @@ +/**************************************************************************** + * + * ViSP, open source Visual Servoing Platform software. + * Copyright (C) 2005 - 2023 by Inria. All rights reserved. + * + * This software is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * See the file LICENSE.txt at the root directory of this source + * distribution for additional information about the GNU GPL. + * + * For using ViSP with software that can not be combined with the GNU + * GPL, please contact Inria about acquiring a ViSP Professional + * Edition License. + * + * See https://visp.inria.fr for more information. + * + * This software was developed at: + * Inria Rennes - Bretagne Atlantique + * Campus Universitaire de Beaulieu + * 35042 Rennes Cedex + * France + * + * If you have questions regarding the use of this file, please contact + * Inria at visp@inria.fr + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * +*****************************************************************************/ + +#include + +void vpStatisticalTestSigma::computeLimits() +{ + float delta = m_h * m_stdev; + m_limitDown = m_mean - delta; + m_limitUp = m_mean + delta; +} + +vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestSigma::detectDownwardMeanShift() +{ + if (m_s <= m_limitDown) { + return vpStatisticalTestAbstract::MEAN_DRIFT_DOWNWARD; + } + else { + return vpStatisticalTestAbstract::NO_MEAN_DRIFT; + } +} + +vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestSigma::detectUpwardMeanShift() +{ + if (m_s >= m_limitUp) { + return vpStatisticalTestAbstract::MEAN_DRIFT_UPWARD; + } + else { + return vpStatisticalTestAbstract::NO_MEAN_DRIFT; + } +} + +bool vpStatisticalTestSigma::updateStatistics(const float &signal) +{ + bool areStatsAvailable = vpStatisticalTestAbstract::updateStatistics(signal); + if (areStatsAvailable) { + computeLimits(); + } + return areStatsAvailable; +} + +void vpStatisticalTestSigma::updateTestSignals(const float &signal) +{ + m_s = signal; +} + +vpStatisticalTestSigma::vpStatisticalTestSigma(const float &h, const unsigned int &nbSamplesForStats) + : vpStatisticalTestAbstract() + , m_h(h) +{ + init(h, nbSamplesForStats); +} + +vpStatisticalTestSigma::vpStatisticalTestSigma(const float &h, const float &mean, const float &stdev) + : vpStatisticalTestAbstract() + , m_h(h) +{ + init(h, mean, stdev); +} + +void vpStatisticalTestSigma::init(const float &h, const unsigned int &nbSamplesForStats) +{ + vpStatisticalTestAbstract::init(); + m_h = h; + setNbSamplesForStat(nbSamplesForStats); + m_s = 0; +} + +void vpStatisticalTestSigma::init(const float &h, const float &mean, const float &stdev) +{ + vpStatisticalTestAbstract::init(); + m_h = h; + m_mean = mean; + m_s = 0; + m_stdev = stdev; + computeLimits(); + m_areStatisticsComputed = true; +} diff --git a/tutorial/CMakeLists.txt b/tutorial/CMakeLists.txt index 7ede770bdd..ae1233344b 100644 --- a/tutorial/CMakeLists.txt +++ b/tutorial/CMakeLists.txt @@ -44,6 +44,7 @@ visp_add_subdirectory(imgproc/contrast-sharpening REQUIRED_DEPS visp_co visp_add_subdirectory(imgproc/count-coins REQUIRED_DEPS visp_core visp_io visp_gui visp_imgproc) visp_add_subdirectory(imgproc/flood-fill REQUIRED_DEPS visp_core visp_io visp_gui visp_imgproc) visp_add_subdirectory(imgproc/hough-transform REQUIRED_DEPS visp_core visp_gui visp_imgproc) +visp_add_subdirectory(mean-drift REQUIRED_DEPS visp_core visp_gui) visp_add_subdirectory(munkres REQUIRED_DEPS visp_core visp_gui) visp_add_subdirectory(robot/flir-ptu REQUIRED_DEPS visp_core visp_robot visp_sensor visp_vision visp_gui visp_vs visp_visual_features visp_detection) visp_add_subdirectory(robot/pioneer REQUIRED_DEPS visp_core visp_robot visp_vs visp_gui) diff --git a/tutorial/mean-drift/CMakeLists.txt b/tutorial/mean-drift/CMakeLists.txt new file mode 100644 index 0000000000..fed2f435fd --- /dev/null +++ b/tutorial/mean-drift/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.5) + +project(tutorial-meandrift) + +find_package(VISP REQUIRED visp_core visp_gui) + +set(tutorial_cpp) + +list(APPEND tutorial_cpp tutorial-meandrift.cpp) + +foreach(cpp ${tutorial_cpp}) + visp_add_target(${cpp}) + if(COMMAND visp_add_dependency) + visp_add_dependency(${cpp} "tutorials") + endif() +endforeach() diff --git a/tutorial/mean-drift/tutorial-meandrift.cpp b/tutorial/mean-drift/tutorial-meandrift.cpp new file mode 100644 index 0000000000..37f4aeb659 --- /dev/null +++ b/tutorial/mean-drift/tutorial-meandrift.cpp @@ -0,0 +1,371 @@ +/**************************************************************************** + * + * ViSP, open source Visual Servoing Platform software. + * Copyright (C) 2005 - 2023 by Inria. All rights reserved. + * + * This software is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * See the file LICENSE.txt at the root directory of this source + * distribution for additional information about the GNU GPL. + * + * For using ViSP with software that can not be combined with the GNU + * GPL, please contact Inria about acquiring a ViSP Professional + * Edition License. + * + * See https://visp.inria.fr for more information. + * + * This software was developed at: + * Inria Rennes - Bretagne Atlantique + * Campus Universitaire de Beaulieu + * 35042 Rennes Cedex + * France + * + * If you have questions regarding the use of this file, please contact + * Inria at visp@inria.fr + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * +*****************************************************************************/ + +//! \example tutorial-meandrift.cpp + +#include +#include +#include +#include +#include +#include +#include + +namespace TutorialMeanDrift +{ + /** + * \brief Structure that permits to choose which process test to use. + * + */ +typedef enum TypeTest +{ + HINLKEY_TYPE_TEST = 0, /*!< Use Hinkley to perform the tests.*/ + EWMA_TYPE_TEST = 1, /*!< Use Exponentially Weighted Moving Average to perform the tests.*/ + MEAN_ADJUSTED_CUSUM_TYPE_TEST = 2, /*!< Use mean adjusted Cumulative Sum to perform the tests.*/ + SIGMA_TYPE_TEST = 3, /*!< Simple test based on the comparisong with the standard deviation.*/ + COUNT_TYPE_TEST = 4, /*!< Number of different aavailable methods.*/ + UNKOWN_TYPE_TEST = COUNT_TYPE_TEST /*!< Unknown method.*/ +}TypeTest; + +/** + * \brief Permit to cast a \b TypeTest object into a string, for display purpose. + * + * \param[in] choice The \b TypeTest object we want to know the name. + * \return std::string The corresponding name. + */ +std::string typeTestToString(const TypeTest &type) +{ + std::string result; + switch (type) { + case HINLKEY_TYPE_TEST: + result = "hinkley"; + break; + case EWMA_TYPE_TEST: + result = "ewma"; + break; + case MEAN_ADJUSTED_CUSUM_TYPE_TEST: + result = "cusum"; + break; + case SIGMA_TYPE_TEST: + result = "sigma"; + break; + case UNKOWN_TYPE_TEST: + default: + result = "unknown-type-test"; + break; + } + return result; +} + +/** + * \brief Permit to cast a string into a \b TypeTest, to + * cast a command line argument. + * + * \param[in] name The name of the process test the user wants to use. + * \return TypeTest The corresponding \b TypeTest object. + */ +TypeTest typeTestFromString(const std::string &name) +{ + TypeTest result = UNKOWN_TYPE_TEST; + unsigned int count = static_cast(COUNT_TYPE_TEST); + unsigned int id = 0; + bool hasNotFound = true; + while ((id < count) && hasNotFound) { + TypeTest temp = static_cast(id); + if (typeTestToString(temp) == name) { + result = temp; + hasNotFound = false; + } + ++id; + } + return result; +} + +/** + * \brief Get the list of available \b TypeTest objects that are handled. + * + * \param[in] prefix The prefix that should be placed before the list. + * \param[in] sep The separator between each element of the list. + * \param[in] suffix The suffix that should terminate the list. + * \return std::string The list of handled type of process tests, presented as a string. + */ +std::string getAvailableTypeTest(const std::string &prefix = "<", const std::string &sep = " , ", + const std::string &suffix = ">") +{ + std::string msg(prefix); + unsigned int count = static_cast(COUNT_TYPE_TEST); + unsigned int lastId = count - 1; + for (unsigned int i = 0; i < lastId; i++) { + msg += typeTestToString(static_cast(i)) + sep; + } + msg += typeTestToString(static_cast(lastId)) + suffix; + return msg; +} + +/** + * \brief Structure that contains the parameters of the different algorithms. + */ +typedef struct ParametersForAlgo +{ + unsigned int m_global_nbsamples; /*!< Number of samples to compute the mean and stdev, common to all the algorithms.*/ + float m_cusum_h; /*!< Alarm factor for the mean adjusted CUSUM test.*/ + float m_cusum_k; /*!< Detection factor for the mean adjusted CUSUM test.*/ + float m_ewma_alpha; /*!< Forgetting factor for the EWMA test.*/ + float m_hinkley_alpha; /*!< Alarm threshold for the Hinkley's test. */ + float m_hinkley_delta; /*!< Detection threshold for the Hinkley's test. */ + float m_sigma_h; /*!< Alarm factor for the sigma test.*/ + + ParametersForAlgo() + : m_global_nbsamples(30) + , m_cusum_h(4.76f) + , m_cusum_k(1.f) + , m_ewma_alpha(0.1f) + , m_hinkley_alpha(4.76f) + , m_hinkley_delta(1.f) + , m_sigma_h(3.f) + { } +}ParametersForAlgo; +} + +int testOnSynthetic(const TutorialMeanDrift::TypeTest &type, const TutorialMeanDrift::ParametersForAlgo parameters, + const float &mean, const float &mean_drift, const float &stdev) +{ + const float dt = 10.f; // Emulate a 10ms period + + vpPlot plotter(1); + plotter.initGraph(0, 1); + plotter.setTitle(0, "Evolution of the signal"); + plotter.setUnitX(0, "Frame ID"); + plotter.setUnitY(0, "No units"); + + unsigned int idFrame = 0; + vpStatisticalTestAbstract *p_test = nullptr; + switch (type) { + case TutorialMeanDrift::EWMA_TYPE_TEST: + p_test = new vpStatisticalTestEWMA(parameters.m_ewma_alpha); + break; + case TutorialMeanDrift::HINLKEY_TYPE_TEST: + p_test = new vpStatisticalTestHinkley(parameters.m_hinkley_alpha, parameters.m_hinkley_delta, parameters.m_global_nbsamples); + break; + case TutorialMeanDrift::MEAN_ADJUSTED_CUSUM_TYPE_TEST: + p_test = new vpStatisticalTestMeanAdjustedCUSUM(parameters.m_cusum_h, parameters.m_cusum_k, parameters.m_global_nbsamples); + break; + case TutorialMeanDrift::SIGMA_TYPE_TEST: + p_test = new vpStatisticalTestSigma(parameters.m_sigma_h, parameters.m_global_nbsamples); + break; + default: + throw(vpException(vpException::badValue, TutorialMeanDrift::typeTestToString(type) + " is not handled.")); + break; + } + + float signal; + std::cout << "Actual mean of the input signal: " << mean << std::endl; + std::cout << "Actual stdev of the input signal: " << stdev << std::endl; + std::cout << "Mean drift of the input signal: " << mean_drift << std::endl; + + // Initial computation of the mean and stdev of the input signal + for (unsigned int i = 0; i < parameters.m_global_nbsamples; ++i) { + vpGaussRand rndGen(stdev, mean, static_cast(idFrame) * dt); + signal = rndGen(); + p_test->testDownUpwardMeanShift(signal); + ++idFrame; + } + std::cout << "Estimated mean of the input signal: " << p_test->getMean() << std::endl; + std::cout << "Estimated stdev of the input signal: " << p_test->getStdev() << std::endl; + + float mean_eff = mean; + bool hasToRun = true; + vpStatisticalTestAbstract::vpMeanDriftType drift_type = vpStatisticalTestAbstract::NO_MEAN_DRIFT; + while (hasToRun) { + vpGaussRand rndGen(stdev, mean_eff, static_cast(idFrame) * dt); + signal = rndGen(); + plotter.plot(0, 0, idFrame - parameters.m_global_nbsamples, signal); + drift_type = p_test->testDownUpwardMeanShift(signal); + if (drift_type != vpStatisticalTestAbstract::NO_MEAN_DRIFT) { + hasToRun = false; + } + else { + mean_eff += mean_drift; + ++idFrame; + } + } + std::cout << "Test failed at frame: " << idFrame - parameters.m_global_nbsamples << std::endl; + std::cout << "Type of mean drift: " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift_type) << std::endl; + std::cout << "Last signal value: " << signal << std::endl; + if (type == TutorialMeanDrift::EWMA_TYPE_TEST) { + vpStatisticalTestEWMA *p_testEwma = dynamic_cast(p_test); + std::cout << "\tw(t) = " << p_testEwma->getWt() << std::endl; + } + else if (type == TutorialMeanDrift::MEAN_ADJUSTED_CUSUM_TYPE_TEST) { + vpStatisticalTestMeanAdjustedCUSUM *p_testCusum = dynamic_cast(p_test); + std::cout << "\tLower cusum = " << p_testCusum->getTestSignalMinus() << std::endl; + std::cout << "\tUpper cusum = " << p_testCusum->getTestSignalPlus() << std::endl; + } + float limitDown = 0.f, limitUp = 0.f; + p_test->getLimits(limitDown, limitUp); + std::cout << "\tLimit down = " << limitDown << std::endl; + std::cout << "\tLimit up = " << limitUp << std::endl; + std::cout << "End of test on synthetic data. Press enter to leave." << std::endl; + std::cin.get(); + return EXIT_SUCCESS; +} + +int main(int argc, char *argv[]) +{ + TutorialMeanDrift::TypeTest opt_typeTest = TutorialMeanDrift::EWMA_TYPE_TEST; + TutorialMeanDrift::ParametersForAlgo parameters; + float opt_mean = 6.f; + float opt_meandrift = 0.1f; + float opt_stdev = 1.f; + + int i = 1; + while (i < argc) { + if ((std::string(argv[i]) == "--test") && ((i + 1) < argc)) { + opt_typeTest = TutorialMeanDrift::typeTestFromString(argv[i + 1]); + ++i; + } + else if ((std::string(argv[i]) == "--nb-samples") && ((i + 1) < argc)) { + parameters.m_global_nbsamples = std::atoi(argv[i + 1]); + ++i; + } + else if ((std::string(argv[i]) == "--mean") && ((i + 1) < argc)) { + opt_mean = std::atof(argv[i + 1]); + ++i; + } + else if ((std::string(argv[i]) == "--mean-drift") && ((i + 1) < argc)) { + opt_meandrift = std::atof(argv[i + 1]); + ++i; + } + else if ((std::string(argv[i]) == "--stdev") && ((i + 1) < argc)) { + opt_stdev = std::atof(argv[i + 1]); + ++i; + } + else if ((std::string(argv[i]) == "--cusum-h") && ((i + 1) < argc)) { + parameters.m_cusum_h = std::atof(argv[i + 1]); + ++i; + } + else if ((std::string(argv[i]) == "--cusum-k") && ((i + 1) < argc)) { + parameters.m_cusum_k = std::atof(argv[i + 1]); + ++i; + } + else if ((std::string(argv[i]) == "--ewma-alpha") && ((i + 1) < argc)) { + parameters.m_ewma_alpha = std::atof(argv[i + 1]); + ++i; + } + else if ((std::string(argv[i]) == "--hinkley-alpha") && ((i + 1) < argc)) { + parameters.m_hinkley_alpha = std::atof(argv[i + 1]); + ++i; + } + else if ((std::string(argv[i]) == "--hinkley-delta") && ((i + 1) < argc)) { + parameters.m_hinkley_delta = std::atof(argv[i + 1]); + ++i; + } + else if ((std::string(argv[i]) == "--sigma-h") && ((i + 1) < argc)) { + parameters.m_sigma_h = std::atof(argv[i + 1]); + ++i; + } + else if ((std::string(argv[i]) == "--help") || (std::string(argv[i]) == "-h")) { + std::cout << "\nSYNOPSIS " << std::endl + << argv[0] + << " [--test ]" + << " [--nb-samples ]" + << " [--mean ]" + << " [--mean-drift ]" + << " [--stdev ]" + << " [--cusum-h ]" + << " [--cusum-k ]" + << " [--ewma-alpha ]" + << " [--hinkley-alpha <]0; inf[>]" + << " [--hinkley-delta <]0; inf[>]" + << " [--sigma-h ]" + << " [--help,-h]" << std::endl; + std::cout << "\nOPTIONS " << std::endl + << " --test " << std::endl + << " Type of test to perform on the data." << std::endl + << " Available values: " << TutorialMeanDrift::getAvailableTypeTest() << std::endl + << std::endl + << " --nb-samples " << std::endl + << " Number of samples to compute the mean and standard deviation of the monitored signal." << std::endl + << " Default: " << parameters.m_global_nbsamples << std::endl + << std::endl + << " --mean " << std::endl + << " Mean of the signal." << std::endl + << " Default: " << opt_mean<< std::endl + << std::endl + << " --mean-drift " << std::endl + << " Mean drift for the synthetic data." << std::endl + << " Default: " << opt_meandrift << std::endl + << std::endl + << " --stdev " << std::endl + << " Standard deviation of the signal." << std::endl + << " Default: " << opt_stdev << std::endl + << std::endl + << " --cusum-h " << std::endl + << " The alarm factor that permits to the CUSUM test to determine when the process is out of control" << std::endl + << " from the standard deviation of the signal." << std::endl + << " Default: " << parameters.m_cusum_h << std::endl + << std::endl + << " --cusum-k " << std::endl + << " The factor that permits to determine the slack of the CUSUM test, " << std::endl + << " i.e. the minimum value of the jumps we want to detect, from the standard deviation of the signal." << std::endl + << " Default: " << parameters.m_cusum_k << std::endl + << std::endl + << " --ewma-alpha " << std::endl + << " Forgetting factor for the Exponential Weighted Moving Average (EWMA)." << std::endl + << " Default: " << parameters.m_ewma_alpha << std::endl + << std::endl + << " --hinkley-alpha " << std::endl + << " The alarm threshold indicating that a mean drift occurs for the Hinkley's test." << std::endl + << " Default: " << parameters.m_hinkley_alpha << std::endl + << std::endl + << " --hinkley-delta " << std::endl + << " Detection threshold indicating minimal magnitude we want to detect for the Hinkley's test." << std::endl + << " Default: " << parameters.m_hinkley_delta << std::endl + << std::endl + << " --sigma-h " << std::endl + << " The alarm factor of the sigma test." << std::endl + << " Default: " << parameters.m_sigma_h << std::endl + << std::endl + << " --help, -h" << std::endl + << " Display this helper message." << std::endl + << std::endl; + return EXIT_SUCCESS; + } + else { + std::cout << "\nERROR " << std::endl << " Unknown option " << argv[i] << std::endl; + return EXIT_FAILURE; + } + ++i; + } + + return testOnSynthetic(opt_typeTest, parameters, opt_mean, opt_meandrift, opt_stdev); +} From f1b1dedaedcddf3fb96598179dd8014742cd2c0b Mon Sep 17 00:00:00 2001 From: rlagneau Date: Thu, 7 Mar 2024 13:16:02 +0100 Subject: [PATCH 02/12] [DOC] Added Doxygen file tag in headers --- modules/core/include/visp3/core/vpStatisticalTestAbstract.h | 4 ++++ modules/core/include/visp3/core/vpStatisticalTestEWMA.h | 4 ++++ modules/core/include/visp3/core/vpStatisticalTestHinkley.h | 4 ++++ .../include/visp3/core/vpStatisticalTestMeanAdjustedCUSUM.h | 4 ++++ modules/core/include/visp3/core/vpStatisticalTestSigma.h | 4 ++++ 5 files changed, 20 insertions(+) diff --git a/modules/core/include/visp3/core/vpStatisticalTestAbstract.h b/modules/core/include/visp3/core/vpStatisticalTestAbstract.h index a365125c71..f7e885713a 100644 --- a/modules/core/include/visp3/core/vpStatisticalTestAbstract.h +++ b/modules/core/include/visp3/core/vpStatisticalTestAbstract.h @@ -29,6 +29,10 @@ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * *****************************************************************************/ +/*! + * \file vpStatisticalTestAbstract.h + * \brief Base class for Statistical Process Control methods implementation. + */ #ifndef _vpStatisticalTestAbstract_h_ #define _vpStatisticalTestAbstract_h_ diff --git a/modules/core/include/visp3/core/vpStatisticalTestEWMA.h b/modules/core/include/visp3/core/vpStatisticalTestEWMA.h index 3bfa0346bf..866c0fe274 100644 --- a/modules/core/include/visp3/core/vpStatisticalTestEWMA.h +++ b/modules/core/include/visp3/core/vpStatisticalTestEWMA.h @@ -29,6 +29,10 @@ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * *****************************************************************************/ +/*! + * \file vpStatisticalTestEWMA.h + * \brief Statistical Process Control Exponentially Weighted Moving Average implementation. + */ #ifndef _vpStatisticalTestEWMA_h_ #define _vpStatisticalTestEWMA_h_ diff --git a/modules/core/include/visp3/core/vpStatisticalTestHinkley.h b/modules/core/include/visp3/core/vpStatisticalTestHinkley.h index 0b34bee22b..92303a4378 100644 --- a/modules/core/include/visp3/core/vpStatisticalTestHinkley.h +++ b/modules/core/include/visp3/core/vpStatisticalTestHinkley.h @@ -29,6 +29,10 @@ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * *****************************************************************************/ +/*! + * \file vpStatisticalTestHinkley.h + * \brief Statistical Process Control Hinkley's test implementation. + */ #ifndef _vpStatisticalTestHinkley_h_ #define _vpStatisticalTestHinkley_h_ diff --git a/modules/core/include/visp3/core/vpStatisticalTestMeanAdjustedCUSUM.h b/modules/core/include/visp3/core/vpStatisticalTestMeanAdjustedCUSUM.h index 2f514eee6d..b1fee06431 100644 --- a/modules/core/include/visp3/core/vpStatisticalTestMeanAdjustedCUSUM.h +++ b/modules/core/include/visp3/core/vpStatisticalTestMeanAdjustedCUSUM.h @@ -29,6 +29,10 @@ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * *****************************************************************************/ +/*! + * \file vpStatisticalTestMeanAdjustedCUSUM.h + * \brief Statistical Process Control mean adjusted CUSUM implementation. + */ #ifndef _vpStatisticalTestMeanAdjustedCUSUM_h_ #define _vpStatisticalTestMeanAdjustedCUSUM_h_ diff --git a/modules/core/include/visp3/core/vpStatisticalTestSigma.h b/modules/core/include/visp3/core/vpStatisticalTestSigma.h index 72036c860e..086b866a5b 100644 --- a/modules/core/include/visp3/core/vpStatisticalTestSigma.h +++ b/modules/core/include/visp3/core/vpStatisticalTestSigma.h @@ -29,6 +29,10 @@ * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. * *****************************************************************************/ +/*! + * \file vpStatisticalTestSigma.h + * \brief Statistical Process Control sigma test implementation. + */ #ifndef _vpStatisticalTestSigma_h_ #define _vpStatisticalTestSigma_h_ From e1709037d9782ab27e1ee097327f5f7f5ec2b1ed Mon Sep 17 00:00:00 2001 From: rlagneau Date: Thu, 7 Mar 2024 15:48:38 +0100 Subject: [PATCH 03/12] [CORPS] Added Shehwhart's test, updated tutorial and added auto mode to Hinkley's test --- .../visp3/core/vpStatisticalTestAbstract.h | 75 ++-- .../visp3/core/vpStatisticalTestEWMA.h | 26 +- .../visp3/core/vpStatisticalTestHinkley.h | 103 +++-- .../core/vpStatisticalTestMeanAdjustedCUSUM.h | 19 +- .../visp3/core/vpStatisticalTestShewhart.h | 207 ++++++++++ .../visp3/core/vpStatisticalTestSigma.h | 27 +- .../math/misc/vpStatisticalTestAbstract.cpp | 73 +++- .../src/math/misc/vpStatisticalTestEWMA.cpp | 8 +- .../math/misc/vpStatisticalTestHinkley.cpp | 102 ++++- .../vpStatisticalTestMeanAdjustedCUSUM.cpp | 8 +- .../math/misc/vpStatisticalTestShewhart.cpp | 308 +++++++++++++++ .../src/math/misc/vpStatisticalTestSigma.cpp | 16 +- tutorial/mean-drift/tutorial-meandrift.cpp | 353 ++++++++++++++++-- 13 files changed, 1180 insertions(+), 145 deletions(-) create mode 100644 modules/core/include/visp3/core/vpStatisticalTestShewhart.h create mode 100644 modules/core/src/math/misc/vpStatisticalTestShewhart.cpp diff --git a/modules/core/include/visp3/core/vpStatisticalTestAbstract.h b/modules/core/include/visp3/core/vpStatisticalTestAbstract.h index f7e885713a..ac5d7867ae 100644 --- a/modules/core/include/visp3/core/vpStatisticalTestAbstract.h +++ b/modules/core/include/visp3/core/vpStatisticalTestAbstract.h @@ -47,18 +47,26 @@ /** * \ingroup group_core_math_tools * \brief Base class for methods detecting the drift of the mean of a process. + * + * To detect only downward drifts of the input signal \f$ s(t) \f$ use + * testDownwardMeanDrift().To detect only upward drifts in \f$ s(t) \f$ use + * testUpwardMeanDrift(). To detect both, downward and upward drifts use + * testDownUpwardMeanDrift(). */ class VISP_EXPORT vpStatisticalTestAbstract { public: /** - * \brief Enum that indicates if a drift of the mean occured. + * \brief Enum that indicates if a drift of the mean occurred. */ typedef enum vpMeanDriftType { - NO_MEAN_DRIFT = 0, /*!< No mean drift occured*/ - MEAN_DRIFT_DOWNWARD = 1, /*!< A downward drift of the mean occured.*/ - MEAN_DRIFT_UPWARD = 2 /*!< An upward drift of the mean occured.*/ + MEAN_DRIFT_NONE = 0, /*!< No mean drift occurred*/ + MEAN_DRIFT_DOWNWARD = 1, /*!< A downward drift of the mean occurred.*/ + MEAN_DRIFT_UPWARD = 2, /*!< An upward drift of the mean occurred.*/ + MEAN_DRIFT_BOTH = 3, /*!< Both an aupward and a downward drifts occurred.*/ + MEAN_DRIFT_COUNT = 4, + MEAN_DRIFT_UNKNOWN = MEAN_DRIFT_COUNT } vpMeanDriftType; /** @@ -69,6 +77,25 @@ class VISP_EXPORT vpStatisticalTestAbstract */ static std::string vpMeanDriftTypeToString(const vpMeanDriftType &type); + /** + * \brief Cast a string into a \b vpMeanDriftType. + * + * \param[in] name The name of the mean drift. + * \return vpMeanDriftType The corresponding \b vpMeanDriftType. + */ + static vpMeanDriftType vpMeanDriftTypeFromString(const std::string &name); + + /** + * \brief Get the list of available \b vpMeanDriftType objects that are handled. + * + * \param[in] prefix The prefix that should be placed before the list. + * \param[in] sep The separator between each element of the list. + * \param[in] suffix The suffix that should terminate the list. + * \return std::string The list of handled type of process tests, presented as a string. + */ + static std::string getAvailableMeanDriftType(const std::string &prefix = "<", const std::string &sep = " , ", + const std::string &suffix = ">"); + /** * \brief Print the message corresponding to the type of mean drift. * @@ -89,22 +116,22 @@ class VISP_EXPORT vpStatisticalTestAbstract float m_sumForMean; /*!< Sum of the samples used to compute the mean and standard deviation.*/ /** - * \brief Detects if a downward mean drift occured. + * \brief Detects if a downward mean drift occurred. * - * \return \b vpMeanDriftType::MEAN_DRIFT_DOWNWARD if a downward mean drift occured, \b vpMeanDriftType::NO_MEAN_DRIFT otherwise. + * \return \b vpMeanDriftType::MEAN_DRIFT_DOWNWARD if a downward mean drift occurred, \b vpMeanDriftType::MEAN_DRIFT_NONE otherwise. * - * \sa detectUpwardMeanShift() + * \sa detectUpwardMeanDrift() */ - virtual vpMeanDriftType detectDownwardMeanShift() = 0; + virtual vpMeanDriftType detectDownwardMeanDrift() = 0; /** - * \brief Detects if a upward mean drift occured. + * \brief Detects if a upward mean drift occurred. * - * \return \b vpMeanDriftType::MEAN_DRIFT_UPWARD if an upward mean drift occured, \b vpMeanDriftType::NO_MEAN_DRIFT otherwise. + * \return \b vpMeanDriftType::MEAN_DRIFT_UPWARD if an upward mean drift occurred, \b vpMeanDriftType::MEAN_DRIFT_NONE otherwise. * - * \sa detectDownwardMeanShift() + * \sa detectDownwardMeanDrift() */ - virtual vpMeanDriftType detectUpwardMeanShift() = 0; + virtual vpMeanDriftType detectUpwardMeanDrift() = 0; /** * \brief Update \b m_s and if enough values are available, compute the mean, the standard @@ -203,37 +230,37 @@ class VISP_EXPORT vpStatisticalTestAbstract void setNbSamplesForStat(const unsigned int &nbSamples); /** - * \brief Test if a downward or an upward mean drift occured + * \brief Test if a downward or an upward mean drift occurred * according to the new value of the signal. * * \param[in] signal The new value of the signal. - * \return vpMeanDriftType The type of mean drift that occured. + * \return vpMeanDriftType The type of mean drift that occurred. * - * \sa testDownwardMeanShift() testUpwardMeanShift() + * \sa testDownwardMeanDrift() testUpwardMeanDrift() */ - vpMeanDriftType testDownUpwardMeanShift(const float &signal); + vpMeanDriftType testDownUpwardMeanDrift(const float &signal); /** - * \brief Test if a downward mean drift occured + * \brief Test if a downward mean drift occurred * according to the new value of the signal. * * \param[in] signal The new value of the signal. - * \return vpMeanDriftType The type of mean drift that occured. + * \return vpMeanDriftType The type of mean drift that occurred. * - * \sa testUpwardMeanShift() + * \sa testUpwardMeanDrift() */ - vpMeanDriftType testDownwardMeanShift(const float &signal); + vpMeanDriftType testDownwardMeanDrift(const float &signal); /** - * \brief Test if an upward mean drift occured + * \brief Test if an upward mean drift occurred * according to the new value of the signal. * * \param[in] signal The new value of the signal. - * \return vpMeanDriftType The type of mean drift that occured. + * \return vpMeanDriftType The type of mean drift that occurred. * - * \sa testDownwardMeanShift() + * \sa testDownwardMeanDrift() */ - vpMeanDriftType testUpwardMeanShift(const float &signal); + vpMeanDriftType testUpwardMeanDrift(const float &signal); }; #endif diff --git a/modules/core/include/visp3/core/vpStatisticalTestEWMA.h b/modules/core/include/visp3/core/vpStatisticalTestEWMA.h index 866c0fe274..b2df53beaa 100644 --- a/modules/core/include/visp3/core/vpStatisticalTestEWMA.h +++ b/modules/core/include/visp3/core/vpStatisticalTestEWMA.h @@ -58,25 +58,29 @@ class VISP_EXPORT vpStatisticalTestEWMA : public vpStatisticalTestAbstract virtual void computeDeltaAndLimits(); /** - * \brief Detects if a downward jump occured on the mean. + * \brief Detects if a downward mean drift occured. * - * \return downwardJump if a downward jump occured, noJump otherwise. + * \return \b vpMeanDriftType::MEAN_DRIFT_DOWNWARD if a downward mean drift occured, \b vpMeanDriftType::MEAN_DRIFT_NONE otherwise. + * + * \sa detectUpwardMeanDrift() */ #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) - virtual vpMeanDriftType detectDownwardMeanShift() override; + virtual vpMeanDriftType detectDownwardMeanDrift() override; #else - virtual vpMeanDriftType detectDownwardMeanShift(); + virtual vpMeanDriftType detectDownwardMeanDrift(); #endif -/** - * \brief Detects if a upward jump occured on the mean. - * - * \return upwardJump if a upward jump occured, noJump otherwise. - */ + /** + * \brief Detects if an upward mean drift occured on the mean. + * + * \return \b vpMeanDriftType::MEAN_DRIFT_UPWARD if an upward mean drift occured, \b vpMeanDriftType::MEAN_DRIFT_NONE otherwise. + * + * \sa detectDownwardMeanDrift() + */ #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) - virtual vpMeanDriftType detectUpwardMeanShift() override; + virtual vpMeanDriftType detectUpwardMeanDrift() override; #else - virtual vpMeanDriftType detectUpwardMeanShift(); + virtual vpMeanDriftType detectUpwardMeanDrift(); #endif /** diff --git a/modules/core/include/visp3/core/vpStatisticalTestHinkley.h b/modules/core/include/visp3/core/vpStatisticalTestHinkley.h index 92303a4378..e07d4b1591 100644 --- a/modules/core/include/visp3/core/vpStatisticalTestHinkley.h +++ b/modules/core/include/visp3/core/vpStatisticalTestHinkley.h @@ -76,9 +76,9 @@ A upward drift is detected if \f$ T_k - N_k > \alpha \f$. To detect only downward drifts in \f$ s(t) \f$ use - testDownwardJump().To detect only upward drifts in \f$ s(t) \f$ use - testUpwardJump(). To detect both, downward and upward drifts use - testDownUpwardJump(). + testDownwardMeanDrift().To detect only upward drifts in \f$ s(t) \f$ use + testUpwardMeanDrift(). To detect both, downward and upward drifts use + testDownUpwardMeanDrift(). If a drift is detected, the drift location is given by the last instant \f$k^{'}\f$ when \f$ M_{k^{'}} - S_{k^{'}} = 0 \f$, or \f$ T_{k^{'}} - @@ -93,6 +93,15 @@ class VISP_EXPORT vpStatisticalTestHinkley : public vpStatisticalTestAbstract float m_Mk; /*!< Maximum of the test signal for downward mean drift \f$S_k\f$ .*/ float m_Tk; /*!< Test signal for upward mean drift.*/ float m_Nk; /*!< Minimum of the test signal for upward mean drift \f$T_k\f$*/ + bool m_computeDeltaAndAlpha; /*!< If true, compute \f$\delta\f$ and \f$\alpha\f$ from the standard deviation, + the alarm factor and the detection factor.*/ + float m_h; /*!< The alarm factor, that permits to compute \f$\alpha\f$ from the standard deviation of the signal.*/ + float m_k; /*!< The detection factor, that permits to compute \f$\delta\f$ from the standard deviation of the signal.*/ + + /** + * \brief Compute \f$\delta\f$ and \f$\alpha\f$ from the standard deviation of the signal. + */ + virtual void computeAlphaDelta(); /** * \brief Compute the mean value \f$m_0\f$ of the signal. The mean value must be @@ -127,25 +136,39 @@ class VISP_EXPORT vpStatisticalTestHinkley : public vpStatisticalTestAbstract void computeNk(); /** - * \brief Detects if a downward mean drift occured. + * \brief Detects if a downward mean drift occurred. * - * \return \b vpMeanDriftType::MEAN_DRIFT_DOWNWARD if a downward mean drift occured, \b vpMeanDriftType::NO_MEAN_DRIFT otherwise. + * \return \b vpMeanDriftType::MEAN_DRIFT_DOWNWARD if a downward mean drift occurred, \b vpMeanDriftType::MEAN_DRIFT_NONE otherwise. */ #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) - virtual vpMeanDriftType detectDownwardMeanShift() override; + virtual vpMeanDriftType detectDownwardMeanDrift() override; #else - virtual vpMeanDriftType detectDownwardMeanShift(); + virtual vpMeanDriftType detectDownwardMeanDrift(); #endif -/** - * \brief Detects if a upward mean drift occured. - * - * \return \b vpMeanDriftType::MEAN_DRIFT_UPWARD if an upward mean drift occured, \b vpMeanDriftType::NO_MEAN_DRIFT otherwise. - */ + /** + * \brief Detects if an upward mean drift occured on the mean. + * + * \return \b vpMeanDriftType::MEAN_DRIFT_UPWARD if an upward mean drift occured, \b vpMeanDriftType::MEAN_DRIFT_NONE otherwise. + * + * \sa detectDownwardMeanDrift() + */ #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) - virtual vpMeanDriftType detectUpwardMeanShift() override; + virtual vpMeanDriftType detectUpwardMeanDrift() override; #else - virtual vpMeanDriftType detectUpwardMeanShift(); + virtual vpMeanDriftType detectUpwardMeanDrift(); +#endif + + /** + * \brief Update m_s and if enough values are available, compute the mean, the standard + * deviation and the limits. + * + * \param[in] signal The new value of the signal to monitor. + */ +#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) + virtual bool updateStatistics(const float &signal) override; +#else + virtual bool updateStatistics(const float &signal); #endif /** @@ -181,6 +204,28 @@ class VISP_EXPORT vpStatisticalTestHinkley : public vpStatisticalTestAbstract */ vpStatisticalTestHinkley(const float &alpha, const float &delta, const unsigned int &nbSamplesForInit = 30); + /** + * \brief Construct a new vpStatisticalTestHinkley object. \f$\alpha\f$ and \f$\delta\f$ will be computed + * from the standard deviation of the signal. + * + * \param[in] h : the alarm factor that permits to compute \f$\alpha\f$ from the standard deviation. + * \param[in] k : the detection factor that permits to compute \f$\delta\f$ from the standard deviation. + * \param[in] computeAlphaDeltaFromStdev : must be equal to true, otherwise throw a vpException. + * \param[in] nbSamplesForInit : number of signal samples to initialize the mean of the signal. + */ + vpStatisticalTestHinkley(const float &h, const float &k, const bool &computeAlphaDeltaFromStdev, const unsigned int &nbSamplesForInit = 30); + + /** + * \brief Construct a new vpStatisticalTestHinkley object. \f$\alpha\f$ and \f$\delta\f$ will be computed + * from the standard deviation of the signal. + * + * \param[in] h : the alarm factor that permits to compute \f$\alpha\f$ from the standard deviation. + * \param[in] k : the detection factor that permits to compute \f$\delta\f$ from the standard deviation. + * \param[in] mean : the expected mean of the signal. + * \param[in] stdev : the expected standard deviation of the signal. + */ + vpStatisticalTestHinkley(const float &h, const float &k, const float &mean, const float &stdev); + /** * \brief Destroy the vpStatisticalTestHinkley object. */ @@ -228,14 +273,6 @@ class VISP_EXPORT vpStatisticalTestHinkley : public vpStatisticalTestAbstract */ void init(); - /** - * \brief Initialise the Hinkley's test by setting the mean signal value - * \f$m_0\f$ to the expected value and \f$S_k, M_k, T_k, N_k\f$ to 0. - * - * \param[in] mean The expected value of the mean. - */ - void init(const float &mean); - /** * \brief Call init() to initialise the Hinkley's test and set \f$\alpha\f$ * and \f$\delta\f$ thresholds. @@ -246,6 +283,17 @@ class VISP_EXPORT vpStatisticalTestHinkley : public vpStatisticalTestAbstract */ void init(const float &alpha, const float &delta, const unsigned int &nbSamplesForInit); + /** + * \brief (Re)Initialize a new vpStatisticalTestHinkley object. \f$\alpha\f$ and \f$\delta\f$ will be computed + * from the standard deviation of the signal. + * + * \param[in] h : the alarm factor that permits to compute \f$\alpha\f$ from the standard deviation. + * \param[in] k : the detection factor that permits to compute \f$\delta\f$ from the standard deviation. + * \param[in] computeAlphaDeltaFromStdev : must be equal to true, otherwise throw a vpException. + * \param[in] nbSamplesForInit : number of signal samples to initialize the mean of the signal. + */ + void init(const float &h, const float &k, const bool &computeAlphaDeltaFromStdev, const unsigned int &nbSamplesForInit); + /** * \brief Call init() to initialise the Hinkley's test, set \f$\alpha\f$ * and \f$\delta\f$ thresholds, and the mean of the signal \f$m_0\f$. @@ -256,6 +304,17 @@ class VISP_EXPORT vpStatisticalTestHinkley : public vpStatisticalTestAbstract */ void init(const float &alpha, const float &delta, const float &mean); + /** + * \brief (Re)Initialize a new vpStatisticalTestHinkley object. \f$\alpha\f$ and \f$\delta\f$ will be computed + * from the standard deviation of the signal. + * + * \param[in] h : the alarm factor that permits to compute \f$\alpha\f$ from the standard deviation. + * \param[in] k : the detection factor that permits to compute \f$\delta\f$ from the standard deviation. + * \param[in] mean : the expected mean of the signal. + * \param[in] stdev : the expected standard deviation of the signal. + */ + void init(const float &h, const float &k, const float &mean, const float &stdev); + /** * \brief Set the drift minimal magnitude that we want to detect. * diff --git a/modules/core/include/visp3/core/vpStatisticalTestMeanAdjustedCUSUM.h b/modules/core/include/visp3/core/vpStatisticalTestMeanAdjustedCUSUM.h index b1fee06431..5bdd6f06f5 100644 --- a/modules/core/include/visp3/core/vpStatisticalTestMeanAdjustedCUSUM.h +++ b/modules/core/include/visp3/core/vpStatisticalTestMeanAdjustedCUSUM.h @@ -61,21 +61,28 @@ class VISP_EXPORT vpStatisticalTestMeanAdjustedCUSUM : public vpStatisticalTestA */ virtual void computeDeltaAndLimits(); + /** + * \brief Detects if a downward mean drift occured. + * + * \return \b vpMeanDriftType::MEAN_DRIFT_DOWNWARD if a downward mean drift occured, \b vpMeanDriftType::MEAN_DRIFT_NONE otherwise. + * + * \sa detectUpwardMeanDrift() + */ #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) - virtual vpMeanDriftType detectDownwardMeanShift() override; + virtual vpMeanDriftType detectDownwardMeanDrift() override; #else - virtual vpMeanDriftType detectDownwardMeanShift(); + virtual vpMeanDriftType detectDownwardMeanDrift(); #endif /** - * \brief Detects if a upward jump occured on the mean. + * \brief Detects if a upward jump occurred on the mean. * - * \return upwardJump if a upward jump occured, noJump otherwise. + * \return upwardJump if a upward jump occurred, noJump otherwise. */ #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) - virtual vpMeanDriftType detectUpwardMeanShift() override; + virtual vpMeanDriftType detectUpwardMeanDrift() override; #else - virtual vpMeanDriftType detectUpwardMeanShift(); + virtual vpMeanDriftType detectUpwardMeanDrift(); #endif /** diff --git a/modules/core/include/visp3/core/vpStatisticalTestShewhart.h b/modules/core/include/visp3/core/vpStatisticalTestShewhart.h new file mode 100644 index 0000000000..22e9d66a3d --- /dev/null +++ b/modules/core/include/visp3/core/vpStatisticalTestShewhart.h @@ -0,0 +1,207 @@ +/**************************************************************************** + * + * ViSP, open source Visual Servoing Platform software. + * Copyright (C) 2005 - 2023 by Inria. All rights reserved. + * + * This software is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * See the file LICENSE.txt at the root directory of this source + * distribution for additional information about the GNU GPL. + * + * For using ViSP with software that can not be combined with the GNU + * GPL, please contact Inria about acquiring a ViSP Professional + * Edition License. + * + * See https://visp.inria.fr for more information. + * + * This software was developed at: + * Inria Rennes - Bretagne Atlantique + * Campus Universitaire de Beaulieu + * 35042 Rennes Cedex + * France + * + * If you have questions regarding the use of this file, please contact + * Inria at visp@inria.fr + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * +*****************************************************************************/ +/*! + * \file vpStatisticalTestShewhart.h + * \brief Statistical Process Control Shewhart's test implementation. + */ + +#ifndef _vpStatisticalTestShewhartTest_h_ +#define _vpStatisticalTestShewhartTest_h_ + +#include + +#include +#include + +/** + * \ingroup group_core_math_tools + * \brief Class that permits a Shewhart test. + */ + +class VISP_EXPORT vpStatisticalTestShewhart : public vpStatisticalTestSigma +{ +public: + typedef enum vpWecoRulesAlarm + { + THREE_SIGMA_WECO = 0, + TWO_SIGMA_WECO = 1, + ONE_SIGMA_WECO = 2, + SAME_SIDE_WECO = 3, + NONE_WECO = 4, + COUNT_WECO = 5 + } vpWecoRulesAlarm; + + static std::string vpWecoRulesAlarmToString(const vpWecoRulesAlarm &alarm); + + static const bool CONST_ALL_WECO_ACTIVATED[COUNT_WECO - 1]; + +protected: + static const int NB_DATA_SIGNAL = 8; + unsigned int m_nbDataInBuffer; /*!< Indicate how many data are available in the circular buffer.*/ + float m_signal[NB_DATA_SIGNAL]; /*!< The last values of the signal.*/ + bool m_activateWECOrules; /*!< If true, activate the WECO rules (NB: it increases the sensitivity of the Shewhart + control chart but the false alarm frequency is also increased.)*/ + bool m_activatedWECOrules[COUNT_WECO - 1]; /*!< The WECO rules that are activated. The more are activated, the higher the + sensitivity of the Shewhart control chart is but the higher the false + alarm frequency is.*/ + int m_idCurrentData; /*!< The index of the current data in m_signal.*/ + vpWecoRulesAlarm m_alarm; /*!< The type of alarm raised due to WECO rules.*/ + float m_oneSigmaNegLim; /*!< The mean - sigma lower threshold.*/ + float m_oneSigmaPosLim; /*!< The mean + sigma lower threshold.*/ + float m_twoSigmaNegLim; /*!< The mean - 2 sigma lower threshold.*/ + float m_twoSigmaPosLim; /*!< The mean + 2 sigma lower threshold.*/ + + /** + * \brief Compute the upper and lower limits of the test signal. + */ +#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) + virtual void computeLimits() override; +#else + virtual void computeLimits(); +#endif + +/** + * \brief Detects if a downward mean drift occured. + * + * \return \b vpMeanDriftType::MEAN_DRIFT_DOWNWARD if a downward mean drift occured, \b vpMeanDriftType::MEAN_DRIFT_NONE otherwise. + * + * \sa detectUpwardMeanDrift() + */ +#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) + virtual vpMeanDriftType detectDownwardMeanDrift() override; +#else + virtual vpMeanDriftType detectDownwardMeanDrift(); +#endif + + /** + * \brief Detects if an upward mean drift occured on the mean. + * + * \return \b vpMeanDriftType::MEAN_DRIFT_UPWARD if an upward mean drift occured, \b vpMeanDriftType::MEAN_DRIFT_NONE otherwise. + * + * \sa detectDownwardMeanDrift() + */ +#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) + virtual vpMeanDriftType detectUpwardMeanDrift() override; +#else + virtual vpMeanDriftType detectUpwardMeanDrift(); +#endif + + /** + * \brief Update m_s and if enough values are available, compute the mean, the standard + * deviation and the limits. + * + * \param[in] signal The new value of the signal to monitor. + */ +#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) + virtual bool updateStatistics(const float &signal) override; +#else + virtual bool updateStatistics(const float &signal); +#endif + + /** + * \brief Update the test signals. + * + * \param[in] signal The new value of the signal to monitor. + */ +#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) + virtual void updateTestSignals(const float &signal) override; +#else + virtual void updateTestSignals(const float &signal); +#endif +public: + /** + * \brief Construct a new vpStatisticalTestShewhart object. + * + * \param[in] activateWECOrules If true, activate the WECO rules (NB: it increases the sensitivity of the Shewhart + * control chart but the false alarm frequency is also increased.) + * \param[in] nbSamplesForStats The number of samples to compute the statistics of the signal. + */ + vpStatisticalTestShewhart(const bool &activateWECOrules = true, const bool activatedRules[COUNT_WECO - 1] = CONST_ALL_WECO_ACTIVATED, const unsigned int &nbSamplesForStats = 30); + + /** + * \brief Construct a new vpStatisticalTestShewhart object. + * + * \param[in] activateWECOrules If true, activate the WECO rules (NB: it increases the sensitivity of the Shewhart + * control chart but the false alarm frequency is also increased.) + * \param[in] mean The expected mean of the signal. + * \param[in] stdev The expected standard deviation of the signal. + */ + vpStatisticalTestShewhart(const bool &activateWECOrules, const bool activatedRules[COUNT_WECO - 1], const float &mean, const float &stdev); + + /** + * \brief Get the alarm raised by the last test due to the WECO rules. + * + * \return vpWecoRulesAlarm The type of raised alarm. + */ + vpWecoRulesAlarm getAlarm() const + { + return m_alarm; + } + + /** + * \brief Get the last value of the signal. + * + * \return float The signal. + */ + inline float getSignal() const + { + return m_signal[m_idCurrentData]; + } + + /** + * \brief Get the NB_DATA_SIGNAL last signal values, sorted from the latest [0] to the newest [NB_DATA_SIGNAL - 1]. + * + * \return std::vector The last NB_DATA_SIGNAL values. + */ + std::vector getSignals() const; + + /** + * \brief (Re)Initialize the test. + * + * \param[in] activateWECOrules If true, activate the WECO rules (NB: it increases the sensitivity of the Shewhart + * control chart but the false alarm frequency is also increased.) + * \param[in] nbSamplesForStats The number of samples to compute the statistics of the signal. + */ + void init(const bool &activateWECOrules, const bool activatedRules[COUNT_WECO - 1] = CONST_ALL_WECO_ACTIVATED, const unsigned int &nbSamplesForStats = 30); + + /** + * \brief (Re)Initialize the test. + * + * \param[in] activateWECOrules If true, activate the WECO rules (NB: it increases the sensitivity of the Shewhart + * control chart but the false alarm frequency is also increased.) + * \param[in] mean The expected mean of the signal. + * \param[in] stdev The expected standard deviation of the signal. + */ + void init(const bool &activateWECOrules, const bool activatedRules[COUNT_WECO - 1], const float &mean, const float &stdev); +}; + +#endif diff --git a/modules/core/include/visp3/core/vpStatisticalTestSigma.h b/modules/core/include/visp3/core/vpStatisticalTestSigma.h index 086b866a5b..94476df584 100644 --- a/modules/core/include/visp3/core/vpStatisticalTestSigma.h +++ b/modules/core/include/visp3/core/vpStatisticalTestSigma.h @@ -58,21 +58,30 @@ class VISP_EXPORT vpStatisticalTestSigma : public vpStatisticalTestAbstract */ virtual void computeLimits(); + /** + * \brief Detects if a downward mean drift occured. + * + * \return \b vpMeanDriftType::MEAN_DRIFT_DOWNWARD if a downward mean drift occured, \b vpMeanDriftType::MEAN_DRIFT_NONE otherwise. + * + * \sa detectUpwardMeanDrift() + */ #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) - virtual vpMeanDriftType detectDownwardMeanShift() override; + virtual vpMeanDriftType detectDownwardMeanDrift() override; #else - virtual vpMeanDriftType detectDownwardMeanShift(); + virtual vpMeanDriftType detectDownwardMeanDrift(); #endif -/** - * \brief Detects if a upward jump occured on the mean. - * - * \return upwardJump if a upward jump occured, noJump otherwise. - */ + /** + * \brief Detects if an upward mean drift occured on the mean. + * + * \return \b vpMeanDriftType::MEAN_DRIFT_UPWARD if an upward mean drift occured, \b vpMeanDriftType::MEAN_DRIFT_NONE otherwise. + * + * \sa detectDownwardMeanDrift() + */ #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) - virtual vpMeanDriftType detectUpwardMeanShift() override; + virtual vpMeanDriftType detectUpwardMeanDrift() override; #else - virtual vpMeanDriftType detectUpwardMeanShift(); + virtual vpMeanDriftType detectUpwardMeanDrift(); #endif /** diff --git a/modules/core/src/math/misc/vpStatisticalTestAbstract.cpp b/modules/core/src/math/misc/vpStatisticalTestAbstract.cpp index 591674dd77..4986a117b9 100644 --- a/modules/core/src/math/misc/vpStatisticalTestAbstract.cpp +++ b/modules/core/src/math/misc/vpStatisticalTestAbstract.cpp @@ -43,22 +43,56 @@ std::string vpStatisticalTestAbstract::vpMeanDriftTypeToString(const vpStatistic { std::string name; switch (type) { - case NO_MEAN_DRIFT: - name = " No jump"; + case MEAN_DRIFT_NONE: + name = "no_drift"; break; case MEAN_DRIFT_DOWNWARD: - name = " Jump downward"; + name = "downward_drift"; break; case MEAN_DRIFT_UPWARD: - name = " Jump upward"; + name = "upward_drift"; break; + case MEAN_DRIFT_BOTH: + name = "both_drift"; + break; + case MEAN_DRIFT_UNKNOWN: default: - name = " Undefined jump"; + name = "undefined_drift"; break; } return name; } +vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestAbstract::vpMeanDriftTypeFromString(const std::string &name) +{ + vpMeanDriftType result = MEAN_DRIFT_UNKNOWN; + unsigned int count = static_cast(MEAN_DRIFT_COUNT); + unsigned int id = 0; + bool hasNotFound = true; + while ((id < count) && hasNotFound) { + vpMeanDriftType temp = static_cast(id); + if (vpMeanDriftTypeToString(temp) == name) { + result = temp; + hasNotFound = false; + } + ++id; + } + return result; +} + +std::string vpStatisticalTestAbstract::getAvailableMeanDriftType(const std::string &prefix, const std::string &sep, + const std::string &suffix) +{ + std::string msg(prefix); + unsigned int count = static_cast(MEAN_DRIFT_COUNT); + unsigned int lastId = count - 1; + for (unsigned int i = 0; i < lastId; i++) { + msg += vpMeanDriftTypeToString(static_cast(i)) + sep; + } + msg += vpMeanDriftTypeToString(static_cast(lastId)) + suffix; + return msg; +} + void vpStatisticalTestAbstract::print(const vpStatisticalTestAbstract::vpMeanDriftType &type) { std::cout << vpMeanDriftTypeToString(type) << " detected" << std::endl; @@ -163,48 +197,51 @@ void vpStatisticalTestAbstract::setNbSamplesForStat(const unsigned int &nbSample m_s = new float[nbSamples]; } -vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestAbstract::testDownUpwardMeanShift(const float &signal) +vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestAbstract::testDownUpwardMeanDrift(const float &signal) { if (m_areStatisticsComputed) { updateTestSignals(signal); - vpMeanDriftType jumpDown = detectDownwardMeanShift(); - vpMeanDriftType jumpUp = detectUpwardMeanShift(); - if (jumpDown != NO_MEAN_DRIFT) { + vpMeanDriftType jumpDown = detectDownwardMeanDrift(); + vpMeanDriftType jumpUp = detectUpwardMeanDrift(); + if ((jumpDown != MEAN_DRIFT_NONE) && (jumpUp != MEAN_DRIFT_NONE)) { + return MEAN_DRIFT_BOTH; + } + else if (jumpDown != MEAN_DRIFT_NONE) { return jumpDown; } - else if (jumpUp != NO_MEAN_DRIFT) { + else if (jumpUp != MEAN_DRIFT_NONE) { return jumpUp; } else { - return NO_MEAN_DRIFT; + return MEAN_DRIFT_NONE; } } else { updateStatistics(signal); - return NO_MEAN_DRIFT; + return MEAN_DRIFT_NONE; } } -vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestAbstract::testDownwardMeanShift(const float &signal) +vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestAbstract::testDownwardMeanDrift(const float &signal) { if (m_areStatisticsComputed) { updateTestSignals(signal); - return detectDownwardMeanShift(); + return detectDownwardMeanDrift(); } else { updateStatistics(signal); - return NO_MEAN_DRIFT; + return MEAN_DRIFT_NONE; } } -vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestAbstract::testUpwardMeanShift(const float &signal) +vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestAbstract::testUpwardMeanDrift(const float &signal) { if (m_areStatisticsComputed) { updateTestSignals(signal); - return detectUpwardMeanShift(); + return detectUpwardMeanDrift(); } else { updateStatistics(signal); - return NO_MEAN_DRIFT; + return MEAN_DRIFT_NONE; } } diff --git a/modules/core/src/math/misc/vpStatisticalTestEWMA.cpp b/modules/core/src/math/misc/vpStatisticalTestEWMA.cpp index d4dd6a5e28..6cb06fee31 100644 --- a/modules/core/src/math/misc/vpStatisticalTestEWMA.cpp +++ b/modules/core/src/math/misc/vpStatisticalTestEWMA.cpp @@ -47,23 +47,23 @@ void vpStatisticalTestEWMA::computeDeltaAndLimits() m_limitUp = m_mean + delta; } -vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestEWMA::detectDownwardMeanShift() +vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestEWMA::detectDownwardMeanDrift() { if (m_wt <= m_limitDown) { return MEAN_DRIFT_DOWNWARD; } else { - return NO_MEAN_DRIFT; + return MEAN_DRIFT_NONE; } } -vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestEWMA::detectUpwardMeanShift() +vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestEWMA::detectUpwardMeanDrift() { if (m_wt >= m_limitUp) { return MEAN_DRIFT_UPWARD; } else { - return NO_MEAN_DRIFT; + return MEAN_DRIFT_NONE; } } diff --git a/modules/core/src/math/misc/vpStatisticalTestHinkley.cpp b/modules/core/src/math/misc/vpStatisticalTestHinkley.cpp index b001d010b6..6d75931952 100644 --- a/modules/core/src/math/misc/vpStatisticalTestHinkley.cpp +++ b/modules/core/src/math/misc/vpStatisticalTestHinkley.cpp @@ -30,8 +30,6 @@ * *****************************************************************************/ -#include - /** * * \file vpStatisticalTestHinkley.cpp @@ -57,6 +55,9 @@ vpStatisticalTestHinkley::vpStatisticalTestHinkley() , m_Mk(0.f) , m_Tk(0.f) , m_Nk(0.f) + , m_computeDeltaAndAlpha(false) + , m_h(4.76f) + , m_k(1.f) { init(); } @@ -69,16 +70,47 @@ vpStatisticalTestHinkley::vpStatisticalTestHinkley(const float &alpha, const flo , m_Mk(0.f) , m_Tk(0.f) , m_Nk(0.f) + , m_computeDeltaAndAlpha(false) + , m_h(4.76f) + , m_k(1.f) { init(alpha, delta_val, nbSamplesForInit); } +vpStatisticalTestHinkley::vpStatisticalTestHinkley(const float &h, const float &k, const bool &computeAlphaDeltaFromStdev, const unsigned int &nbSamplesForInit) + : vpStatisticalTestAbstract() +{ + init(h, k, computeAlphaDeltaFromStdev, nbSamplesForInit); +} + +vpStatisticalTestHinkley::vpStatisticalTestHinkley(const float &h, const float &k, const float &mean, const float &stdev) + : vpStatisticalTestAbstract() +{ + init(h, k, mean, stdev); +} + +void vpStatisticalTestHinkley::init() +{ + vpStatisticalTestAbstract::init(); + setNbSamplesForStat(30); + setAlpha(m_alpha); + + m_Sk = 0.f; + m_Mk = 0.f; + + m_Tk = 0.f; + m_Nk = 0.f; + + m_computeDeltaAndAlpha = false; +} + void vpStatisticalTestHinkley::init(const float &alpha, const float &delta_val, const unsigned int &nbSamplesForInit) { init(); setNbSamplesForStat(nbSamplesForInit); setAlpha(alpha); setDelta(delta_val); + m_computeDeltaAndAlpha = false; } void vpStatisticalTestHinkley::init(const float &alpha, const float &delta_val, const float &mean) @@ -87,31 +119,36 @@ void vpStatisticalTestHinkley::init(const float &alpha, const float &delta_val, setAlpha(alpha); setDelta(delta_val); m_mean = mean; + m_computeDeltaAndAlpha = false; m_areStatisticsComputed = true; } -vpStatisticalTestHinkley::~vpStatisticalTestHinkley() { } - -void vpStatisticalTestHinkley::init() +void vpStatisticalTestHinkley::init(const float &h, const float &k, const bool &computeAlphaDeltaFromStdev, const unsigned int &nbSamples) { - vpStatisticalTestAbstract::init(); - setNbSamplesForStat(30); - setAlpha(m_alpha); - - m_Sk = 0.f; - m_Mk = 0.f; - - m_Tk = 0.f; - m_Nk = 0.f; + if (!computeAlphaDeltaFromStdev) { + throw(vpException(vpException::badValue, "computeAlphaDeltaFromStdev must be true, or use another init function")); + } + init(); + setNbSamplesForStat(nbSamples); + m_h = h; + m_k = k; + m_computeDeltaAndAlpha = true; } -void vpStatisticalTestHinkley::init(const float &mean) +void vpStatisticalTestHinkley::init(const float &h, const float &k, const float &mean, const float &stdev) { - vpStatisticalTestHinkley::init(); + init(); m_mean = mean; + m_stdev = stdev; + m_h = h; + m_k = k; + m_computeDeltaAndAlpha = true; + computeAlphaDelta(); m_areStatisticsComputed = true; } +vpStatisticalTestHinkley::~vpStatisticalTestHinkley() { } + void vpStatisticalTestHinkley::setDelta(const float &delta) { m_dmin2 = delta / 2.f; } void vpStatisticalTestHinkley::setAlpha(const float &alpha) @@ -121,6 +158,14 @@ void vpStatisticalTestHinkley::setAlpha(const float &alpha) m_limitUp = m_alpha; } +void vpStatisticalTestHinkley::computeAlphaDelta() +{ + float delta = m_k * m_stdev; + setDelta(delta); + float alpha = m_h * m_stdev; + setAlpha(alpha); +} + void vpStatisticalTestHinkley::computeMean(double signal) { // When the mean slowly increases or decreases, especially after an abrupt change of the mean, @@ -158,24 +203,41 @@ void vpStatisticalTestHinkley::computeNk() } } -vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestHinkley::detectDownwardMeanShift() +vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestHinkley::detectDownwardMeanDrift() { - vpStatisticalTestAbstract::vpMeanDriftType shift = NO_MEAN_DRIFT; + vpStatisticalTestAbstract::vpMeanDriftType shift = MEAN_DRIFT_NONE; if ((m_Mk - m_Sk) > m_alpha) { shift = MEAN_DRIFT_DOWNWARD; } return shift; } -vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestHinkley::detectUpwardMeanShift() +vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestHinkley::detectUpwardMeanDrift() { - vpStatisticalTestAbstract::vpMeanDriftType shift = NO_MEAN_DRIFT; + vpStatisticalTestAbstract::vpMeanDriftType shift = MEAN_DRIFT_NONE; if ((m_Tk - m_Nk) > m_alpha) { shift = MEAN_DRIFT_UPWARD; } return shift; } +bool vpStatisticalTestHinkley::updateStatistics(const float &signal) +{ + bool updateStats = vpStatisticalTestAbstract::updateStatistics(signal); + if (m_areStatisticsComputed) { + // If needed, compute alpha and delta + if (m_computeDeltaAndAlpha) { + computeAlphaDelta(); + } + // Initialize the test signals + m_Mk = 0.f; + m_Nk = 0.f; + m_Sk = 0.f; + m_Tk = 0.f; + } + return updateStats; +} + void vpStatisticalTestHinkley::updateTestSignals(const float &signal) { computeSk(signal); diff --git a/modules/core/src/math/misc/vpStatisticalTestMeanAdjustedCUSUM.cpp b/modules/core/src/math/misc/vpStatisticalTestMeanAdjustedCUSUM.cpp index a60cf77798..0007b0a0eb 100644 --- a/modules/core/src/math/misc/vpStatisticalTestMeanAdjustedCUSUM.cpp +++ b/modules/core/src/math/misc/vpStatisticalTestMeanAdjustedCUSUM.cpp @@ -48,23 +48,23 @@ void vpStatisticalTestMeanAdjustedCUSUM::computeDeltaAndLimits() setLimits(limitDown, limitUp); } -vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestMeanAdjustedCUSUM::detectDownwardMeanShift() +vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestMeanAdjustedCUSUM::detectDownwardMeanDrift() { if (m_sminus >= m_limitDown) { return MEAN_DRIFT_DOWNWARD; } else { - return NO_MEAN_DRIFT; + return MEAN_DRIFT_NONE; } } -vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestMeanAdjustedCUSUM::detectUpwardMeanShift() +vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestMeanAdjustedCUSUM::detectUpwardMeanDrift() { if (m_splus >= m_limitUp) { return MEAN_DRIFT_UPWARD; } else { - return NO_MEAN_DRIFT; + return MEAN_DRIFT_NONE; } } diff --git a/modules/core/src/math/misc/vpStatisticalTestShewhart.cpp b/modules/core/src/math/misc/vpStatisticalTestShewhart.cpp new file mode 100644 index 0000000000..794e8aea27 --- /dev/null +++ b/modules/core/src/math/misc/vpStatisticalTestShewhart.cpp @@ -0,0 +1,308 @@ +/**************************************************************************** + * + * ViSP, open source Visual Servoing Platform software. + * Copyright (C) 2005 - 2023 by Inria. All rights reserved. + * + * This software is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * See the file LICENSE.txt at the root directory of this source + * distribution for additional information about the GNU GPL. + * + * For using ViSP with software that can not be combined with the GNU + * GPL, please contact Inria about acquiring a ViSP Professional + * Edition License. + * + * See https://visp.inria.fr for more information. + * + * This software was developed at: + * Inria Rennes - Bretagne Atlantique + * Campus Universitaire de Beaulieu + * 35042 Rennes Cedex + * France + * + * If you have questions regarding the use of this file, please contact + * Inria at visp@inria.fr + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * +*****************************************************************************/ + +/** +* +* \file vpStatisticalTestShewhart.cpp +* +* \brief Definition of the vpStatisticalTestShewhart class that implements Shewhart's +* mean drift test. +*/ + +#include + +#include + +#include + +const bool vpStatisticalTestShewhart::CONST_ALL_WECO_ACTIVATED[vpStatisticalTestShewhart::COUNT_WECO - 1] = { true, true, true, true }; + +std::string vpStatisticalTestShewhart::vpWecoRulesAlarmToString(const vpStatisticalTestShewhart::vpWecoRulesAlarm &alarm) +{ + std::string name; + switch (alarm) { + case THREE_SIGMA_WECO: + name = "3-sigma alarm"; + break; + case TWO_SIGMA_WECO: + name = "2-sigma alarm"; + break; + case ONE_SIGMA_WECO: + name = "1-sigma alarm"; + break; + case SAME_SIDE_WECO: + name = "Same-side alarm"; + break; + case NONE_WECO: + name = "No alarm"; + break; + default: + name = "Unknown WECO alarm"; + } + return name; +} + +void vpStatisticalTestShewhart::computeLimits() +{ + float delta = 3.f * m_stdev; + m_limitDown = m_mean - delta; + m_limitUp = m_mean + delta; + m_oneSigmaNegLim = m_mean - m_stdev; + m_oneSigmaPosLim = m_mean + m_stdev; + m_twoSigmaNegLim = m_mean - 2.f * m_stdev; + m_twoSigmaPosLim = m_mean + 2.f * m_stdev; +} + +vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestShewhart::detectDownwardMeanDrift() +{ + if (m_nbDataInBuffer < NB_DATA_SIGNAL) { + return vpStatisticalTestAbstract::MEAN_DRIFT_NONE; + } + if ((m_signal[m_idCurrentData] <= m_limitDown) && m_activatedWECOrules[THREE_SIGMA_WECO]) { + m_alarm = vpWecoRulesAlarm::THREE_SIGMA_WECO; + return vpStatisticalTestAbstract::MEAN_DRIFT_DOWNWARD; + } + if (!m_activateWECOrules) { + return vpStatisticalTestAbstract::MEAN_DRIFT_NONE; + } + vpStatisticalTestAbstract::vpMeanDriftType result = vpStatisticalTestAbstract::MEAN_DRIFT_NONE; + int id = vpMath::modulo(m_idCurrentData - (NB_DATA_SIGNAL - 1), NB_DATA_SIGNAL); + int i = 0; + unsigned int nbAboveMean = 0; + unsigned int nbAbove2SigmaLimit = 0; + unsigned int nbAbove1SigmaLimit = 0; + while (i < NB_DATA_SIGNAL) { + // Reinit for next iteration + nbAbove2SigmaLimit = 0; + nbAbove1SigmaLimit = 0; + if (m_signal[id] <= m_mean && m_activatedWECOrules[SAME_SIDE_WECO]) { + // Single-side test + ++nbAboveMean; + } + if (i > 3 && m_activatedWECOrules[TWO_SIGMA_WECO]) { + // Two sigma test + for (int idPrev = vpMath::modulo(id - 2, NB_DATA_SIGNAL); idPrev != id; idPrev = vpMath::modulo(idPrev + 1, NB_DATA_SIGNAL)) { + if (m_signal[idPrev] <= m_twoSigmaNegLim) { + ++nbAbove2SigmaLimit; + } + } + if (m_signal[id] <= m_twoSigmaNegLim) { + ++nbAbove2SigmaLimit; + } + if (nbAbove2SigmaLimit >= 2) { + break; + } + } + if (i > 5 && m_activatedWECOrules[ONE_SIGMA_WECO]) { + // One sigma test + for (int idPrev = vpMath::modulo(id - 4, NB_DATA_SIGNAL); idPrev != id; idPrev = vpMath::modulo(idPrev + 1, NB_DATA_SIGNAL)) { + if (m_signal[idPrev] <= m_oneSigmaNegLim) { + ++nbAbove1SigmaLimit; + } + } + if (m_signal[id] <= m_oneSigmaNegLim) { + ++nbAbove1SigmaLimit; + } + if (nbAbove1SigmaLimit >= 4) { + break; + } + } + id = vpMath::modulo(id + 1, NB_DATA_SIGNAL); + ++i; + } + if (nbAboveMean == NB_DATA_SIGNAL) { + m_alarm = SAME_SIDE_WECO; + result = MEAN_DRIFT_DOWNWARD; + } + else if (nbAbove2SigmaLimit >= 2) { + m_alarm = TWO_SIGMA_WECO; + result = MEAN_DRIFT_DOWNWARD; + } + else if (nbAbove1SigmaLimit >= 4) { + m_alarm = ONE_SIGMA_WECO; + result = MEAN_DRIFT_DOWNWARD; + } + return result; +} + +vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestShewhart::detectUpwardMeanDrift() +{ + if (m_nbDataInBuffer < NB_DATA_SIGNAL) { + return vpStatisticalTestAbstract::MEAN_DRIFT_NONE; + } + if ((m_signal[m_idCurrentData] >= m_limitUp) && m_activatedWECOrules[THREE_SIGMA_WECO]) { + m_alarm = vpWecoRulesAlarm::THREE_SIGMA_WECO; + return vpStatisticalTestAbstract::MEAN_DRIFT_UPWARD; + } + if (!m_activateWECOrules) { + return vpStatisticalTestAbstract::MEAN_DRIFT_NONE; + } + vpStatisticalTestAbstract::vpMeanDriftType result = vpStatisticalTestAbstract::MEAN_DRIFT_NONE; + int id = vpMath::modulo(m_idCurrentData - (NB_DATA_SIGNAL - 1), NB_DATA_SIGNAL); + int i = 0; + unsigned int nbAboveMean = 0; + unsigned int nbAbove2SigmaLimit = 0; + unsigned int nbAbove1SigmaLimit = 0; + while (i < NB_DATA_SIGNAL) { + // Reinit for next iteration + nbAbove2SigmaLimit = 0; + nbAbove1SigmaLimit = 0; + if (m_signal[id] > m_mean && m_activatedWECOrules[SAME_SIDE_WECO]) { + // Single-side test + ++nbAboveMean; + } + if (i > 3 && m_activatedWECOrules[TWO_SIGMA_WECO]) { + // Two sigma test + for (int idPrev = vpMath::modulo(id - 2, NB_DATA_SIGNAL); idPrev != id; idPrev = vpMath::modulo(idPrev + 1, NB_DATA_SIGNAL)) { + if (m_signal[idPrev] >= m_twoSigmaPosLim) { + ++nbAbove2SigmaLimit; + } + } + if (m_signal[id] >= m_twoSigmaPosLim) { + ++nbAbove2SigmaLimit; + } + if (nbAbove2SigmaLimit >= 2) { + break; + } + } + if (i > 5 && m_activatedWECOrules[ONE_SIGMA_WECO]) { + // One sigma test + for (int idPrev = vpMath::modulo(id - 4, NB_DATA_SIGNAL); idPrev != id; idPrev = vpMath::modulo(idPrev + 1, NB_DATA_SIGNAL)) { + if (m_signal[idPrev] >= m_oneSigmaPosLim) { + ++nbAbove1SigmaLimit; + } + } + if (m_signal[id] >= m_oneSigmaPosLim) { + ++nbAbove1SigmaLimit; + } + if (nbAbove1SigmaLimit >= 4) { + break; + } + } + id = vpMath::modulo(id + 1, NB_DATA_SIGNAL); + ++i; + } + if (nbAboveMean == NB_DATA_SIGNAL) { + m_alarm = SAME_SIDE_WECO; + result = MEAN_DRIFT_UPWARD; + } + else if (nbAbove2SigmaLimit >= 2) { + m_alarm = TWO_SIGMA_WECO; + result = MEAN_DRIFT_UPWARD; + } + else if (nbAbove1SigmaLimit >= 4) { + m_alarm = ONE_SIGMA_WECO; + result = MEAN_DRIFT_UPWARD; + } + return result; +} + +bool vpStatisticalTestShewhart::updateStatistics(const float &signal) +{ + bool areStatsAvailable = vpStatisticalTestAbstract::updateStatistics(signal); + updateTestSignals(signal); // Store the signal in the circular buffer too. + if (areStatsAvailable) { + computeLimits(); + } + return areStatsAvailable; +} + +void vpStatisticalTestShewhart::updateTestSignals(const float &signal) +{ + m_idCurrentData = (m_idCurrentData + 1) % NB_DATA_SIGNAL; + m_signal[m_idCurrentData] = signal; + if (m_nbDataInBuffer < NB_DATA_SIGNAL) { + ++m_nbDataInBuffer; + } +} + +vpStatisticalTestShewhart::vpStatisticalTestShewhart(const bool &activateWECOrules, const bool activatedRules[COUNT_WECO - 1], const unsigned int &nbSamplesForStats) + : vpStatisticalTestSigma(3, nbSamplesForStats) + , m_nbDataInBuffer(0) + , m_activateWECOrules(activateWECOrules) + , m_idCurrentData(0) + , m_alarm(NONE_WECO) + , m_oneSigmaNegLim(0.f) + , m_oneSigmaPosLim(0.f) + , m_twoSigmaNegLim(0.f) + , m_twoSigmaPosLim(0.f) +{ + init(activateWECOrules, activatedRules, nbSamplesForStats); +} + +vpStatisticalTestShewhart::vpStatisticalTestShewhart(const bool &activateWECOrules, const bool activatedRules[COUNT_WECO - 1], const float &mean, const float &stdev) + : vpStatisticalTestSigma(3) + , m_nbDataInBuffer(0) + , m_activateWECOrules(activateWECOrules) + , m_idCurrentData(0) + , m_alarm(NONE_WECO) + , m_oneSigmaNegLim(0.f) + , m_oneSigmaPosLim(0.f) + , m_twoSigmaNegLim(0.f) + , m_twoSigmaPosLim(0.f) +{ + init(activateWECOrules, activatedRules, mean, stdev); +} + +std::vector vpStatisticalTestShewhart::getSignals() const +{ + std::vector signals; + for (int i = 0; i < NB_DATA_SIGNAL; ++i) { + int id = vpMath::modulo(m_idCurrentData - (NB_DATA_SIGNAL - i - 1), NB_DATA_SIGNAL); + signals.push_back(m_signal[id]); + } + return signals; +} + +void vpStatisticalTestShewhart::init(const bool &activateWECOrules, const bool activatedRules[COUNT_WECO - 1], const unsigned int &nbSamplesForStats) +{ + vpStatisticalTestSigma::init(3.f, nbSamplesForStats); + m_nbDataInBuffer = 0; + memset(m_signal, 0, NB_DATA_SIGNAL * sizeof(float)); + m_activateWECOrules = activateWECOrules; + std::memcpy(m_activatedWECOrules, activatedRules, (COUNT_WECO - 1) * sizeof(bool)); + m_idCurrentData = 0; + m_alarm = NONE_WECO; + m_oneSigmaNegLim = 0.f; + m_oneSigmaPosLim = 0.f; + m_twoSigmaNegLim = 0.f; + m_twoSigmaPosLim = 0.f; +} + +void vpStatisticalTestShewhart::init(const bool &activateWECOrules, const bool activatedRules[COUNT_WECO - 1], const float &mean, const float &stdev) +{ + vpStatisticalTestShewhart::init(activateWECOrules, activatedRules, 30); + m_mean = mean; + m_stdev = stdev; + computeLimits(); + m_areStatisticsComputed = true; +} diff --git a/modules/core/src/math/misc/vpStatisticalTestSigma.cpp b/modules/core/src/math/misc/vpStatisticalTestSigma.cpp index 65dd6a1d2b..5a64cacbbc 100644 --- a/modules/core/src/math/misc/vpStatisticalTestSigma.cpp +++ b/modules/core/src/math/misc/vpStatisticalTestSigma.cpp @@ -30,6 +30,14 @@ * *****************************************************************************/ +/** +* +* \file vpStatisticalTestSigma.cpp +* +* \brief Definition of the vpStatisticalTestSigma class that implements sigma +* mean drift test. +*/ + #include void vpStatisticalTestSigma::computeLimits() @@ -39,23 +47,23 @@ void vpStatisticalTestSigma::computeLimits() m_limitUp = m_mean + delta; } -vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestSigma::detectDownwardMeanShift() +vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestSigma::detectDownwardMeanDrift() { if (m_s <= m_limitDown) { return vpStatisticalTestAbstract::MEAN_DRIFT_DOWNWARD; } else { - return vpStatisticalTestAbstract::NO_MEAN_DRIFT; + return vpStatisticalTestAbstract::MEAN_DRIFT_NONE; } } -vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestSigma::detectUpwardMeanShift() +vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestSigma::detectUpwardMeanDrift() { if (m_s >= m_limitUp) { return vpStatisticalTestAbstract::MEAN_DRIFT_UPWARD; } else { - return vpStatisticalTestAbstract::NO_MEAN_DRIFT; + return vpStatisticalTestAbstract::MEAN_DRIFT_NONE; } } diff --git a/tutorial/mean-drift/tutorial-meandrift.cpp b/tutorial/mean-drift/tutorial-meandrift.cpp index 37f4aeb659..3e2b6701ba 100644 --- a/tutorial/mean-drift/tutorial-meandrift.cpp +++ b/tutorial/mean-drift/tutorial-meandrift.cpp @@ -37,22 +37,24 @@ #include #include #include +#include #include #include namespace TutorialMeanDrift { /** - * \brief Structure that permits to choose which process test to use. + * \brief Enumeration that permits to choose which process test to use. * */ typedef enum TypeTest { - HINLKEY_TYPE_TEST = 0, /*!< Use Hinkley to perform the tests.*/ + HINLKEY_TYPE_TEST = 0, /*!< Use Hinkley's test.*/ EWMA_TYPE_TEST = 1, /*!< Use Exponentially Weighted Moving Average to perform the tests.*/ MEAN_ADJUSTED_CUSUM_TYPE_TEST = 2, /*!< Use mean adjusted Cumulative Sum to perform the tests.*/ - SIGMA_TYPE_TEST = 3, /*!< Simple test based on the comparisong with the standard deviation.*/ - COUNT_TYPE_TEST = 4, /*!< Number of different aavailable methods.*/ + SHEWHART_TYPE_TEST = 3, /*!< Shewhart's test.*/ + SIGMA_TYPE_TEST = 4, /*!< Simple test based on the comparisong with the standard deviation.*/ + COUNT_TYPE_TEST = 5, /*!< Number of different aavailable methods.*/ UNKOWN_TYPE_TEST = COUNT_TYPE_TEST /*!< Unknown method.*/ }TypeTest; @@ -75,6 +77,9 @@ std::string typeTestToString(const TypeTest &type) case MEAN_ADJUSTED_CUSUM_TYPE_TEST: result = "cusum"; break; + case SHEWHART_TYPE_TEST: + result = "shewhart"; + break; case SIGMA_TYPE_TEST: result = "sigma"; break; @@ -131,28 +136,204 @@ std::string getAvailableTypeTest(const std::string &prefix = "<", const std::str return msg; } +/** + * \brief Cast a number type into a string. + * + * \tparam T Type of number. + * \param[in] number The number to cast. + * \return std::string The corresponding string. + */ +template +std::string numberToString(const T &number) +{ + std::stringstream ss; + ss << number; + return ss.str(); +} + +/** + * \brief Cast a boolean into a string. + * + * \param[in] boolean The boolean to cast. + * \return std::string The corresponding string. + */ +std::string boolToString(const bool &boolean) +{ + if (boolean) { + return "true"; + } + else { + return "false"; + } +} + +/** + * \brief Write the WECO's rules used in the Shewhart's test in human readable format. + * + * \param[in] rules The array indicating which WECO's rules are used. + * \param[in] prefix The first character(s) delimiting the array in the string. + * \param[in] suffix The last character(s) delimiting the array in the string. + * \param[in] sep The separator character(s). + * \return std::string The corresponding string. + */ +std::string wecoRulesToString(const bool rules[vpStatisticalTestShewhart::COUNT_WECO - 1], const std::string &prefix = "[", const std::string &suffix = "]", const std::string &sep = " , ") +{ + std::string rulesAsString = prefix; + for (unsigned int i = 0; i < vpStatisticalTestShewhart::COUNT_WECO - 2; ++i) { + if (rules[i]) { + rulesAsString += "ON"; + } + else { + rulesAsString += "OFF"; + } + rulesAsString += sep; + } + if (rules[vpStatisticalTestShewhart::COUNT_WECO - 2]) { + rulesAsString += "ON"; + } + else { + rulesAsString += "OFF"; + } + rulesAsString += suffix; + return rulesAsString; +} + +/** + * \brief Array that sets all the types of mean drift to deactivated. + */ +const bool CONST_ALL_ALARM_OFF[vpStatisticalTestAbstract::MEAN_DRIFT_COUNT] = { false, false, false, false }; + +/** + * \brief Array that sets all the types of mean drift to activated. + */ +const bool CONST_ALL_ALARM_ON[vpStatisticalTestAbstract::MEAN_DRIFT_COUNT] = { true, true, true, true }; + +/** + * \brief Cast a vector of string into an array of boolean activating / deactivating + * the mean drift alarms. + * + * \param[in] names The names of the alarms to set. + * \param[out] array The corresponding array of boolean. + */ +void vectorOfStringToMeanDriftTypeArray(const std::vector &names, bool array[vpStatisticalTestAbstract::MEAN_DRIFT_COUNT]) +{ + std::memcpy(array, CONST_ALL_ALARM_OFF, vpStatisticalTestAbstract::MEAN_DRIFT_COUNT * sizeof(bool)); + size_t nbNames = names.size(); + for (size_t i = 0; i < nbNames; ++i) { + vpStatisticalTestAbstract::vpMeanDriftType alarmToActivate = vpStatisticalTestAbstract::vpMeanDriftTypeFromString(names[i]); + std::cout << "alarm[" << names[i] << "] (i.e. " << static_cast(alarmToActivate) << ") set to true" << std::endl; + array[static_cast(alarmToActivate)] = true; + if (alarmToActivate == vpStatisticalTestAbstract::MEAN_DRIFT_BOTH) { + array[vpStatisticalTestAbstract::MEAN_DRIFT_DOWNWARD] = true; + array[vpStatisticalTestAbstract::MEAN_DRIFT_UPWARD] = true; + } + } + if (array[vpStatisticalTestAbstract::MEAN_DRIFT_DOWNWARD] || array[vpStatisticalTestAbstract::MEAN_DRIFT_UPWARD]) { + array[vpStatisticalTestAbstract::MEAN_DRIFT_BOTH] = true; + } +} + +/** + * \brief Cast an array of boolean (de)activating the mean drift alarms into + * the corresponding vector of strings. + * + * \param[in] array The array of boolean indicating which alarm are set. + * \return std::vector The corresponding vector of names of alarms. + */ +std::vector meanDriftArrayToVectorOfString(const bool array[vpStatisticalTestAbstract::MEAN_DRIFT_COUNT]) +{ + std::vector listActivatedAlarms; + unsigned int nbTypeTests = static_cast(vpStatisticalTestAbstract::MEAN_DRIFT_COUNT); + for (unsigned int id = 0; id < nbTypeTests; ++id) { + if (array[id]) { + vpStatisticalTestAbstract::vpMeanDriftType test = static_cast(id); + std::string testName = vpStatisticalTestAbstract::vpMeanDriftTypeToString(test); + listActivatedAlarms.push_back(testName); + } + } + return listActivatedAlarms; +} + +/** + * \brief Cast an array of boolean (de)activating the mean drift alarms into + * a single string listing all the alarms. + * + * \param[in] array The array of boolean indicating which alarm are set. + * \return std::string The corresponding string listing the names of alarms. + */ +std::string meanDriftArrayToString(const bool array[vpStatisticalTestAbstract::MEAN_DRIFT_COUNT], + const std::string &prefix = "[", const std::string &sep = " , ", + const std::string &suffix = "]") +{ + std::vector listActivatedAlarms = meanDriftArrayToVectorOfString(array); + std::string result = prefix; + size_t nbTestActivated = listActivatedAlarms.size(); + if (nbTestActivated == 0) { + return prefix + " " + suffix; + } + for (size_t i = 0; i < nbTestActivated - 1; ++i) { + result += listActivatedAlarms[i] + sep; + } + result += listActivatedAlarms[nbTestActivated - 1] + suffix; + return result; +} + +/** + * \brief Indicate how many alarms are set. + * + * \param[in] array The array of boolean indicating which alarms are set. + * \return unsigned int The number of alarms that are set. + */ +unsigned int meanDriftArrayToNbActivated(const bool array[vpStatisticalTestAbstract::MEAN_DRIFT_COUNT]) +{ + unsigned int nbActivated = 0; + unsigned int nbTypeAlarms = static_cast(vpStatisticalTestAbstract::MEAN_DRIFT_COUNT); + for (unsigned int id = 0; id < nbTypeAlarms; ++id) { + if (array[id]) { + ++nbActivated; + } + } + return nbActivated; +} + /** * \brief Structure that contains the parameters of the different algorithms. */ typedef struct ParametersForAlgo { - unsigned int m_global_nbsamples; /*!< Number of samples to compute the mean and stdev, common to all the algorithms.*/ + unsigned int m_test_nbsamples; /*!< Number of samples to compute the mean and stdev, common to all the algorithms.*/ + bool m_test_activatedalarms[vpStatisticalTestAbstract::MEAN_DRIFT_COUNT]; /*!< Flag is true for a type of alarm that must be considered, false otherwise.*/ + unsigned int m_test_nbactivatedalarms; /*!< Number of activated alarms.*/ float m_cusum_h; /*!< Alarm factor for the mean adjusted CUSUM test.*/ float m_cusum_k; /*!< Detection factor for the mean adjusted CUSUM test.*/ float m_ewma_alpha; /*!< Forgetting factor for the EWMA test.*/ float m_hinkley_alpha; /*!< Alarm threshold for the Hinkley's test. */ float m_hinkley_delta; /*!< Detection threshold for the Hinkley's test. */ + bool m_hinkley_computealphadelta; /*!< If true, compute alpha and delta of the Hinkley's using the stdev of the signal.*/ + float m_hinkley_h; /*!< Alarm factor permitting to compute alpha from the standard deviation of the signal.*/ + float m_hinkley_k; /*!< Detection factor permitting to compute delta from the standard deviation of the signal.*/ + bool m_shewhart_useWECO; /*!< If true, use the WECO rules for additionnal subtests for Shewhart's test.*/ + bool m_shewhart_rules[vpStatisticalTestShewhart::COUNT_WECO - 1]; /*!< Rules for the Shewart's test. True activate a WECO rule, false deactivate it.*/ float m_sigma_h; /*!< Alarm factor for the sigma test.*/ ParametersForAlgo() - : m_global_nbsamples(30) + : m_test_nbsamples(30) , m_cusum_h(4.76f) , m_cusum_k(1.f) , m_ewma_alpha(0.1f) , m_hinkley_alpha(4.76f) , m_hinkley_delta(1.f) + , m_hinkley_computealphadelta(false) + , m_hinkley_h(4.76f) + , m_hinkley_k(1.f) + , m_shewhart_useWECO(false) , m_sigma_h(3.f) - { } + { + std::memcpy(m_shewhart_rules, vpStatisticalTestShewhart::CONST_ALL_WECO_ACTIVATED, (vpStatisticalTestShewhart::COUNT_WECO - 1) * sizeof(bool)); + memcpy(m_test_activatedalarms, CONST_ALL_ALARM_ON, vpStatisticalTestAbstract::MEAN_DRIFT_COUNT * sizeof(bool)); + m_test_activatedalarms[vpStatisticalTestAbstract::MEAN_DRIFT_NONE] = false; + m_test_nbactivatedalarms = meanDriftArrayToNbActivated(m_test_activatedalarms); + } }ParametersForAlgo; } @@ -174,43 +355,52 @@ int testOnSynthetic(const TutorialMeanDrift::TypeTest &type, const TutorialMeanD p_test = new vpStatisticalTestEWMA(parameters.m_ewma_alpha); break; case TutorialMeanDrift::HINLKEY_TYPE_TEST: - p_test = new vpStatisticalTestHinkley(parameters.m_hinkley_alpha, parameters.m_hinkley_delta, parameters.m_global_nbsamples); + p_test = new vpStatisticalTestHinkley(parameters.m_hinkley_alpha, parameters.m_hinkley_delta, parameters.m_test_nbsamples); break; case TutorialMeanDrift::MEAN_ADJUSTED_CUSUM_TYPE_TEST: - p_test = new vpStatisticalTestMeanAdjustedCUSUM(parameters.m_cusum_h, parameters.m_cusum_k, parameters.m_global_nbsamples); + p_test = new vpStatisticalTestMeanAdjustedCUSUM(parameters.m_cusum_h, parameters.m_cusum_k, parameters.m_test_nbsamples); + break; + case TutorialMeanDrift::SHEWHART_TYPE_TEST: + p_test = new vpStatisticalTestShewhart(parameters.m_shewhart_useWECO, parameters.m_shewhart_rules, parameters.m_test_nbsamples); break; case TutorialMeanDrift::SIGMA_TYPE_TEST: - p_test = new vpStatisticalTestSigma(parameters.m_sigma_h, parameters.m_global_nbsamples); + p_test = new vpStatisticalTestSigma(parameters.m_sigma_h, parameters.m_test_nbsamples); break; default: throw(vpException(vpException::badValue, TutorialMeanDrift::typeTestToString(type) + " is not handled.")); break; } + if ((type == TutorialMeanDrift::HINLKEY_TYPE_TEST) && parameters.m_hinkley_computealphadelta) { + delete p_test; + p_test = new vpStatisticalTestHinkley(parameters.m_hinkley_h, parameters.m_hinkley_k, true, parameters.m_test_nbsamples); + } + float signal; std::cout << "Actual mean of the input signal: " << mean << std::endl; std::cout << "Actual stdev of the input signal: " << stdev << std::endl; std::cout << "Mean drift of the input signal: " << mean_drift << std::endl; // Initial computation of the mean and stdev of the input signal - for (unsigned int i = 0; i < parameters.m_global_nbsamples; ++i) { + for (unsigned int i = 0; i < parameters.m_test_nbsamples; ++i) { vpGaussRand rndGen(stdev, mean, static_cast(idFrame) * dt); signal = rndGen(); - p_test->testDownUpwardMeanShift(signal); + p_test->testDownUpwardMeanDrift(signal); ++idFrame; } + std::cout << "Estimated mean of the input signal: " << p_test->getMean() << std::endl; std::cout << "Estimated stdev of the input signal: " << p_test->getStdev() << std::endl; float mean_eff = mean; bool hasToRun = true; - vpStatisticalTestAbstract::vpMeanDriftType drift_type = vpStatisticalTestAbstract::NO_MEAN_DRIFT; + vpStatisticalTestAbstract::vpMeanDriftType drift_type = vpStatisticalTestAbstract::MEAN_DRIFT_NONE; while (hasToRun) { - vpGaussRand rndGen(stdev, mean_eff, static_cast(idFrame) * dt); + vpGaussRand rndGen(stdev, mean_eff, vpTime::measureTimeMs() * 1e3 + static_cast(idFrame) * dt); signal = rndGen(); - plotter.plot(0, 0, idFrame - parameters.m_global_nbsamples, signal); - drift_type = p_test->testDownUpwardMeanShift(signal); - if (drift_type != vpStatisticalTestAbstract::NO_MEAN_DRIFT) { + plotter.plot(0, 0, idFrame - parameters.m_test_nbsamples, signal); + drift_type = p_test->testDownUpwardMeanDrift(signal); + if ((drift_type != vpStatisticalTestAbstract::MEAN_DRIFT_NONE) && (parameters.m_test_activatedalarms[drift_type])) { hasToRun = false; } else { @@ -218,7 +408,7 @@ int testOnSynthetic(const TutorialMeanDrift::TypeTest &type, const TutorialMeanD ++idFrame; } } - std::cout << "Test failed at frame: " << idFrame - parameters.m_global_nbsamples << std::endl; + std::cout << "Test failed at frame: " << idFrame - parameters.m_test_nbsamples << std::endl; std::cout << "Type of mean drift: " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift_type) << std::endl; std::cout << "Last signal value: " << signal << std::endl; if (type == TutorialMeanDrift::EWMA_TYPE_TEST) { @@ -230,6 +420,26 @@ int testOnSynthetic(const TutorialMeanDrift::TypeTest &type, const TutorialMeanD std::cout << "\tLower cusum = " << p_testCusum->getTestSignalMinus() << std::endl; std::cout << "\tUpper cusum = " << p_testCusum->getTestSignalPlus() << std::endl; } + else if (type==TutorialMeanDrift::SHEWHART_TYPE_TEST) { + vpStatisticalTestShewhart *p_testShewhart = dynamic_cast(p_test); + std::vector signal = p_testShewhart->getSignals(); + size_t nbSignal = signal.size(); + std::cout << "Signal history = [ "; + for (size_t i = 0; i < nbSignal; ++i) { + std::cout << signal[i] << " "; + } + std::cout << "]" << std::endl; + std::cout << "\tWECO alarm type = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(p_testShewhart->getAlarm()) << std::endl; + } + else if (type == TutorialMeanDrift::HINLKEY_TYPE_TEST) { + vpStatisticalTestHinkley *p_hinkley = dynamic_cast(p_test); + float Mk = p_hinkley->getMk(); + float Nk = p_hinkley->getNk(); + float Sk = p_hinkley->getSk(); + float Tk = p_hinkley->getTk(); + std::cout << "S+(t) = " << Tk - Nk < alarmNames; + bool hasNotFoundNextParams = true; + for (int j = 1; ((i + j) < argc) && hasNotFoundNextParams; ++j) { + std::string candidate(argv[i+j]); + if (candidate.find("--") != std::string::npos) { + // This is the next command line parameter + hasNotFoundNextParams = false; + } + else { + // This is a name + alarmNames.push_back(candidate); + ++nbArguments; + } + } + TutorialMeanDrift::vectorOfStringToMeanDriftTypeArray(alarmNames, parameters.m_test_activatedalarms); + parameters.m_test_nbactivatedalarms = TutorialMeanDrift::meanDriftArrayToNbActivated(parameters.m_test_activatedalarms); + i += nbArguments; + } else if ((std::string(argv[i]) == "--cusum-h") && ((i + 1) < argc)) { parameters.m_cusum_h = std::atof(argv[i + 1]); ++i; @@ -289,6 +519,32 @@ int main(int argc, char *argv[]) parameters.m_hinkley_delta = std::atof(argv[i + 1]); ++i; } + else if (std::string(argv[i]) == "--hinkley-compute") { + parameters.m_hinkley_computealphadelta = true; + } + else if ((std::string(argv[i]) == "--hinkley-h") && ((i + 1) < argc)) { + parameters.m_hinkley_h = std::atof(argv[i + 1]); + ++i; + } + else if ((std::string(argv[i]) == "--hinkley-k") && ((i + 1) < argc)) { + parameters.m_hinkley_k = std::atof(argv[i + 1]); + ++i; + } + else if ((std::string(argv[i]) == "--shewhart-rules") && (i + vpStatisticalTestShewhart::COUNT_WECO - 1 < argc)) { + for (int j = 0; j < vpStatisticalTestShewhart::COUNT_WECO - 1; ++j) { + std::string argument = std::string(argv[i + 1 + j]); + if ((argument.find("on") != std::string::npos) || (argument.find("ON") != std::string::npos)) { + parameters.m_shewhart_rules[j] = true; + } + else { + parameters.m_shewhart_rules[j] = false; + } + } + i += vpStatisticalTestShewhart::COUNT_WECO - 1; + } + else if (std::string(argv[i]) == "--shewhart-weco") { + parameters.m_shewhart_useWECO = true; + } else if ((std::string(argv[i]) == "--sigma-h") && ((i + 1) < argc)) { parameters.m_sigma_h = std::atof(argv[i + 1]); ++i; @@ -298,6 +554,7 @@ int main(int argc, char *argv[]) << argv[0] << " [--test ]" << " [--nb-samples ]" + << " [--alarms ]" << " [--mean ]" << " [--mean-drift ]" << " [--stdev ]" @@ -306,6 +563,11 @@ int main(int argc, char *argv[]) << " [--ewma-alpha ]" << " [--hinkley-alpha <]0; inf[>]" << " [--hinkley-delta <]0; inf[>]" + << " [--hinkley-compute]" + << " [--hinkley-h <]0; inf[>]" + << " [--hinkley-k <]0; inf[>]" + << " [--shewhart-rules <3-sigma:{on|off} 2-sigma:{on|off} 1-sigma:{on|off} same-side:{on|off}>" + << " [--shewhart-weco]" << " [--sigma-h ]" << " [--help,-h]" << std::endl; std::cout << "\nOPTIONS " << std::endl @@ -315,7 +577,12 @@ int main(int argc, char *argv[]) << std::endl << " --nb-samples " << std::endl << " Number of samples to compute the mean and standard deviation of the monitored signal." << std::endl - << " Default: " << parameters.m_global_nbsamples << std::endl + << " Default: " << parameters.m_test_nbsamples << std::endl + << std::endl + << " --alarms " << std::endl + << " Set the mean drift alarms to monitor." << std::endl + << " Default: " << TutorialMeanDrift::meanDriftArrayToString(parameters.m_test_activatedalarms) << std::endl + << " Available: " << vpStatisticalTestAbstract::getAvailableMeanDriftType() << std::endl << std::endl << " --mean " << std::endl << " Mean of the signal." << std::endl @@ -351,6 +618,27 @@ int main(int argc, char *argv[]) << " Detection threshold indicating minimal magnitude we want to detect for the Hinkley's test." << std::endl << " Default: " << parameters.m_hinkley_delta << std::endl << std::endl + << " --hinkley-compute" << std::endl + << " If set, the Hinkley's test will compute the alarm and detection thresholds" << std::endl + << " from the standard deviation of the input signal." << std::endl + << " Default: disabled" << std::endl + << std::endl + << " --hinkley-h " << std::endl + << " Alarm factor permitting to compute the alarm threshold for the Hinkley's test." << std::endl + << " Default: " << parameters.m_hinkley_h << std::endl + << std::endl + << " --hinkley-k " << std::endl + << " Detection factor permitting to compute the Detection threshold for the Hinkley's test." << std::endl + << " Default: " << parameters.m_hinkley_k << std::endl + << std::endl + << " --shewhart-rules <3-sigma:{on|off} 2-sigma:{on|off} 1-sigma:{on|off} same-side:{on|off}>" << std::endl + << " Choose the WECO additionnal tests for the Shewhart's test to use. To activate them, --shewart-weco must be used." << std::endl + << " Default: ON ON ON ON" << std::endl + << std::endl + << " --shewhart-weco" << std::endl + << " Activate the WECO additionnal tests for the Shewhart's test." << std::endl + << " Default: deactivated" << std::endl + << std::endl << " --sigma-h " << std::endl << " The alarm factor of the sigma test." << std::endl << " Default: " << parameters.m_sigma_h << std::endl @@ -367,5 +655,24 @@ int main(int argc, char *argv[]) ++i; } + if (parameters.m_test_nbactivatedalarms == 0) { + throw(vpException(vpException::badValue, "Error, at least one type of alarm must be monitored. See " + std::string(argv[0]) + " --help")); + return EXIT_FAILURE; + } + + std::cout << " Activated statistical test : " << TutorialMeanDrift::typeTestToString(opt_typeTest) << std::endl; + std::cout << " Activated alarms : " << TutorialMeanDrift::meanDriftArrayToString(parameters.m_test_activatedalarms) << std::endl; + std::cout << " Nb samples for statistics computation: " << parameters.m_test_nbsamples << std::endl; + std::cout << " Alarm factor CUSUM test : " << (opt_typeTest == TutorialMeanDrift::MEAN_ADJUSTED_CUSUM_TYPE_TEST ? TutorialMeanDrift::numberToString(parameters.m_cusum_h) : "N/A") << std::endl; + std::cout << " Detection factor CUSUM test : " << (opt_typeTest == TutorialMeanDrift::MEAN_ADJUSTED_CUSUM_TYPE_TEST ? TutorialMeanDrift::numberToString(parameters.m_cusum_k) : "N/A") << std::endl; + std::cout << " Forgetting factor EWMA test : " << (opt_typeTest == TutorialMeanDrift::EWMA_TYPE_TEST ? TutorialMeanDrift::numberToString(parameters.m_ewma_alpha) : "N/A") << std::endl; + std::cout << " Alarm threshold Hinkley's test : " << ((opt_typeTest == TutorialMeanDrift::HINLKEY_TYPE_TEST) && (!parameters.m_hinkley_computealphadelta) ? TutorialMeanDrift::numberToString(parameters.m_hinkley_alpha) : "N/A") << std::endl; + std::cout << " Detection threshold Hinkley's test : " << ((opt_typeTest == TutorialMeanDrift::HINLKEY_TYPE_TEST) && (!parameters.m_hinkley_computealphadelta) ? TutorialMeanDrift::numberToString(parameters.m_hinkley_delta) : "N/A") << std::endl; + std::cout << " Alarm factor Hinkley's test : " << ((opt_typeTest == TutorialMeanDrift::HINLKEY_TYPE_TEST) && parameters.m_hinkley_computealphadelta ? TutorialMeanDrift::numberToString(parameters.m_hinkley_h) : "N/A") << std::endl; + std::cout << " Detection factor Hinkley's test : " << ((opt_typeTest == TutorialMeanDrift::HINLKEY_TYPE_TEST) && parameters.m_hinkley_computealphadelta ? TutorialMeanDrift::numberToString(parameters.m_hinkley_k) : "N/A") << std::endl; + std::cout << " Shewhart's test set of WECO rules : " << (parameters.m_shewhart_useWECO && (opt_typeTest == TutorialMeanDrift::SHEWHART_TYPE_TEST) ? TutorialMeanDrift::wecoRulesToString(parameters.m_shewhart_rules) : "N/A") << std::endl; + std::cout << " Shewhart's test use WECO rules : " << (opt_typeTest == TutorialMeanDrift::SHEWHART_TYPE_TEST ? TutorialMeanDrift::boolToString(parameters.m_shewhart_useWECO && (opt_typeTest == TutorialMeanDrift::SHEWHART_TYPE_TEST)) : "N/A") << std::endl; + std::cout << " Alarm factor Sigma test : " << (opt_typeTest == TutorialMeanDrift::SIGMA_TYPE_TEST ? TutorialMeanDrift::numberToString(parameters.m_sigma_h) : "N/A") << std::endl; + return testOnSynthetic(opt_typeTest, parameters, opt_mean, opt_meandrift, opt_stdev); } From 727ee50925d32c1dbc90e5b31483eb3d41dce4b1 Mon Sep 17 00:00:00 2001 From: rlagneau Date: Fri, 8 Mar 2024 09:50:34 +0100 Subject: [PATCH 04/12] [TUTO] Added a doxyfile explaining the code of the tutorial-meandrift.cpp --- .../tutorial/misc/img-tutorial-spc-run.png | Bin 0 -> 147847 bytes doc/tutorial/misc/tutorial-spc.dox | 89 ++++++++++++++++++ doc/tutorial/tutorial-users.dox | 1 + tutorial/mean-drift/tutorial-meandrift.cpp | 25 ++++- 4 files changed, 111 insertions(+), 4 deletions(-) create mode 100644 doc/image/tutorial/misc/img-tutorial-spc-run.png create mode 100644 doc/tutorial/misc/tutorial-spc.dox diff --git a/doc/image/tutorial/misc/img-tutorial-spc-run.png b/doc/image/tutorial/misc/img-tutorial-spc-run.png new file mode 100644 index 0000000000000000000000000000000000000000..153666a51a9c1cb959687893eeca3aaeca9dc3c1 GIT binary patch literal 147847 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 tutorial explains how to use a threaded PCL-based point cloud visualizer. - \subpage tutorial-json
This tutorial explains how to read and save data in the portable JSON format. It focuses on saving the data generated by a visual servoing experiment and exporting it to Python in order to generate plots. - \subpage tutorial-synthetic-blenderproc
This tutorial shows you how to easily generate synthetic data from the 3D model of an object and obtain various modalities. This data can then be used to train a neural network for your own task. +- \subpage tutorial-spc
This tutorial shows you how to monitor if a signal is "in control" using Statistical Process Control methods. */ /*! \page tutorial_munkres Munkres Assignment Algorithm diff --git a/tutorial/mean-drift/tutorial-meandrift.cpp b/tutorial/mean-drift/tutorial-meandrift.cpp index 3e2b6701ba..2e3ea1887a 100644 --- a/tutorial/mean-drift/tutorial-meandrift.cpp +++ b/tutorial/mean-drift/tutorial-meandrift.cpp @@ -43,6 +43,7 @@ namespace TutorialMeanDrift { + //! [Enum_For_Test_Choice] /** * \brief Enumeration that permits to choose which process test to use. * @@ -57,6 +58,7 @@ typedef enum TypeTest COUNT_TYPE_TEST = 5, /*!< Number of different aavailable methods.*/ UNKOWN_TYPE_TEST = COUNT_TYPE_TEST /*!< Unknown method.*/ }TypeTest; +//! [Enum_For_Test_Choice] /** * \brief Permit to cast a \b TypeTest object into a string, for display purpose. @@ -296,6 +298,7 @@ unsigned int meanDriftArrayToNbActivated(const bool array[vpStatisticalTestAbstr return nbActivated; } +//! [Structure_Parameters] /** * \brief Structure that contains the parameters of the different algorithms. */ @@ -335,6 +338,7 @@ typedef struct ParametersForAlgo m_test_nbactivatedalarms = meanDriftArrayToNbActivated(m_test_activatedalarms); } }ParametersForAlgo; +//! [Structure_Parameters] } int testOnSynthetic(const TutorialMeanDrift::TypeTest &type, const TutorialMeanDrift::ParametersForAlgo parameters, @@ -342,12 +346,15 @@ int testOnSynthetic(const TutorialMeanDrift::TypeTest &type, const TutorialMeanD { const float dt = 10.f; // Emulate a 10ms period + //! [Plot_Init] vpPlot plotter(1); plotter.initGraph(0, 1); plotter.setTitle(0, "Evolution of the signal"); plotter.setUnitX(0, "Frame ID"); plotter.setUnitY(0, "No units"); + //! [Plot_Init] + //! [Test_Creat] unsigned int idFrame = 0; vpStatisticalTestAbstract *p_test = nullptr; switch (type) { @@ -372,15 +379,15 @@ int testOnSynthetic(const TutorialMeanDrift::TypeTest &type, const TutorialMeanD } if ((type == TutorialMeanDrift::HINLKEY_TYPE_TEST) && parameters.m_hinkley_computealphadelta) { + // Initialization of Hinkley's test in automatic mode delete p_test; p_test = new vpStatisticalTestHinkley(parameters.m_hinkley_h, parameters.m_hinkley_k, true, parameters.m_test_nbsamples); } + //! [Test_Creat] float signal; - std::cout << "Actual mean of the input signal: " << mean << std::endl; - std::cout << "Actual stdev of the input signal: " << stdev << std::endl; - std::cout << "Mean drift of the input signal: " << mean_drift << std::endl; + //! [Test_Init] // Initial computation of the mean and stdev of the input signal for (unsigned int i = 0; i < parameters.m_test_nbsamples; ++i) { vpGaussRand rndGen(stdev, mean, static_cast(idFrame) * dt); @@ -388,15 +395,17 @@ int testOnSynthetic(const TutorialMeanDrift::TypeTest &type, const TutorialMeanD p_test->testDownUpwardMeanDrift(signal); ++idFrame; } + //! [Test_Init] std::cout << "Estimated mean of the input signal: " << p_test->getMean() << std::endl; std::cout << "Estimated stdev of the input signal: " << p_test->getStdev() << std::endl; + //! [Loop_Monitor] float mean_eff = mean; bool hasToRun = true; vpStatisticalTestAbstract::vpMeanDriftType drift_type = vpStatisticalTestAbstract::MEAN_DRIFT_NONE; while (hasToRun) { - vpGaussRand rndGen(stdev, mean_eff, vpTime::measureTimeMs() * 1e3 + static_cast(idFrame) * dt); + vpGaussRand rndGen(stdev, mean_eff, static_cast(idFrame) * dt); signal = rndGen(); plotter.plot(0, 0, idFrame - parameters.m_test_nbsamples, signal); drift_type = p_test->testDownUpwardMeanDrift(signal); @@ -408,6 +417,9 @@ int testOnSynthetic(const TutorialMeanDrift::TypeTest &type, const TutorialMeanD ++idFrame; } } + //! [Loop_Monitor] + + //! [Failure_Debrief] std::cout << "Test failed at frame: " << idFrame - parameters.m_test_nbsamples << std::endl; std::cout << "Type of mean drift: " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift_type) << std::endl; std::cout << "Last signal value: " << signal << std::endl; @@ -444,8 +456,10 @@ int testOnSynthetic(const TutorialMeanDrift::TypeTest &type, const TutorialMeanD p_test->getLimits(limitDown, limitUp); std::cout << "\tLimit down = " << limitDown << std::endl; std::cout << "\tLimit up = " << limitUp << std::endl; + //! [Failure_Debrief] std::cout << "End of test on synthetic data. Press enter to leave." << std::endl; std::cin.get(); + delete p_test; return EXIT_SUCCESS; } @@ -673,6 +687,9 @@ int main(int argc, char *argv[]) std::cout << " Shewhart's test set of WECO rules : " << (parameters.m_shewhart_useWECO && (opt_typeTest == TutorialMeanDrift::SHEWHART_TYPE_TEST) ? TutorialMeanDrift::wecoRulesToString(parameters.m_shewhart_rules) : "N/A") << std::endl; std::cout << " Shewhart's test use WECO rules : " << (opt_typeTest == TutorialMeanDrift::SHEWHART_TYPE_TEST ? TutorialMeanDrift::boolToString(parameters.m_shewhart_useWECO && (opt_typeTest == TutorialMeanDrift::SHEWHART_TYPE_TEST)) : "N/A") << std::endl; std::cout << " Alarm factor Sigma test : " << (opt_typeTest == TutorialMeanDrift::SIGMA_TYPE_TEST ? TutorialMeanDrift::numberToString(parameters.m_sigma_h) : "N/A") << std::endl; + std::cout << " Actual mean of the input signal: " << opt_mean << std::endl; + std::cout << " Actual stdev of the input signal: " << opt_stdev << std::endl; + std::cout << " Mean drift of the input signal: " << opt_meandrift << std::endl; return testOnSynthetic(opt_typeTest, parameters, opt_mean, opt_meandrift, opt_stdev); } From 94cd90125c7a9d75f0a56437d5fbbe39618184dd Mon Sep 17 00:00:00 2001 From: rlagneau Date: Fri, 8 Mar 2024 11:54:52 +0100 Subject: [PATCH 05/12] [DOC] Documented the SPC classes --- doc/tutorial/misc/tutorial-spc.dox | 2 +- .../visp3/core/vpStatisticalTestEWMA.h | 26 ++++++- .../core/vpStatisticalTestMeanAdjustedCUSUM.h | 40 +++++++++- .../visp3/core/vpStatisticalTestShewhart.h | 75 ++++++++++++++----- .../visp3/core/vpStatisticalTestSigma.h | 20 ++++- .../math/misc/vpStatisticalTestShewhart.cpp | 4 +- tutorial/mean-drift/tutorial-meandrift.cpp | 2 + 7 files changed, 139 insertions(+), 30 deletions(-) diff --git a/doc/tutorial/misc/tutorial-spc.dox b/doc/tutorial/misc/tutorial-spc.dox index 8ce166f961..cc32c5d384 100644 --- a/doc/tutorial/misc/tutorial-spc.dox +++ b/doc/tutorial/misc/tutorial-spc.dox @@ -8,7 +8,7 @@ if a signal is "in control". In this tutorial, we will use a Statistical Process Control method to monitor if a -random signal following a Gaussian law is "in control". +random signal following a normal distribution is "in control". \subsection tuto-spc-intro-methods Available methods diff --git a/modules/core/include/visp3/core/vpStatisticalTestEWMA.h b/modules/core/include/visp3/core/vpStatisticalTestEWMA.h index b2df53beaa..134debf418 100644 --- a/modules/core/include/visp3/core/vpStatisticalTestEWMA.h +++ b/modules/core/include/visp3/core/vpStatisticalTestEWMA.h @@ -43,13 +43,35 @@ /** * \ingroup group_core_math_tools - * \brief Class that permits to perform Exponentially Weighted Moving Average mean shift tests. + * \brief Class that permits to perform Exponentially Weighted Moving Average mean drft tests. + * + * The EWMA test is designed to detect drift in the mean \f$ \mu \f$ + * of an observed signal \f$ s(t) \f$. + * + * The test signal \f$ w(t) \f$ is computed as follow: + * + * \f$ w(0) = \mu \f$ + * + * \f$ w(t) = \alpha s(t) + ( 1 - \alpha ) * w(t-1) \f$ + * + * Be \f$ \sigma \f$ the standard deviation of the input signal \f$ s(t) \f$. + * + * A downward alarm is raised if: + * \f$ w(t) <= \mu - 3 * \sigma * \sqrt{ \frac{\alpha}{2 - \alpha}}\f$ + * + * An upward alarm is raised if: + * \f$ w(t) >= \mu + 3 * \sigma * \sqrt{ \frac{\alpha}{2 - \alpha}}\f$ + * + * To detect only downward drifts of the input signal \f$ s(t) \f$ use + * testDownwardMeanDrift().To detect only upward drifts in \f$ s(t) \f$ use + * testUpwardMeanDrift(). To detect both, downward and upward drifts use + * testDownUpwardMeanDrift(). */ class VISP_EXPORT vpStatisticalTestEWMA : public vpStatisticalTestAbstract { protected: float m_alpha; /*!< Forgetting factor: the higher, the more weight the current signal value has.*/ - float m_wt; /*!< Test signal such as m_wt = m_alpha * y(t) + ( 1 - m_alpha ) * m_wtprev .*/ + float m_wt; /*!< Test signal that permits to raise an alarm.*/ float m_wtprev; /*!< Previous value of the test signal.*/ /** diff --git a/modules/core/include/visp3/core/vpStatisticalTestMeanAdjustedCUSUM.h b/modules/core/include/visp3/core/vpStatisticalTestMeanAdjustedCUSUM.h index 5bdd6f06f5..fdb9f09ebf 100644 --- a/modules/core/include/visp3/core/vpStatisticalTestMeanAdjustedCUSUM.h +++ b/modules/core/include/visp3/core/vpStatisticalTestMeanAdjustedCUSUM.h @@ -44,17 +44,49 @@ /** * \ingroup group_core_math_tools * \brief Class that permits to perform a mean adjusted Cumulative Sum test. + * + * The mean adjusted CUSUM test is designed to detect drift in the mean \f$ \mu \f$ + * of an observed signal \f$ s(t) \f$. + * + * Be \f$ \delta \f$ the amplitude of the mean drift we want to detect. + * Two test signals are computed at each iteration: + * + * \f$ S_-(t) = max\{0, S_-(t-1) - (s(t) - \mu) - \frac{\delta}{2}\} \f$ + * + * \f$ S_+(t) = max\{0, S_+(t-1) + (s(t) - \mu) - \frac{\delta}{2}\} \f$ + * + * A downward alarm is raised if: + * \f$ S_-(t) >= thresh\f$ + * + * An upward alarm is raised if: + * \f$ S_+(t) >= thresh\f$ + * + * To ease the understanding of the detection threshold \f$ \delta \f$ and the + * alarm threshold \f$ thresh \f$, ViSP implemented these two thresholds as + * a multiple of the standard deviation of the signal \f$ \sigma \f$: + * + * \f$ \delta = k \sigma , k \in R^{+*} \f$ + * + * \f$ thresh = h \sigma , h \in R^{+*} \f$ + * + * To have an Average Run Lenght of ~374 samples for a detection threshold \f$ \delta \f$ + * of 1 standard deviation \f$ \sigma \f$, set \f$ h \f$ to 4.76 . + * + * To detect only downward drifts of the input signal \f$ s(t) \f$ use + * testDownwardMeanDrift().To detect only upward drifts in \f$ s(t) \f$ use + * testUpwardMeanDrift(). To detect both, downward and upward drifts use + * testDownUpwardMeanDrift(). */ class VISP_EXPORT vpStatisticalTestMeanAdjustedCUSUM : public vpStatisticalTestAbstract { protected: float m_delta; /*!< Slack of the CUSUM test, i.e. amplitude of mean shift we want to be able to detect.*/ - float m_h; /*!< Alarm factor that permits to determine the limit telling when a mean shift occurs: limit = m_h * m_stdev . + float m_h; /*!< Alarm factor that permits to determine the limit telling when a mean shift occurs: \f$thresh = h * \sigma \f$ . To have an Average Run Lenght of ~374 samples for a detection of 1 stdev, set it to 4.76f*/ float m_half_delta; /*!< Half of the amplitude we want to detect.*/ - float m_k; /*!< Detection factor that permits to determine the slack: m_delta = m_k * m_stdev .*/ - float m_sminus; /*!< Test signal for downward mean shift: S_-(i) = max{0, S_-(i-1) - (y_i - m_mean) - m_delta/2}.*/ - float m_splus; /*!< Test signal for upward mean shift: S_+(i) = max{0, S_+(i-1) + (y_i - m_mean) - m_delta/2}.*/ + float m_k; /*!< Detection factor that permits to determine the slack: \f$\delta = k * \sigma\f$ .*/ + float m_sminus; /*!< Test signal for downward mean shift: \f$ S_-(t) = max\{0, S_-(t-1) - (s(t) - \mu) - \frac{\delta}{2}\} \f$.*/ + float m_splus; /*!< Test signal for upward mean shift: \f$ S_+(t) = max\{0, S_+(t-1) + (s(t) - \mu) - \frac{\delta}{2}\} \f$.*/ /** * \brief Compute the upper and lower limits of the test signal. diff --git a/modules/core/include/visp3/core/vpStatisticalTestShewhart.h b/modules/core/include/visp3/core/vpStatisticalTestShewhart.h index 22e9d66a3d..5dcfc37723 100644 --- a/modules/core/include/visp3/core/vpStatisticalTestShewhart.h +++ b/modules/core/include/visp3/core/vpStatisticalTestShewhart.h @@ -44,7 +44,30 @@ /** * \ingroup group_core_math_tools - * \brief Class that permits a Shewhart test. + * \brief Class that permits a Shewhart's test. + * + * Be \f$ s(t) \f$ the signal to monitor, \f$ \mu \f$ and \f$ \sigma \f$ the mean and standard deviation + * of this signal when it is "in control". + * + * A downward alarm is raised if: + * \f$ s(t) >= \mu - 3 \sigma \f$ + * + * An upward alarm is raised if: + * \f$ s(t) >= \mu + 3 \sigma \f$ + * + * Additionnally, we can activate the WECO's rules that have been + * proposed by the Western Electric Company to add additionnal verifications: + * - An alarm is raised if two out of three consecutive points fall beyond the \f$2\sigma\f$-limit, on the same side of the mean \f$ \mu \f$ + * - An alarm is raised if four out of five consecutive points fall beyond the \f$1\sigma\f$-limit, on the same side of the mean \f$ \mu \f$ + * - An alarm is raised if eight consecutive points fall on the same side of the mean \f$ \mu \f$. + * + * The user can decide to use or not the WECO's rules. Additionnally, the user can choose which WECO's + * rule(s) to activate. + * + * To detect only downward drifts of the input signal \f$ s(t) \f$ use + * testDownwardMeanDrift().To detect only upward drifts in \f$ s(t) \f$ use + * testUpwardMeanDrift(). To detect both, downward and upward drifts use + * testDownUpwardMeanDrift(). */ class VISP_EXPORT vpStatisticalTestShewhart : public vpStatisticalTestSigma @@ -52,12 +75,12 @@ class VISP_EXPORT vpStatisticalTestShewhart : public vpStatisticalTestSigma public: typedef enum vpWecoRulesAlarm { - THREE_SIGMA_WECO = 0, - TWO_SIGMA_WECO = 1, - ONE_SIGMA_WECO = 2, - SAME_SIDE_WECO = 3, - NONE_WECO = 4, - COUNT_WECO = 5 + THREE_SIGMA_WECO = 0, /*!< When a \f$ 3\sigma \f$ alarm was raised.*/ + TWO_SIGMA_WECO = 1, /*!< When a \f$ 2\sigma \f$ alarm was raised.*/ + ONE_SIGMA_WECO = 2, /*!< When a \f$ 1\sigma \f$ alarm was raised*/ + SAME_SIDE_WECO = 3, /*!< When a alarm raised when 8 consecutive points lie on the same side of the mean \f$ \mu \f$ was raised.*/ + NONE_WECO = 4, /*!< When no WECO's rule alarm was raised.*/ + COUNT_WECO = 5 /*!< Number of WECO's rules that are implemented.*/ } vpWecoRulesAlarm; static std::string vpWecoRulesAlarmToString(const vpWecoRulesAlarm &alarm); @@ -68,17 +91,17 @@ class VISP_EXPORT vpStatisticalTestShewhart : public vpStatisticalTestSigma static const int NB_DATA_SIGNAL = 8; unsigned int m_nbDataInBuffer; /*!< Indicate how many data are available in the circular buffer.*/ float m_signal[NB_DATA_SIGNAL]; /*!< The last values of the signal.*/ - bool m_activateWECOrules; /*!< If true, activate the WECO rules (NB: it increases the sensitivity of the Shewhart + bool m_activateWECOrules; /*!< If true, activate the WECO's rules (NB: it increases the sensitivity of the Shewhart control chart but the false alarm frequency is also increased.)*/ - bool m_activatedWECOrules[COUNT_WECO - 1]; /*!< The WECO rules that are activated. The more are activated, the higher the + bool m_activatedWECOrules[COUNT_WECO - 1]; /*!< The WECO's rules that are activated. The more are activated, the higher the sensitivity of the Shewhart control chart is but the higher the false alarm frequency is.*/ int m_idCurrentData; /*!< The index of the current data in m_signal.*/ - vpWecoRulesAlarm m_alarm; /*!< The type of alarm raised due to WECO rules.*/ - float m_oneSigmaNegLim; /*!< The mean - sigma lower threshold.*/ - float m_oneSigmaPosLim; /*!< The mean + sigma lower threshold.*/ - float m_twoSigmaNegLim; /*!< The mean - 2 sigma lower threshold.*/ - float m_twoSigmaPosLim; /*!< The mean + 2 sigma lower threshold.*/ + vpWecoRulesAlarm m_alarm; /*!< The type of alarm raised due to WECO's rules.*/ + float m_oneSigmaNegLim; /*!< The \f$ \mu - \sigma \* threshold.*/ + float m_oneSigmaPosLim; /*!< The \f$ \mu + \sigma \* threshold.*/ + float m_twoSigmaNegLim; /*!< The \f$ \mu - 2 \sigma \* threshold.*/ + float m_twoSigmaPosLim; /*!< The \f$ \mu + 2 \sigma \* threshold.*/ /** * \brief Compute the upper and lower limits of the test signal. @@ -141,8 +164,10 @@ class VISP_EXPORT vpStatisticalTestShewhart : public vpStatisticalTestSigma /** * \brief Construct a new vpStatisticalTestShewhart object. * - * \param[in] activateWECOrules If true, activate the WECO rules (NB: it increases the sensitivity of the Shewhart + * \param[in] activateWECOrules If true, activate the WECO's rules (NB: it increases the sensitivity of the Shewhart * control chart but the false alarm frequency is also increased.) + * \param[in] activatedRules An array where true means that the corresponding WECO's rule is activated and false means + * that it is not. * \param[in] nbSamplesForStats The number of samples to compute the statistics of the signal. */ vpStatisticalTestShewhart(const bool &activateWECOrules = true, const bool activatedRules[COUNT_WECO - 1] = CONST_ALL_WECO_ACTIVATED, const unsigned int &nbSamplesForStats = 30); @@ -150,15 +175,17 @@ class VISP_EXPORT vpStatisticalTestShewhart : public vpStatisticalTestSigma /** * \brief Construct a new vpStatisticalTestShewhart object. * - * \param[in] activateWECOrules If true, activate the WECO rules (NB: it increases the sensitivity of the Shewhart + * \param[in] activateWECOrules If true, activate the WECO's rules (NB: it increases the sensitivity of the Shewhart * control chart but the false alarm frequency is also increased.) + * \param[in] activatedRules An array where true means that the corresponding WECO's rule is activated and false means + * that it is not. * \param[in] mean The expected mean of the signal. * \param[in] stdev The expected standard deviation of the signal. */ vpStatisticalTestShewhart(const bool &activateWECOrules, const bool activatedRules[COUNT_WECO - 1], const float &mean, const float &stdev); /** - * \brief Get the alarm raised by the last test due to the WECO rules. + * \brief Get the alarm raised by the last test due to the WECO's rules. * * \return vpWecoRulesAlarm The type of raised alarm. */ @@ -172,7 +199,11 @@ class VISP_EXPORT vpStatisticalTestShewhart : public vpStatisticalTestSigma * * \return float The signal. */ - inline float getSignal() const +#if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_11) + inline virtual float getSignal() const override +#else + inline virtual float getSignal() const +#endif { return m_signal[m_idCurrentData]; } @@ -187,8 +218,10 @@ class VISP_EXPORT vpStatisticalTestShewhart : public vpStatisticalTestSigma /** * \brief (Re)Initialize the test. * - * \param[in] activateWECOrules If true, activate the WECO rules (NB: it increases the sensitivity of the Shewhart + * \param[in] activateWECOrules If true, activate the WECO's rules (NB: it increases the sensitivity of the Shewhart * control chart but the false alarm frequency is also increased.) + * \param[in] activatedRules An array where true means that the corresponding WECO's rule is activated and false means + * that it is not. * \param[in] nbSamplesForStats The number of samples to compute the statistics of the signal. */ void init(const bool &activateWECOrules, const bool activatedRules[COUNT_WECO - 1] = CONST_ALL_WECO_ACTIVATED, const unsigned int &nbSamplesForStats = 30); @@ -196,8 +229,10 @@ class VISP_EXPORT vpStatisticalTestShewhart : public vpStatisticalTestSigma /** * \brief (Re)Initialize the test. * - * \param[in] activateWECOrules If true, activate the WECO rules (NB: it increases the sensitivity of the Shewhart + * \param[in] activateWECOrules If true, activate the WECO's rules (NB: it increases the sensitivity of the Shewhart * control chart but the false alarm frequency is also increased.) + * \param[in] activatedRules An array where true means that the corresponding WECO's rule is activated and false means + * that it is not. * \param[in] mean The expected mean of the signal. * \param[in] stdev The expected standard deviation of the signal. */ diff --git a/modules/core/include/visp3/core/vpStatisticalTestSigma.h b/modules/core/include/visp3/core/vpStatisticalTestSigma.h index 94476df584..3c0f10facd 100644 --- a/modules/core/include/visp3/core/vpStatisticalTestSigma.h +++ b/modules/core/include/visp3/core/vpStatisticalTestSigma.h @@ -45,6 +45,24 @@ * \ingroup group_core_math_tools * \brief Class that permits a simple test comparing the current value to the * standard deviation of the signal. + * + * Be \f$ s(t) \f$ the signal to monitor, \f$ \mu \f$ and \f$ \sigma \f$ the mean and standard deviation + * of this signal when it is "in control". + * + * Be \f$ h \f$ a user-defined alarm factor. + * + * A downward alarm is raised if: + * \f$ s(t) >= \mu - h \sigma \f$ + * + * An upward alarm is raised if: + * \f$ s(t) >= \mu - h \sigma \f$ + * + * \f$ h \f$ is often set to 3 if we assume the \f$ s(t) \f$ follows a normal distribution. + * + * To detect only downward drifts of the input signal \f$ s(t) \f$ use + * testDownwardMeanDrift().To detect only upward drifts in \f$ s(t) \f$ use + * testUpwardMeanDrift(). To detect both, downward and upward drifts use + * testDownUpwardMeanDrift(). */ class VISP_EXPORT vpStatisticalTestSigma : public vpStatisticalTestAbstract @@ -129,7 +147,7 @@ class VISP_EXPORT vpStatisticalTestSigma : public vpStatisticalTestAbstract * * \return float The signal. */ - inline float getS() const + inline virtual float getSignal() const { return m_s; } diff --git a/modules/core/src/math/misc/vpStatisticalTestShewhart.cpp b/modules/core/src/math/misc/vpStatisticalTestShewhart.cpp index 794e8aea27..cc1be99cec 100644 --- a/modules/core/src/math/misc/vpStatisticalTestShewhart.cpp +++ b/modules/core/src/math/misc/vpStatisticalTestShewhart.cpp @@ -88,7 +88,7 @@ vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestShewhart::detectDown return vpStatisticalTestAbstract::MEAN_DRIFT_NONE; } if ((m_signal[m_idCurrentData] <= m_limitDown) && m_activatedWECOrules[THREE_SIGMA_WECO]) { - m_alarm = vpWecoRulesAlarm::THREE_SIGMA_WECO; + m_alarm = THREE_SIGMA_WECO; return vpStatisticalTestAbstract::MEAN_DRIFT_DOWNWARD; } if (!m_activateWECOrules) { @@ -160,7 +160,7 @@ vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestShewhart::detectUpwa return vpStatisticalTestAbstract::MEAN_DRIFT_NONE; } if ((m_signal[m_idCurrentData] >= m_limitUp) && m_activatedWECOrules[THREE_SIGMA_WECO]) { - m_alarm = vpWecoRulesAlarm::THREE_SIGMA_WECO; + m_alarm = THREE_SIGMA_WECO; return vpStatisticalTestAbstract::MEAN_DRIFT_UPWARD; } if (!m_activateWECOrules) { diff --git a/tutorial/mean-drift/tutorial-meandrift.cpp b/tutorial/mean-drift/tutorial-meandrift.cpp index 2e3ea1887a..181e94906d 100644 --- a/tutorial/mean-drift/tutorial-meandrift.cpp +++ b/tutorial/mean-drift/tutorial-meandrift.cpp @@ -32,6 +32,8 @@ //! \example tutorial-meandrift.cpp +#include //std::memcpy + #include #include #include From 54a2513d0419809f81ed6c3739a01a56811a1e08 Mon Sep 17 00:00:00 2001 From: rlagneau Date: Fri, 8 Mar 2024 16:37:27 +0100 Subject: [PATCH 06/12] [TEST] Added unit tests for SPC classes --- .../visp3/core/vpStatisticalTestShewhart.h | 2 +- .../math/misc/vpStatisticalTestShewhart.cpp | 2 +- modules/core/test/math/testSPC.cpp | 809 ++++++++++++++++++ tutorial/mean-drift/tutorial-meandrift.cpp | 8 + 4 files changed, 819 insertions(+), 2 deletions(-) create mode 100644 modules/core/test/math/testSPC.cpp diff --git a/modules/core/include/visp3/core/vpStatisticalTestShewhart.h b/modules/core/include/visp3/core/vpStatisticalTestShewhart.h index 5dcfc37723..584658b0ec 100644 --- a/modules/core/include/visp3/core/vpStatisticalTestShewhart.h +++ b/modules/core/include/visp3/core/vpStatisticalTestShewhart.h @@ -86,9 +86,9 @@ class VISP_EXPORT vpStatisticalTestShewhart : public vpStatisticalTestSigma static std::string vpWecoRulesAlarmToString(const vpWecoRulesAlarm &alarm); static const bool CONST_ALL_WECO_ACTIVATED[COUNT_WECO - 1]; + static const int NB_DATA_SIGNAL = 8; protected: - static const int NB_DATA_SIGNAL = 8; unsigned int m_nbDataInBuffer; /*!< Indicate how many data are available in the circular buffer.*/ float m_signal[NB_DATA_SIGNAL]; /*!< The last values of the signal.*/ bool m_activateWECOrules; /*!< If true, activate the WECO's rules (NB: it increases the sensitivity of the Shewhart diff --git a/modules/core/src/math/misc/vpStatisticalTestShewhart.cpp b/modules/core/src/math/misc/vpStatisticalTestShewhart.cpp index cc1be99cec..b30bcf0a1f 100644 --- a/modules/core/src/math/misc/vpStatisticalTestShewhart.cpp +++ b/modules/core/src/math/misc/vpStatisticalTestShewhart.cpp @@ -104,7 +104,7 @@ vpStatisticalTestAbstract::vpMeanDriftType vpStatisticalTestShewhart::detectDown // Reinit for next iteration nbAbove2SigmaLimit = 0; nbAbove1SigmaLimit = 0; - if (m_signal[id] <= m_mean && m_activatedWECOrules[SAME_SIDE_WECO]) { + if (m_signal[id] < m_mean && m_activatedWECOrules[SAME_SIDE_WECO]) { // Single-side test ++nbAboveMean; } diff --git a/modules/core/test/math/testSPC.cpp b/modules/core/test/math/testSPC.cpp new file mode 100644 index 0000000000..407330060b --- /dev/null +++ b/modules/core/test/math/testSPC.cpp @@ -0,0 +1,809 @@ +/**************************************************************************** + * + * ViSP, open source Visual Servoing Platform software. + * Copyright (C) 2005 - 2023 by Inria. All rights reserved. + * + * This software is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * See the file LICENSE.txt at the root directory of this source + * distribution for additional information about the GNU GPL. + * + * For using ViSP with software that can not be combined with the GNU + * GPL, please contact Inria about acquiring a ViSP Professional + * Edition License. + * + * See https://visp.inria.fr for more information. + * + * This software was developed at: + * Inria Rennes - Bretagne Atlantique + * Campus Universitaire de Beaulieu + * 35042 Rennes Cedex + * France + * + * If you have questions regarding the use of this file, please contact + * Inria at visp@inria.fr + * + * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE + * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Description: + * Test various Statistical Process Control methods. + */ + +/*! + \example testSPC.cpp + \brief Test various Statistical Process Control methods. +*/ + +#include +#include + +#include +#include +#include +#include +#include + +bool initializeShewhartTest(const float &mean, const float &stdev, const bool &verbose, const std::string &testName, vpStatisticalTestShewhart &tester) +{ + const bool activateWECOrules = true; + tester.init(activateWECOrules, vpStatisticalTestShewhart::CONST_ALL_WECO_ACTIVATED, mean, stdev); + bool isInitOK = true; + const vpStatisticalTestAbstract::vpMeanDriftType EXPECTED_DRIFT_INIT = vpStatisticalTestAbstract::MEAN_DRIFT_NONE; + vpStatisticalTestAbstract::vpMeanDriftType drift; + unsigned int i = 0; + while ((i < vpStatisticalTestShewhart::NB_DATA_SIGNAL - 1) && isInitOK) { + drift = tester.testDownUpwardMeanDrift(mean); + isInitOK = (drift == EXPECTED_DRIFT_INIT); + if (isInitOK) { + ++i; + } + } + if (!isInitOK) { + if (verbose) { + std::cerr << "\t" << testName << " test initialization failed: " << std::endl; + std::cerr << "\t\ts(t) = " << tester.getSignal() << std::endl; + float limitDown = 0.f, limitUp = 0.f; + tester.getLimits(limitDown, limitUp); + std::cerr << "\t\tlim_- = " << limitDown << std::endl; + std::cerr << "\t\tlim_+ = " << limitUp << std::endl; + std::cerr << "\t\tdetected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl; + std::cerr << "\t\texpected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(EXPECTED_DRIFT_INIT) << std::endl; + } + } + return isInitOK; +} + +void usage(const char *name) +{ + std::cout << "SYNOPSIS " << std::endl; + std::cout << name << "[--mean ] [--stdev ] [-v, --verbose] [-h, --help]" << std::endl; + std::cout << "\nOPTIONS" << std::endl; + std::cout << " --mean" << std::endl; + std::cout << " Permits to set the mean of the input signal." << std::endl; + std::cout << std::endl; + std::cout << " --stdev" << std::endl; + std::cout << " Permits to set the standard deviation of the input signal." << std::endl; + std::cout << std::endl; + std::cout << " -v, --verbose" << std::endl; + std::cout << " Activate verbose mode." << std::endl; + std::cout << std::endl; + std::cout << " -h, --help" << std::endl; + std::cout << " Display the help." << std::endl; + std::cout << std::endl; +} + +bool getOptions(int argc, const char **argv, float &opt_mean, float &opt_stdev, bool &opt_verbose) +{ + int i = 1; + while (i < argc) { + std::string argname(argv[i]); + if ((argname == "--mean") && ((i + 1) < argc)) { + opt_mean = std::atof(argv[i + 1]); + ++i; + } + else if ((argname == "--stdev") && ((i + 1) < argc)) { + opt_stdev = std::atof(argv[i + 1]); + ++i; + } + else if ((argname == "-v") || (argname == "--verbose")) { + opt_verbose = true; + } + else if ((argname == "-h") || (argname == "--help")) { + usage(argv[0]); + return false; + } + else if ((argname == "-c") || (argname == "-d")) { + // Arguments given by CTest by default, do nothing + } + else { + usage(argv[0]); + std::cerr << "Error: unrecognised argument \"" << argv[i] << "\"" << std::endl; + return false; + } + ++i; + } + return true; +} + +int main(int argc, const char **argv) +{ + float opt_mean = 0.f; + float opt_stdev = 1.f; + bool opt_verbose = false; + + bool isParsingOk = getOptions(argc, argv, opt_mean, opt_stdev, opt_verbose); + if (!isParsingOk) { + return EXIT_FAILURE; + } + + bool success = true; + + // vpStatisticalTestEWMA tests + { + if (opt_verbose) { + std::cout << "------ vpStatisticalTestEWMA tests ------" << std::endl; + } + const float alpha = 0.1f; + vpStatisticalTestEWMA tester(alpha); + + // ---- Upward drift test ---- + { + tester.init(alpha, opt_mean, opt_stdev); + + // w(t = 1) >= mu + 3 sigma sqrt(alpha / (2 - alpha)) + // <=> alpha s(t=1) + (1 - alpha) mu >= mu + 3 sigma sqrt(alpha / (2 - alpha)) + // <=> s(t=1) >= (1 / alpha) (alpha mu + 3 sigma sqrt(alpha / (2 - alpha)) + float signal = (1.f / alpha) * (alpha * opt_mean + 3.f * opt_stdev * std::sqrt(alpha / (2.f - alpha))); + signal += 0.5f; // To be sure we are greater than the threshold + vpStatisticalTestAbstract::vpMeanDriftType drift = tester.testDownUpwardMeanDrift(signal); + if (drift != vpStatisticalTestAbstract::MEAN_DRIFT_UPWARD) { + success = false; + if (opt_verbose) { + std::cerr << "Upward drift test failed: " << std::endl; + std::cerr << "\tw(t) = " << tester.getWt() << std::endl; + float limitDown = 0.f, limitUp = 0.f; + tester.getLimits(limitDown, limitUp); + std::cerr << "\tlimit_up = " << limitUp << std::endl; + } + } + else if (opt_verbose) { + std::cout << "Upward drift test succeeded." << std::endl; + } + } + + // ---- Downward drift test ---- + { + tester.init(alpha, opt_mean, opt_stdev); + // w(t = 1) <= mu - 3 sigma sqrt(alpha / (2 - alpha)) + // <=> alpha s(t=1) + (1 - alpha) mu <= mu - 3 sigma sqrt(alpha / (2 - alpha)) + // <=> s(t=1) <= (1 / alpha) (alpha mu - 3 sigma sqrt(alpha / (2 - alpha)) + float signal = (1.f / alpha) * (alpha * opt_mean - 3.f * opt_stdev * std::sqrt(alpha / (2.f - alpha))); + signal -= 0.5f; // To be sure we are greater than the threshold + vpStatisticalTestAbstract::vpMeanDriftType drift = tester.testDownUpwardMeanDrift(signal); + if (drift != vpStatisticalTestAbstract::MEAN_DRIFT_DOWNWARD) { + success = false; + if (opt_verbose) { + std::cerr << "Downward drift test failed: " << std::endl; + std::cerr << "\tw(t) = " << tester.getWt() << std::endl; + float limitDown = 0.f, limitUp = 0.f; + tester.getLimits(limitDown, limitUp); + std::cerr << "\tlimit_down = " << limitDown << std::endl; + } + } + else if (opt_verbose) { + std::cout << "Downward drift test succeeded." << std::endl; + } + } + } + + // vpStatisticalTestHinkley tests + { + if (opt_verbose) { + std::cout << "------ vpStatisticalTestHinkley tests ------" << std::endl; + } + + const float h = 4.76f, k = 1.f; + vpStatisticalTestHinkley tester(h, k, opt_mean, opt_stdev); + const unsigned int HINKLEY_NB_DATA = 4; + const float HINKLEY_SAMPLE = 2.f * opt_stdev; + + // Hinkley's test upward drift + { + const float HINKLEY_DATA[HINKLEY_NB_DATA] = { HINKLEY_SAMPLE, HINKLEY_SAMPLE, HINKLEY_SAMPLE, HINKLEY_SAMPLE }; + const vpStatisticalTestAbstract::vpMeanDriftType HINKLEY_EXPECTED_RES[HINKLEY_NB_DATA] = { vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_UPWARD }; + bool isTestOk = true; + unsigned int id = 0; + vpStatisticalTestAbstract::vpMeanDriftType drift; + while ((id < HINKLEY_NB_DATA) && isTestOk) { + drift = tester.testDownUpwardMeanDrift(HINKLEY_DATA[id]); + isTestOk = (drift == HINKLEY_EXPECTED_RES[id]); + if (isTestOk) { + ++id; + } + } + if (!isTestOk) { + success = false; + if (opt_verbose) { + std::cerr << "Upward drift test failed: " << std::endl; + float Tk = tester.getTk(), Nk = tester.getNk(); + std::cerr << "T(k) = " << Tk << " | N(k) = " << Nk << " => S+(k) = " << Tk - Nk << std::endl; + float limitDown = 0.f, limitUp = 0.f; + tester.getLimits(limitDown, limitUp); + std::cerr << "lim_+ = " << limitUp << std::endl; + std::cerr << "drift type : " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl; + std::cerr << "expected drift type : " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(HINKLEY_EXPECTED_RES[id]) << std::endl; + } + } + else if (opt_verbose) { + std::cout << "Upward drift test succeeded." << std::endl; + } + } + + // Hinkley's test downward drift + { + const float HINKLEY_DATA[HINKLEY_NB_DATA] = { -1.f * HINKLEY_SAMPLE, -1.f * HINKLEY_SAMPLE, -1.f * HINKLEY_SAMPLE, -1.f * HINKLEY_SAMPLE }; + const vpStatisticalTestAbstract::vpMeanDriftType HINKLEY_EXPECTED_RES[HINKLEY_NB_DATA] = { vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_DOWNWARD }; + bool isTestOk = true; + unsigned int id = 0; + vpStatisticalTestAbstract::vpMeanDriftType drift; + while ((id < HINKLEY_NB_DATA) && isTestOk) { + drift = tester.testDownUpwardMeanDrift(HINKLEY_DATA[id]); + isTestOk = (drift == HINKLEY_EXPECTED_RES[id]); + if (isTestOk) { + ++id; + } + } + if (!isTestOk) { + success = false; + if (opt_verbose) { + std::cerr << "Downward drift test failed: " << std::endl; + float Sk = tester.getSk(), Mk = tester.getMk(); + std::cerr << "S(k) = " << Sk << " | M(k) = " << Mk << " => S+(k) = " << Mk - Sk << std::endl; + float limitDown = 0.f, limitUp = 0.f; + tester.getLimits(limitDown, limitUp); + std::cerr << "lim_- = " << limitDown << std::endl; + std::cerr << "drift type : " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl; + std::cerr << "expected drift type : " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(HINKLEY_EXPECTED_RES[id]) << std::endl; + } + } + else if (opt_verbose) { + std::cout << "Downward drift test succeeded." << std::endl; + } + } + } + + // vpStatisticalTestMeanAdjustedCUSUM tests + { + if (opt_verbose) { + std::cout << "------ vpStatisticalTestMeanAdjustedCUSUM tests ------" << std::endl; + } + + const float h = 4.76f, k = 1.f; + vpStatisticalTestMeanAdjustedCUSUM tester(h, k); + tester.init(h, k, opt_mean, opt_stdev); + const unsigned int CUSUM_NB_DATA = 4; + const float CUSUM_SAMPLE = 2.f * opt_stdev; + + // Mean adjusted CUSUM test upward drift + { + const float CUSUM_DATA[CUSUM_NB_DATA] = { CUSUM_SAMPLE, CUSUM_SAMPLE, CUSUM_SAMPLE, CUSUM_SAMPLE }; + const vpStatisticalTestAbstract::vpMeanDriftType CUSUM_EXPECTED_RES[CUSUM_NB_DATA] = { vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_UPWARD }; + bool isTestOk = true; + unsigned int id = 0; + vpStatisticalTestAbstract::vpMeanDriftType drift; + while ((id < CUSUM_NB_DATA) && isTestOk) { + drift = tester.testDownUpwardMeanDrift(CUSUM_DATA[id]); + isTestOk = (drift == CUSUM_EXPECTED_RES[id]); + if (isTestOk) { + ++id; + } + } + if (!isTestOk) { + success = false; + if (opt_verbose) { + std::cerr << "Upward drift test failed: " << std::endl; + std::cerr << "\tS+(k) = " << tester.getTestSignalPlus() << std::endl; + float limitDown = 0.f, limitUp = 0.f; + tester.getLimits(limitDown, limitUp); + std::cerr << "\tlim_+ = " << limitUp << std::endl; + std::cerr << "\tdrift type : " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl; + std::cerr << "\texpected drift type : " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(CUSUM_EXPECTED_RES[id]) << std::endl; + } + } + else if (opt_verbose) { + std::cout << "Upward drift test succeeded." << std::endl; + } + } + + // Mean adjusted CUSUM test upward drift + { + const float CUSUM_DATA[CUSUM_NB_DATA] = { -1.f * CUSUM_SAMPLE, -1.f * CUSUM_SAMPLE, -1.f * CUSUM_SAMPLE, -1.f * CUSUM_SAMPLE }; + const vpStatisticalTestAbstract::vpMeanDriftType CUSUM_EXPECTED_RES[CUSUM_NB_DATA] = { vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_DOWNWARD }; + bool isTestOk = true; + unsigned int id = 0; + vpStatisticalTestAbstract::vpMeanDriftType drift; + while ((id < CUSUM_NB_DATA) && isTestOk) { + drift = tester.testDownUpwardMeanDrift(CUSUM_DATA[id]); + isTestOk = (drift == CUSUM_EXPECTED_RES[id]); + if (isTestOk) { + ++id; + } + } + if (!isTestOk) { + success = false; + if (opt_verbose) { + std::cerr << "Downward drift test failed: " << std::endl; + std::cerr << "\tS-(k) = " << tester.getTestSignalMinus() << std::endl; + float limitDown = 0.f, limitUp = 0.f; + tester.getLimits(limitDown, limitUp); + std::cerr << "\tlim_- = " << limitDown << std::endl; + std::cerr << "\tdrift type : " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl; + std::cerr << "\texpected drift type : " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(CUSUM_EXPECTED_RES[id]) << std::endl; + } + } + else if (opt_verbose) { + std::cout << "Downward drift test succeeded." << std::endl; + } + } + } + + // vpStatisticalTestShewhart tests + { + if (opt_verbose) { + std::cout << "------ vpStatisticalTestShewhart tests ------" << std::endl; + } + const bool activateWECOrules = true; + vpStatisticalTestShewhart tester(activateWECOrules, vpStatisticalTestShewhart::CONST_ALL_WECO_ACTIVATED, opt_mean, opt_stdev); + + // Upward drift test + { + if (opt_verbose) { + std::cout << "Upward drift tests" << std::endl; + } + + // 3-sigma test + { + bool isInitOK = initializeShewhartTest(opt_mean, opt_stdev, opt_verbose, "3-sigma", tester); + if (!isInitOK) { + success = false; + } + else { + const float signal = 3.5f * opt_stdev; + vpStatisticalTestAbstract::vpMeanDriftType drift = tester.testDownUpwardMeanDrift(signal); + vpStatisticalTestShewhart::vpWecoRulesAlarm alarm = tester.getAlarm(); + const vpStatisticalTestAbstract::vpMeanDriftType EXPECTED_DRIFT = vpStatisticalTestAbstract::MEAN_DRIFT_UPWARD; + const vpStatisticalTestShewhart::vpWecoRulesAlarm EXPECTED_ALARM = vpStatisticalTestShewhart::THREE_SIGMA_WECO; + if ((drift != EXPECTED_DRIFT) || (alarm != EXPECTED_ALARM)) { + success = false; + if (opt_verbose) { + std::cerr << "\t3-sigma test failed: " << std::endl; + std::vector s = tester.getSignals(); + std::cerr << "\t\ts(t) = [ "; + for (size_t i = 0; i < s.size(); ++i) { + std::cerr << s[i] << " "; + } + std::cerr << "]" << std::endl; + float limitDown = 0.f, limitUp = 0.f; + tester.getLimits(limitDown, limitUp); + std::cerr << "\t\tlim_+ = " << limitUp << std::endl; + std::cerr << "\t\tdetected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl; + std::cerr << "\t\texpected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(EXPECTED_DRIFT) << std::endl; + std::cerr << "\t\tdetected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(alarm) << std::endl; + std::cerr << "\t\texpected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(EXPECTED_ALARM) << std::endl; + } + } + else if (opt_verbose) { + std::cout << "\t3-sigma test succeeded " << std::endl; + } + } + } + + // 2-sigma test + { + bool isInitOK = initializeShewhartTest(opt_mean, opt_stdev, opt_verbose, "2-sigma", tester); + if (!isInitOK) { + success = false; + } + else { + const unsigned int NB_SAMPLES = 3; + const float DATA[NB_SAMPLES] = { 2.75f * opt_stdev, 1.5f * opt_stdev, 2.5f * opt_stdev }; + const vpStatisticalTestAbstract::vpMeanDriftType EXPECTED_DRIFT[NB_SAMPLES] = { vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_UPWARD }; + const vpStatisticalTestShewhart::vpWecoRulesAlarm EXPECTED_ALARM[NB_SAMPLES] = { vpStatisticalTestShewhart::NONE_WECO, vpStatisticalTestShewhart::NONE_WECO, vpStatisticalTestShewhart::TWO_SIGMA_WECO }; + vpStatisticalTestAbstract::vpMeanDriftType drift; + vpStatisticalTestShewhart::vpWecoRulesAlarm alarm = tester.getAlarm(); + unsigned int i = 0; + bool isTestOk = true; + while ((i < NB_SAMPLES) && isTestOk) { + drift = tester.testDownUpwardMeanDrift(DATA[i]); + alarm = tester.getAlarm(); + isTestOk = ((drift == EXPECTED_DRIFT[i]) && (alarm == EXPECTED_ALARM[i])); + if (isTestOk) { + ++i; + } + } + + if (!isTestOk) { + success = false; + if (opt_verbose) { + std::cerr << "\t2-sigma test failed: " << std::endl; + std::vector s = tester.getSignals(); + std::cerr << "\t\ts(t) = [ "; + for (size_t i = 0; i < s.size(); ++i) { + std::cerr << s[i] << " "; + } + std::cerr << "]" << std::endl; + float limitDown = 0.f, limitUp = 0.f; + tester.getLimits(limitDown, limitUp); + std::cerr << "\t\tlim_+ = " << limitUp << std::endl; + std::cerr << "\t\tdetected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl; + std::cerr << "\t\texpected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(EXPECTED_DRIFT[i]) << std::endl; + std::cerr << "\t\tdetected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(alarm) << std::endl; + std::cerr << "\t\texpected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(EXPECTED_ALARM[i]) << std::endl; + } + } + else if (opt_verbose) { + std::cout << "\t2-sigma test succeeded " << std::endl; + } + } + } + + // 1-sigma test + { + bool isInitOK = initializeShewhartTest(opt_mean, opt_stdev, opt_verbose, "1-sigma", tester); + if (!isInitOK) { + success = false; + } + else { + const unsigned int NB_SAMPLES = 5; + 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 }; + const vpStatisticalTestAbstract::vpMeanDriftType EXPECTED_DRIFT[NB_SAMPLES] = { vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_UPWARD }; + const vpStatisticalTestShewhart::vpWecoRulesAlarm EXPECTED_ALARM[NB_SAMPLES] = { vpStatisticalTestShewhart::NONE_WECO, vpStatisticalTestShewhart::NONE_WECO, vpStatisticalTestShewhart::NONE_WECO, vpStatisticalTestShewhart::NONE_WECO, vpStatisticalTestShewhart::ONE_SIGMA_WECO }; + vpStatisticalTestAbstract::vpMeanDriftType drift; + vpStatisticalTestShewhart::vpWecoRulesAlarm alarm = tester.getAlarm(); + unsigned int i = 0; + bool isTestOk = true; + while ((i < NB_SAMPLES) && isTestOk) { + drift = tester.testDownUpwardMeanDrift(DATA[i]); + alarm = tester.getAlarm(); + isTestOk = ((drift == EXPECTED_DRIFT[i]) && (alarm == EXPECTED_ALARM[i])); + if (isTestOk) { + ++i; + } + } + + if (!isTestOk) { + success = false; + if (opt_verbose) { + std::cerr << "\t1-sigma test failed: " << std::endl; + std::vector s = tester.getSignals(); + std::cerr << "\t\ts(t) = [ "; + for (size_t i = 0; i < s.size(); ++i) { + std::cerr << s[i] << " "; + } + std::cerr << "]" << std::endl; + float limitDown = 0.f, limitUp = 0.f; + tester.getLimits(limitDown, limitUp); + std::cerr << "\t\tlim_+ = " << limitUp << std::endl; + std::cerr << "\t\tdetected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl; + std::cerr << "\t\texpected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(EXPECTED_DRIFT[i]) << std::endl; + std::cerr << "\t\tdetected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(alarm) << std::endl; + std::cerr << "\t\texpected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(EXPECTED_ALARM[i]) << std::endl; + } + } + else if (opt_verbose) { + std::cout << "\t1-sigma test succeeded " << std::endl; + } + } + } + + // Same-side test + { + bool isInitOK = initializeShewhartTest(opt_mean, opt_stdev, opt_verbose, "Same-side", tester); + if (!isInitOK) { + success = false; + } + else { + const unsigned int NB_SAMPLES = 8; + 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 }; + const vpStatisticalTestAbstract::vpMeanDriftType EXPECTED_DRIFT[NB_SAMPLES] = { vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_UPWARD }; + const vpStatisticalTestShewhart::vpWecoRulesAlarm EXPECTED_ALARM[NB_SAMPLES] = { vpStatisticalTestShewhart::NONE_WECO, vpStatisticalTestShewhart::NONE_WECO, vpStatisticalTestShewhart::NONE_WECO, vpStatisticalTestShewhart::NONE_WECO, vpStatisticalTestShewhart::NONE_WECO, vpStatisticalTestShewhart::NONE_WECO, vpStatisticalTestShewhart::NONE_WECO, vpStatisticalTestShewhart::SAME_SIDE_WECO }; + vpStatisticalTestAbstract::vpMeanDriftType drift; + vpStatisticalTestShewhart::vpWecoRulesAlarm alarm = tester.getAlarm(); + unsigned int i = 0; + bool isTestOk = true; + while ((i < NB_SAMPLES) && isTestOk) { + drift = tester.testDownUpwardMeanDrift(DATA[i]); + alarm = tester.getAlarm(); + isTestOk = ((drift == EXPECTED_DRIFT[i]) && (alarm == EXPECTED_ALARM[i])); + if (isTestOk) { + ++i; + } + } + + if (!isTestOk) { + success = false; + if (opt_verbose) { + std::cerr << "\tSame-side test failed: " << std::endl; + std::vector s = tester.getSignals(); + std::cerr << "\t\ts(t) = [ "; + for (size_t i = 0; i < s.size(); ++i) { + std::cerr << s[i] << " "; + } + std::cerr << "]" << std::endl; + float limitDown = 0.f, limitUp = 0.f; + tester.getLimits(limitDown, limitUp); + std::cerr << "\t\tlim_+ = " << limitUp << std::endl; + std::cerr << "\t\tdetected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl; + std::cerr << "\t\texpected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(EXPECTED_DRIFT[i]) << std::endl; + std::cerr << "\t\tdetected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(alarm) << std::endl; + std::cerr << "\t\texpected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(EXPECTED_ALARM[i]) << std::endl; + } + } + else if (opt_verbose) { + std::cout << "\tSame-side test succeeded " << std::endl; + } + } + } + } + + // Downward drift test + { + if (opt_verbose) { + std::cout << "Downward drift tests" << std::endl; + } + + // 3-sigma test + { + bool isInitOK = initializeShewhartTest(opt_mean, opt_stdev, opt_verbose, "3-sigma", tester); + if (!isInitOK) { + success = false; + } + else { + const float signal = -3.5f * opt_stdev; + vpStatisticalTestAbstract::vpMeanDriftType drift = tester.testDownUpwardMeanDrift(signal); + vpStatisticalTestShewhart::vpWecoRulesAlarm alarm = tester.getAlarm(); + const vpStatisticalTestAbstract::vpMeanDriftType EXPECTED_DRIFT = vpStatisticalTestAbstract::MEAN_DRIFT_DOWNWARD; + const vpStatisticalTestShewhart::vpWecoRulesAlarm EXPECTED_ALARM = vpStatisticalTestShewhart::THREE_SIGMA_WECO; + if ((drift != EXPECTED_DRIFT) || (alarm != EXPECTED_ALARM)) { + success = false; + if (opt_verbose) { + std::cerr << "\t3-sigma test failed: " << std::endl; + std::vector s = tester.getSignals(); + std::cerr << "\t\ts(t) = [ "; + for (size_t i = 0; i < s.size(); ++i) { + std::cerr << s[i] << " "; + } + std::cerr << "]" << std::endl; + float limitDown = 0.f, limitUp = 0.f; + tester.getLimits(limitDown, limitUp); + std::cerr << "\t\tlim_- = " << limitDown << std::endl; + std::cerr << "\t\tlim_+ = " << limitUp << std::endl; + std::cerr << "\t\tdetected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl; + std::cerr << "\t\texpected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(EXPECTED_DRIFT) << std::endl; + std::cerr << "\t\tdetected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(alarm) << std::endl; + std::cerr << "\t\texpected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(EXPECTED_ALARM) << std::endl; + } + } + else if (opt_verbose) { + std::cout << "\t3-sigma test succeeded " << std::endl; + } + } + } + + // 2-sigma test + { + bool isInitOK = initializeShewhartTest(opt_mean, opt_stdev, opt_verbose, "2-sigma", tester); + if (!isInitOK) { + success = false; + } + else { + const unsigned int NB_SAMPLES = 3; + const float DATA[NB_SAMPLES] = { -2.75f * opt_stdev, -1.5f * opt_stdev, -2.5f * opt_stdev }; + const vpStatisticalTestAbstract::vpMeanDriftType EXPECTED_DRIFT[NB_SAMPLES] = { vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_DOWNWARD }; + const vpStatisticalTestShewhart::vpWecoRulesAlarm EXPECTED_ALARM[NB_SAMPLES] = { vpStatisticalTestShewhart::NONE_WECO, vpStatisticalTestShewhart::NONE_WECO, vpStatisticalTestShewhart::TWO_SIGMA_WECO }; + vpStatisticalTestAbstract::vpMeanDriftType drift; + vpStatisticalTestShewhart::vpWecoRulesAlarm alarm = tester.getAlarm(); + unsigned int i = 0; + bool isTestOk = true; + while ((i < NB_SAMPLES) && isTestOk) { + drift = tester.testDownUpwardMeanDrift(DATA[i]); + alarm = tester.getAlarm(); + isTestOk = ((drift == EXPECTED_DRIFT[i]) && (alarm == EXPECTED_ALARM[i])); + if (isTestOk) { + ++i; + } + } + + if (!isTestOk) { + success = false; + if (opt_verbose) { + std::cerr << "\t2-sigma test failed: " << std::endl; + std::vector s = tester.getSignals(); + std::cerr << "\t\ts(t) = [ "; + for (size_t i = 0; i < s.size(); ++i) { + std::cerr << s[i] << " "; + } + std::cerr << "]" << std::endl; + float limitDown = 0.f, limitUp = 0.f; + tester.getLimits(limitDown, limitUp); + std::cerr << "\t\tlim_- = " << limitDown << std::endl; + std::cerr << "\t\tlim_+ = " << limitUp << std::endl; + std::cerr << "\t\tdetected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl; + std::cerr << "\t\texpected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(EXPECTED_DRIFT[i]) << std::endl; + std::cerr << "\t\tdetected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(alarm) << std::endl; + std::cerr << "\t\texpected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(EXPECTED_ALARM[i]) << std::endl; + } + } + else if (opt_verbose) { + std::cout << "\t2-sigma test succeeded " << std::endl; + } + } + } + + // 1-sigma test + { + bool isInitOK = initializeShewhartTest(opt_mean, opt_stdev, opt_verbose, "1-sigma", tester); + if (!isInitOK) { + success = false; + } + else { + const unsigned int NB_SAMPLES = 5; + 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 }; + const vpStatisticalTestAbstract::vpMeanDriftType EXPECTED_DRIFT[NB_SAMPLES] = { vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_DOWNWARD }; + const vpStatisticalTestShewhart::vpWecoRulesAlarm EXPECTED_ALARM[NB_SAMPLES] = { vpStatisticalTestShewhart::NONE_WECO, vpStatisticalTestShewhart::NONE_WECO, vpStatisticalTestShewhart::NONE_WECO, vpStatisticalTestShewhart::NONE_WECO, vpStatisticalTestShewhart::ONE_SIGMA_WECO }; + vpStatisticalTestAbstract::vpMeanDriftType drift; + vpStatisticalTestShewhart::vpWecoRulesAlarm alarm = tester.getAlarm(); + unsigned int i = 0; + bool isTestOk = true; + while ((i < NB_SAMPLES) && isTestOk) { + drift = tester.testDownUpwardMeanDrift(DATA[i]); + alarm = tester.getAlarm(); + isTestOk = ((drift == EXPECTED_DRIFT[i]) && (alarm == EXPECTED_ALARM[i])); + if (isTestOk) { + ++i; + } + } + + if (!isTestOk) { + success = false; + if (opt_verbose) { + std::cerr << "\t1-sigma test failed: " << std::endl; + std::vector s = tester.getSignals(); + std::cerr << "\t\ts(t) = [ "; + for (size_t i = 0; i < s.size(); ++i) { + std::cerr << s[i] << " "; + } + std::cerr << "]" << std::endl; + float limitDown = 0.f, limitUp = 0.f; + tester.getLimits(limitDown, limitUp); + std::cerr << "\t\tlim_- = " << limitDown << std::endl; + std::cerr << "\t\tlim_+ = " << limitUp << std::endl; + std::cerr << "\t\tdetected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl; + std::cerr << "\t\texpected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(EXPECTED_DRIFT[i]) << std::endl; + std::cerr << "\t\tdetected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(alarm) << std::endl; + std::cerr << "\t\texpected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(EXPECTED_ALARM[i]) << std::endl; + } + } + else if (opt_verbose) { + std::cout << "\t1-sigma test succeeded " << std::endl; + } + } + } + + // Same-side test + { + bool isInitOK = initializeShewhartTest(opt_mean, opt_stdev, opt_verbose, "Same-side", tester); + if (!isInitOK) { + success = false; + } + else { + const unsigned int NB_SAMPLES = 8; + 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 }; + const vpStatisticalTestAbstract::vpMeanDriftType EXPECTED_DRIFT[NB_SAMPLES] = { vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_NONE, vpStatisticalTestAbstract::MEAN_DRIFT_DOWNWARD }; + const vpStatisticalTestShewhart::vpWecoRulesAlarm EXPECTED_ALARM[NB_SAMPLES] = { vpStatisticalTestShewhart::NONE_WECO, vpStatisticalTestShewhart::NONE_WECO, vpStatisticalTestShewhart::NONE_WECO, vpStatisticalTestShewhart::NONE_WECO, vpStatisticalTestShewhart::NONE_WECO, vpStatisticalTestShewhart::NONE_WECO, vpStatisticalTestShewhart::NONE_WECO, vpStatisticalTestShewhart::SAME_SIDE_WECO }; + vpStatisticalTestAbstract::vpMeanDriftType drift; + vpStatisticalTestShewhart::vpWecoRulesAlarm alarm = tester.getAlarm(); + unsigned int i = 0; + bool isTestOk = true; + while ((i < NB_SAMPLES) && isTestOk) { + drift = tester.testDownUpwardMeanDrift(DATA[i]); + alarm = tester.getAlarm(); + isTestOk = ((drift == EXPECTED_DRIFT[i]) && (alarm == EXPECTED_ALARM[i])); + if (isTestOk) { + ++i; + } + } + + if (!isTestOk) { + success = false; + if (opt_verbose) { + std::cerr << "\tSame-side test failed: " << std::endl; + std::vector s = tester.getSignals(); + std::cerr << "\t\ts(t) = [ "; + for (size_t i = 0; i < s.size(); ++i) { + std::cerr << s[i] << " "; + } + std::cerr << "]" << std::endl; + float limitDown = 0.f, limitUp = 0.f; + tester.getLimits(limitDown, limitUp); + std::cerr << "\t\tlim_+ = " << limitUp << std::endl; + std::cerr << "\t\tlim_- = " << limitDown << std::endl; + std::cerr << "\t\tdetected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl; + std::cerr << "\t\texpected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(EXPECTED_DRIFT[i]) << std::endl; + std::cerr << "\t\tdetected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(alarm) << std::endl; + std::cerr << "\t\texpected alarm = " << vpStatisticalTestShewhart::vpWecoRulesAlarmToString(EXPECTED_ALARM[i]) << std::endl; + } + } + else if (opt_verbose) { + std::cout << "\tSame-side test succeeded " << std::endl; + } + } + } + } + } + + // vpStatisticalTestSigma tests + { + if (opt_verbose) { + std::cout << "------ vpStatisticalTestSigma tests ------" << std::endl; + } + const float h = 3.f; + vpStatisticalTestSigma tester(h, opt_mean, opt_stdev); + + // Upward drift test + { + const float signal = 3.5f * opt_stdev; + vpStatisticalTestAbstract::vpMeanDriftType drift = tester.testDownUpwardMeanDrift(signal); + const vpStatisticalTestAbstract::vpMeanDriftType EXPECTED_DRIFT = vpStatisticalTestAbstract::MEAN_DRIFT_UPWARD; + if (drift != EXPECTED_DRIFT) { + success = false; + if (opt_verbose) { + std::cerr << "Upward drift test failed: " << std::endl; + std::cerr << "\ts(t) = " << tester.getSignal() << std::endl; + float limitDown = 0.f, limitUp = 0.f; + tester.getLimits(limitDown, limitUp); + std::cerr << "\tlim_+ = " << limitUp << std::endl; + std::cerr << "\tdetected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl; + std::cerr << "\texpected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(EXPECTED_DRIFT) << std::endl; + } + } + else if (opt_verbose) { + std::cout << "Upward drift test succeeded " << std::endl; + } + } + + // Downward drift test + { + const float signal = -3.5f * opt_stdev; + vpStatisticalTestAbstract::vpMeanDriftType drift = tester.testDownUpwardMeanDrift(signal); + const vpStatisticalTestAbstract::vpMeanDriftType EXPECTED_DRIFT = vpStatisticalTestAbstract::MEAN_DRIFT_DOWNWARD; + if (drift != EXPECTED_DRIFT) { + success = false; + if (opt_verbose) { + std::cerr << "Downward drift test failed: " << std::endl; + std::cerr << "\ts(t) = " << tester.getSignal() << std::endl; + float limitDown = 0.f, limitUp = 0.f; + tester.getLimits(limitDown, limitUp); + std::cerr << "\tlim_- = " << limitDown << std::endl; + std::cerr << "\tdetected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(drift) << std::endl; + std::cerr << "\texpected drift = " << vpStatisticalTestAbstract::vpMeanDriftTypeToString(EXPECTED_DRIFT) << std::endl; + } + } + else if (opt_verbose) { + std::cout << "Downward drift test succeeded " << std::endl; + } + } + } + + if (success) { + std::cout << "Test succeed" << std::endl; + } + else { + std::cout << "Test failed" << std::endl; + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} diff --git a/tutorial/mean-drift/tutorial-meandrift.cpp b/tutorial/mean-drift/tutorial-meandrift.cpp index 181e94906d..945f312678 100644 --- a/tutorial/mean-drift/tutorial-meandrift.cpp +++ b/tutorial/mean-drift/tutorial-meandrift.cpp @@ -43,6 +43,7 @@ #include #include +#if defined(VISP_HAVE_DISPLAY) namespace TutorialMeanDrift { //! [Enum_For_Test_Choice] @@ -695,3 +696,10 @@ int main(int argc, char *argv[]) return testOnSynthetic(opt_typeTest, parameters, opt_mean, opt_meandrift, opt_stdev); } +#else +int main() +{ + std::cerr << "Recompile ViSP with display capabilities in order to use this tutorial." << std::endl; + return EXIT_FAILURE; +} +#endif From 66f235a179dd122d9c3ab16e9d71c5a957ccb94c Mon Sep 17 00:00:00 2001 From: rlagneau Date: Fri, 8 Mar 2024 17:38:32 +0100 Subject: [PATCH 07/12] [FIX] Fixed wrong delete in vpStasticalTestAbstract --- modules/core/src/math/misc/vpStatisticalTestAbstract.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/core/src/math/misc/vpStatisticalTestAbstract.cpp b/modules/core/src/math/misc/vpStatisticalTestAbstract.cpp index 4986a117b9..399b4b3ddd 100644 --- a/modules/core/src/math/misc/vpStatisticalTestAbstract.cpp +++ b/modules/core/src/math/misc/vpStatisticalTestAbstract.cpp @@ -147,7 +147,7 @@ vpStatisticalTestAbstract::vpStatisticalTestAbstract(const vpStatisticalTestAbst vpStatisticalTestAbstract::~vpStatisticalTestAbstract() { if (m_s != nullptr) { - delete m_s; + delete[] m_s; m_s = nullptr; } } @@ -161,7 +161,7 @@ void vpStatisticalTestAbstract::init() m_mean = 0.f; m_nbSamplesForStatistics = 0; if (m_s != nullptr) { - delete m_s; + delete[] m_s; m_s = nullptr; } m_stdev = 0.f; @@ -180,7 +180,7 @@ vpStatisticalTestAbstract &vpStatisticalTestAbstract::operator=(const vpStatisti } else if (m_s != nullptr) { m_nbSamplesForStatistics = 0; - delete m_s; + delete[] m_s; m_s = nullptr; } m_stdev = 0.f; @@ -192,7 +192,7 @@ void vpStatisticalTestAbstract::setNbSamplesForStat(const unsigned int &nbSample { m_nbSamplesForStatistics = nbSamples; if (m_s != nullptr) { - delete m_s; + delete[] m_s; } m_s = new float[nbSamples]; } From 3e93687f2abe2525f6c49254f6da306409d6d445 Mon Sep 17 00:00:00 2001 From: rlagneau Date: Mon, 11 Mar 2024 13:52:45 +0100 Subject: [PATCH 08/12] [FIX] Trying to fix error C2039: 'max': is not a member of 'std' --- modules/core/include/visp3/core/vpStatisticalTestAbstract.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/include/visp3/core/vpStatisticalTestAbstract.h b/modules/core/include/visp3/core/vpStatisticalTestAbstract.h index ac5d7867ae..dbf9604a2d 100644 --- a/modules/core/include/visp3/core/vpStatisticalTestAbstract.h +++ b/modules/core/include/visp3/core/vpStatisticalTestAbstract.h @@ -37,7 +37,7 @@ #ifndef _vpStatisticalTestAbstract_h_ #define _vpStatisticalTestAbstract_h_ - +#include #include #include #include From 9989cb9efc7952edb57f9dab4c7133845eff3bae Mon Sep 17 00:00:00 2001 From: Fabien Spindler Date: Mon, 11 Mar 2024 17:15:26 +0100 Subject: [PATCH 09/12] Reduce SPC tutorial image resolution and change format to jpeg --- .../tutorial/misc/img-tutorial-spc-run.jpg | Bin 0 -> 97635 bytes .../tutorial/misc/img-tutorial-spc-run.png | Bin 147847 -> 0 bytes doc/tutorial/misc/tutorial-spc.dox | 4 ++-- 3 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 doc/image/tutorial/misc/img-tutorial-spc-run.jpg delete mode 100644 doc/image/tutorial/misc/img-tutorial-spc-run.png diff --git a/doc/image/tutorial/misc/img-tutorial-spc-run.jpg b/doc/image/tutorial/misc/img-tutorial-spc-run.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ccbcce61ea312b0d8ab6c25a524cff5c9f2fc92f GIT binary patch literal 97635 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%0Aco@*eYB?OJC3xfn4 zbMVHOjk^fhm0Mi7cfRmivEjYsD*-ap{jojt+wZD|Z?cmRdFEud6H@&3y#3b}1<|?1 zqHTgmbox3=H8DK9qmkN^Ji;jmdN>Deb!>`((n%PnO=JiV`g_rv=-F7;wUl z;|FZ_JRgKU&v&W$xO^-a%AO(Ag4WW`@Z%FKwMbg;F7HnhgloI&P$EfUvT(U!9tv<< z2W@qshkM&`RY6*H0BeX2W%f&=W|@_8d^nQzmx1M?(Polu0JEBDRU)P6=6te)hO@^Y zeU@aIyTCwnkBYIjOFcgqe7GK<`oMNr!~*buh+yT_jI53)n}o$i@w2)%)+2}J)WY4_ zrj((6cPNFplX_zfc>|n|mzqzvp?9*NmGYr=+`8xe^xc8<6?kk4i{ep{ zt|mGrvuhs=l@go2YQy4W7&i-pV!6&%%(TjqX7z?7CX2?Y z&VClZM?6$@brDL&IQ!Cy3-56-GGAr^(}V-~606JKQP{SB;%n>TEL=3=)-8BoAyBjX`F{ z%{!-ynbgsdT0`40`IFk^F6ra8nS*_UGQc=3N|%s#$#i{60Yu`V69@eeWkLyE^R-;G z3eDm~J#x|7d$fyZ{WiHD`E$kg_}w;q?sOw@JbBkb(W25WnJSpyf~C(Ir1OnVotFKc z1)D_NOFo?3q7`&E(7+zS&~ooZ#@516iHBbC;^PVLR3Tw?>gsJ#J+n~VDSeStamG92 zb?4W+-LsrROe~U{xN+He?Ny}nn^VOM#SNwpdbFVO7*mRFDV`2PPD3AIZQ*Zp&Bk`0 zgWqTI(G4@f8b$5Z53Ji~^#OW(i2NYXh+tAIO$3Rp$S-RZ$;^C(9G67wmt5ZnY^ONq z&swQe5OPR0-%gXZ8M?=(dyhM@U9Imyl2AinHjPhUwC>fC%>`&=bj?E|6@p=A6zroAO<+>z;+X

~^n9;F~XYO)c*a% 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 Q?;lt;{&#Ch?6;5q18iU@jQ{`u literal 0 HcmV?d00001 diff --git a/doc/image/tutorial/misc/img-tutorial-spc-run.png b/doc/image/tutorial/misc/img-tutorial-spc-run.png deleted file mode 100644 index 153666a51a9c1cb959687893eeca3aaeca9dc3c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 147847 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 Date: Mon, 11 Mar 2024 17:15:40 +0100 Subject: [PATCH 10/12] Fix doxygen warnings --- .../core/include/visp3/core/vpStatisticalTestShewhart.h | 8 ++++---- tutorial/mean-drift/tutorial-meandrift.cpp | 5 ++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/modules/core/include/visp3/core/vpStatisticalTestShewhart.h b/modules/core/include/visp3/core/vpStatisticalTestShewhart.h index 584658b0ec..32c543086a 100644 --- a/modules/core/include/visp3/core/vpStatisticalTestShewhart.h +++ b/modules/core/include/visp3/core/vpStatisticalTestShewhart.h @@ -98,10 +98,10 @@ class VISP_EXPORT vpStatisticalTestShewhart : public vpStatisticalTestSigma alarm frequency is.*/ int m_idCurrentData; /*!< The index of the current data in m_signal.*/ vpWecoRulesAlarm m_alarm; /*!< The type of alarm raised due to WECO's rules.*/ - float m_oneSigmaNegLim; /*!< The \f$ \mu - \sigma \* threshold.*/ - float m_oneSigmaPosLim; /*!< The \f$ \mu + \sigma \* threshold.*/ - float m_twoSigmaNegLim; /*!< The \f$ \mu - 2 \sigma \* threshold.*/ - float m_twoSigmaPosLim; /*!< The \f$ \mu + 2 \sigma \* threshold.*/ + float m_oneSigmaNegLim; /*!< The \f$ \mu - \sigma \f$ threshold.*/ + float m_oneSigmaPosLim; /*!< The \f$ \mu + \sigma \f$ threshold.*/ + float m_twoSigmaNegLim; /*!< The \f$ \mu - 2 \sigma \f$ threshold.*/ + float m_twoSigmaPosLim; /*!< The \f$ \mu + 2 \sigma \f$ threshold.*/ /** * \brief Compute the upper and lower limits of the test signal. diff --git a/tutorial/mean-drift/tutorial-meandrift.cpp b/tutorial/mean-drift/tutorial-meandrift.cpp index 945f312678..9ba89e457c 100644 --- a/tutorial/mean-drift/tutorial-meandrift.cpp +++ b/tutorial/mean-drift/tutorial-meandrift.cpp @@ -66,7 +66,7 @@ typedef enum TypeTest /** * \brief Permit to cast a \b TypeTest object into a string, for display purpose. * - * \param[in] choice The \b TypeTest object we want to know the name. + * \param[in] type The \b TypeTest object we want to know the name. * \return std::string The corresponding name. */ std::string typeTestToString(const TypeTest &type) @@ -264,6 +264,9 @@ std::vector meanDriftArrayToVectorOfString(const bool array[vpStati * a single string listing all the alarms. * * \param[in] array The array of boolean indicating which alarm are set. + * \param[in] prefix The returned string prefix. + * \param[in] sep The returned string separator. + * \param[in] suffix The returned string suffix. * \return std::string The corresponding string listing the names of alarms. */ std::string meanDriftArrayToString(const bool array[vpStatisticalTestAbstract::MEAN_DRIFT_COUNT], From 22f679c6ea8c097e595d90d7a18948a8004b0b89 Mon Sep 17 00:00:00 2001 From: Fabien Spindler Date: Tue, 12 Mar 2024 13:55:57 +0100 Subject: [PATCH 11/12] Add verbose option to ctest --- .github/workflows/ubuntu-sanitizers.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ubuntu-sanitizers.yml b/.github/workflows/ubuntu-sanitizers.yml index 9894441bac..e215a425c0 100644 --- a/.github/workflows/ubuntu-sanitizers.yml +++ b/.github/workflows/ubuntu-sanitizers.yml @@ -82,4 +82,4 @@ jobs: # SUMMARY: AddressSanitizer: odr-violation: global 'ALIGNMENT' at /home/runner/work/visp/visp/3rdparty/simdlib/Simd/SimdLib.cpp:82:18 ASAN_OPTIONS: detect_odr_violation=0 working-directory: build - run: ctest -j$(nproc) --output-on-failure + run: ctest -j$(nproc) --output-on-failure -V From 394b3698e24b9f34f32cb09d18651176d5fb7996 Mon Sep 17 00:00:00 2001 From: Fabien Spindler Date: Tue, 12 Mar 2024 14:35:02 +0100 Subject: [PATCH 12/12] Fix warnings detected with msvc --- .../imgproc/src/vpCircleHoughTransform.cpp | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/modules/imgproc/src/vpCircleHoughTransform.cpp b/modules/imgproc/src/vpCircleHoughTransform.cpp index a30d1829f9..9806d6be74 100644 --- a/modules/imgproc/src/vpCircleHoughTransform.cpp +++ b/modules/imgproc/src/vpCircleHoughTransform.cpp @@ -315,12 +315,12 @@ vpCircleHoughTransform::detect(const vpImage &I) // the pixelization of the image const float minCenterPositionDiff = 3.f; if ((m_algoParams.m_centerXlimits.second - m_algoParams.m_centerXlimits.first) < minCenterPositionDiff) { - m_algoParams.m_centerXlimits.second += minCenterPositionDiff / 2.f; - m_algoParams.m_centerXlimits.first -= minCenterPositionDiff / 2.f; + m_algoParams.m_centerXlimits.second += static_cast(minCenterPositionDiff / 2.f); + m_algoParams.m_centerXlimits.first -= static_cast(minCenterPositionDiff / 2.f); } if ((m_algoParams.m_centerYlimits.second - m_algoParams.m_centerYlimits.first) < minCenterPositionDiff) { - m_algoParams.m_centerYlimits.second += minCenterPositionDiff / 2.f; - m_algoParams.m_centerYlimits.first -= minCenterPositionDiff / 2.f; + m_algoParams.m_centerYlimits.second += static_cast(minCenterPositionDiff / 2.f); + m_algoParams.m_centerYlimits.first -= static_cast(minCenterPositionDiff / 2.f); } // First thing, we need to apply a Gaussian filter on the image to remove some spurious noise @@ -397,7 +397,7 @@ void vpCircleHoughTransform::computeVotingMask(const vpImage &I, #endif { bool hasFoundSimilarCircle = false; - unsigned int nbPreviouslyDetected = m_finalCircles.size(); + unsigned int nbPreviouslyDetected = static_cast(m_finalCircles.size()); unsigned int id = 0; // Looking for a circle that was detected and is similar to the one given to the function while ((id < nbPreviouslyDetected) && (!hasFoundSimilarCircle)) { @@ -410,7 +410,7 @@ void vpCircleHoughTransform::computeVotingMask(const vpImage &I, { hasFoundSimilarCircle = true; // We found a circle that is similar to the one given to the function => updating the mask - const unsigned int nbVotingPoints = m_finalCirclesVotingPoints[id].size(); + const unsigned int nbVotingPoints = static_cast(m_finalCirclesVotingPoints[id].size()); for (unsigned int idPoint = 0; idPoint < nbVotingPoints; ++idPoint) { const std::pair &votingPoint = m_finalCirclesVotingPoints[id][idPoint]; #if (VISP_CXX_STANDARD >= VISP_CXX_STANDARD_17) @@ -858,11 +858,11 @@ vpCircleHoughTransform::computeCenterCandidates() std::sort(merged_peaks_position_votes.begin(), merged_peaks_position_votes.end(), sortingCenters); nbPeaks = static_cast(merged_peaks_position_votes.size()); - int nbPeaksToKeep = (m_algoParams.m_expectedNbCenters > 0 ? m_algoParams.m_expectedNbCenters : nbPeaks); - nbPeaksToKeep = std::min(nbPeaksToKeep, (int)nbPeaks); + int nbPeaksToKeep = (m_algoParams.m_expectedNbCenters > 0 ? m_algoParams.m_expectedNbCenters : static_cast(nbPeaks)); + nbPeaksToKeep = std::min(nbPeaksToKeep, static_cast(nbPeaks)); for (int i = 0; i < nbPeaksToKeep; i++) { m_centerCandidatesList.push_back(merged_peaks_position_votes[i].first); - m_centerVotes.push_back(merged_peaks_position_votes[i].second); + m_centerVotes.push_back(static_cast(merged_peaks_position_votes[i].second)); } } } @@ -1049,17 +1049,17 @@ vpCircleHoughTransform::computeCircleCandidates() } } - unsigned int nbCandidates = v_r_effective.size(); + unsigned int nbCandidates = static_cast(v_r_effective.size()); for (unsigned int idBin = 0; idBin < nbCandidates; ++idBin) { // If the circle of center CeC_i and radius RCB_k has enough votes, it is added to the list // of Circle Candidates float r_effective = v_r_effective[idBin]; vpImageCircle candidateCircle(vpImagePoint(centerCandidate.first, centerCandidate.second), r_effective); - float proba = computeCircleProbability(candidateCircle, v_votes_effective[idBin]); + float proba = computeCircleProbability(candidateCircle, static_cast(v_votes_effective[idBin])); if (proba > m_algoParams.m_circleProbaThresh) { m_circleCandidates.push_back(candidateCircle); m_circleCandidatesProbabilities.push_back(proba); - m_circleCandidatesVotes.push_back(v_votes_effective[idBin]); + m_circleCandidatesVotes.push_back(static_cast(v_votes_effective[idBin])); if (m_algoParams.m_recordVotingPoints) { if (v_hasMerged_effective[idBin]) { // Remove potential duplicated points @@ -1081,7 +1081,7 @@ vpCircleHoughTransform::computeCircleProbability(const vpImageCircle &circle, co float visibleArc(static_cast(nbVotes)); float theoreticalLenght; if (mp_mask != nullptr) { - theoreticalLenght = circle.computePixelsInMask(*mp_mask); + theoreticalLenght = static_cast(circle.computePixelsInMask(*mp_mask)); } else { theoreticalLenght = circle.computeArcLengthInRoI(vpRect(vpImagePoint(0, 0), m_edgeMap.getWidth(), m_edgeMap.getHeight()));