diff --git a/include/rosa/agent/Abstraction.hpp b/include/rosa/agent/Abstraction.hpp index 6afa7fd..a39ee4a 100644 --- a/include/rosa/agent/Abstraction.hpp +++ b/include/rosa/agent/Abstraction.hpp @@ -1,244 +1,244 @@ //===-- rosa/agent/Abstraction.hpp ------------------------------*- C++ -*-===// // // The RoSA Framework // // Distributed under the terms and conditions of the Boost Software License 1.0. // See accompanying file LICENSE. // // If you did not receive a copy of the license file, see // http://www.boost.org/LICENSE_1_0.txt. // //===----------------------------------------------------------------------===// /// /// \file rosa/agent/Abstraction.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Definition of *abstraction* *functionality*. /// //===----------------------------------------------------------------------===// #ifndef ROSA_AGENT_ABSTRACTION_HPP #define ROSA_AGENT_ABSTRACTION_HPP #include "rosa/agent/Functionality.h" #include "rosa/support/debug.hpp" #include #include namespace rosa { namespace agent { /// Abstracts values from a type to another one. /// /// \tparam T type to abstract from /// \tparam A type to abstract to template class Abstraction : public Functionality { protected: /// Value to abstract to by default. const A Default; public: /// Creates an instance. /// /// \param Default value to abstract to by default Abstraction(const A Default) noexcept : Default(Default) {} /// Destroys \p this object. ~Abstraction(void) = default; /// Checks wether the Abstraction evaluates to default at the given position /// /// \param V the value at which to check if the function falls back to it's /// default value. /// \return true, the default implementation always falls back to the default /// value virtual bool isDefaultAt(const T &V) const noexcept{ (void)V; return true; } /// Abstracts a value from type \p T to type \p A. /// /// \note The default implementation always returns /// \c rosa::agent::Abstraction::Default, hence the actual argument is /// ignored. /// /// \return the abstracted value virtual A operator()(const T &) const noexcept { return Default; } }; /// Implements \c rosa::agent::Abstraction as a \c std::map from a type to /// another one. /// /// \note This implementation is supposed to be used to abstract between /// enumeration types, which is statically enforced. /// /// \tparam T type to abstract from /// \tparam A type to abstract to template class MapAbstraction : public Abstraction, private std::map { // Make sure the actual type arguments are enumerations. STATIC_ASSERT((std::is_enum::value && std::is_enum::value), "mapping not enumerations"); // Bringing into scope inherited members. using Abstraction::Default; using std::map::end; using std::map::find; public: /// Creates an instance by initializing the underlying \c std::map. /// /// \param Map the mapping to do abstraction according to /// \param Default value to abstract to by default MapAbstraction(const std::map &Map, const A Default) noexcept : Abstraction(Default), std::map(Map) {} /// Destroys \p this object. ~MapAbstraction(void) = default; /// Checks wether the Abstraction evaluates to default at the given position /// /// \param V the value at which to check if the function falls back to it's /// default value. /// \return true if the Abstraction falls back to the default value bool isDefaultAt(const T &V) const noexcept override { const auto I = find(V); return I == end() ? true : false; } /// Abstracts a value from type \p T to type \p A based on the set mapping. /// /// Results in the value associated by the set mapping to the argument, or /// \c rosa::agent::MapAbstraction::Default if the actual argument is not /// associated with anything by the set mapping. /// /// \param V value to abstract /// /// \return the abstracted value based on the set mapping A operator()(const T &V) const noexcept override { const auto I = find(V); return I == end() ? Default : *I; } }; /// Implements \c rosa::agent::Abstraction as a \c std::map from ranges of a /// type to values of another type. /// /// \note This implementation is supposed to be used to abstract ranges of /// arithmetic types into enumerations, which is statically enforced. /// /// \invariant The keys in the underlying \c std::map define valid ranges /// such that `first <= second` and there are no overlapping ranges defined by /// the keys. /// /// \tparam T type to abstract from /// \tparam A type to abstract to template class RangeAbstraction : public Abstraction, private std::map, A> { // Make sure the actual type arguments are matching our expectations. STATIC_ASSERT((std::is_arithmetic::value), "abstracting not arithmetic"); /// \todo check if this compiles with the definition of abstractions as /// self-aware properties //STATIC_ASSERT((std::is_enum::value), "abstracting not to enumeration"); // Bringing into scope inherited members. using Abstraction::Default; using std::map, A>::begin; using std::map, A>::end; using std::map, A>::find; public: /// Creates an instance by Initializing the unserlying \c std::map. /// /// \param Map the mapping to do abstraction according to /// \param Default value to abstract to by default /// /// \pre Each key defines a valid range such that `first <= second` and /// there are no overlapping ranges defined by the keys. RangeAbstraction(const std::map, A> &Map, const A &Default) : Abstraction(Default), std::map, A>(Map) { // Sanity check. ASSERT(std::all_of( begin(), end(), [this](const std::pair, A> &P) { return P.first.first <= P.first.second && std::all_of(++find(P.first), end(), [&P](const std::pair, A> &R) { // \note Values in \c Map are sorted. - return P.first.first < P.first.second && + return P.first.first <= P.first.second && P.first.second <= R.first.first || P.first.first == P.first.second && - P.first.second < R.first.first; + P.first.second <= R.first.first; }); })); } /// Destroys \p this object. ~RangeAbstraction(void) = default; /// Checks wether the Abstraction evaluates to default at the given position /// /// \param V the value at which to check if the function falls back to it's /// default value. /// \return true if the Abstraction falls back to the default value bool isDefaultAt(const T &V) const noexcept override { auto I = begin(); bool Found = false; // Indicates if \c I refers to a matching range. bool Failed = false; // Indicates if it is pointless to continue searching. while (!Found && !Failed && I != end()) { if (V < I->first.first) { // No match so far and \p V is below the next range, never will match. // \note Keys are sorted in the map. return true; } else if (I->first.first <= V && V < I->first.second) { // Matching range found. return false; } else { // Cannot conclude in this step, move to the next range. ++I; } } return true; } /// Abstracts a value from type \p T to type \p A based on the set mapping. /// /// Results in the value associated by the set mapping to the argument, or /// \c rosa::agent::RangeAbstraction::Default if the actual argument is not /// included in any of the ranges in the set mapping. /// /// \param V value to abstract /// /// \return the abstracted value based on the set mapping A operator()(const T &V) const noexcept override { auto I = begin(); bool Found = false; // Indicates if \c I refers to a matching range. bool Failed = false; // Indicates if it is pointless to continue searching. while (!Found && !Failed && I != end()) { if (V < I->first.first) { // No match so far and \p V is below the next range, never will match. // \note Keys are sorted in the map. Failed = true; } else if (I->first.first <= V && V < I->first.second) { // Matching range found. Found = true; } else { // Cannot conclude in this step, move to the next range. ++I; } } ASSERT(!Found || I != end()); return Found ? I->second : Default; } }; } // End namespace agent } // End namespace rosa #endif // ROSA_AGENT_ABSTRACTION_HPP diff --git a/include/rosa/agent/SignalState.hpp b/include/rosa/agent/SignalState.hpp index 2b2595e..1ea6b6a 100644 --- a/include/rosa/agent/SignalState.hpp +++ b/include/rosa/agent/SignalState.hpp @@ -1,688 +1,638 @@ //===-- rosa/agent/SignalState.hpp ------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/agent/SignalState.hpp /// /// \author Maximilian Götzinger (maximilian.goetzinger@tuwien.ac.at) /// /// \date 2019 /// /// \brief Definition of *signal state* *functionality*. /// //===----------------------------------------------------------------------===// #ifndef ROSA_AGENT_SIGNALSTATE_HPP #define ROSA_AGENT_SIGNALSTATE_HPP #include "rosa/agent/DistanceMetrics.hpp" #include "rosa/agent/FunctionAbstractions.hpp" #include "rosa/agent/Functionality.h" #include "rosa/agent/History.hpp" #include "rosa/agent/State.hpp" #include "rosa/support/math.hpp" namespace rosa { namespace agent { /// Signal properties defining the properties of the signal which is monitored /// by \c rosa::agent::SignalStateDetector and is saved in \c /// rosa::agent::SignalStateInformation. enum SignalProperties : uint8_t { INPUT = 0, ///< The signal is an input signal OUTPUT = 1 ///< The signal is an output signal }; /// TODO: write description template struct DABHistoryEntry { /// TODO: write description PROCDATATYPE AvgValue; /// TODO: write description CONFDATATYPE DecisionDABIsStable; /// TODO: write description CONFDATATYPE DecisionDABIsDriftingDown; /// TODO: write description CONFDATATYPE DecisionDABIsDriftingUp; /// TODO: write description bool DABIsCurrent; public: DABHistoryEntry(PROCDATATYPE AvgValue) { this->AvgValue = AvgValue; this->DecisionDABIsStable = 1; this->DecisionDABIsDriftingDown = 0; this->DecisionDABIsDriftingUp = 0; this->DABIsCurrent = true; } }; /// TODO: write description template struct SignalStateInformation : StateInformation { // Make sure the actual type arguments are matching our expectations. STATIC_ASSERT((std::is_arithmetic::value), "confidence type is not to arithmetic"); /// ConfidenceOfMatchingState is the confidence how good the new sample /// matches the state. CONFDATATYPE ConfidenceOfMatchingState; /// ConfidenceOfMatchingState is the confidence how bad the new sample /// matches the state. CONFDATATYPE ConfidenceOfMismatchingState; /// The SignalProperty saves whether the monitored signal is an input our /// output signal. SignalProperties SignalProperty; /// The SignalStateIsValid saves the number of samples which have been /// inserted into the state after entering it. uint32_t NumberOfInsertedSamplesAfterEntrance; public: SignalStateInformation(unsigned int SignalStateID, SignalProperties _SignalProperty) { this->StateID = SignalStateID; this->SignalProperty = _SignalProperty; this->StateCondition = StateConditions::UNKNOWN; this->NumberOfInsertedSamplesAfterEntrance = 0; this->StateIsValid = false; this->StateJustGotValid = false; this->StateIsValidAfterReentrance = false; this->ConfidenceStateIsValid = 0; this->ConfidenceStateIsInvalid = 0; this->ConfidenceStateIsStable = 0; this->ConfidenceStateIsDrifting = 0; this->ConfidenceStateIsDriftingDown = 0; this->ConfidenceStateIsDriftingUp = 0; } SignalStateInformation() = default; }; /// \tparam INDATATYPE type of input data, \tparam CONFDATATYPE type of /// data in that the confidence values are given, \tparam PROCDATATYPE type of /// the relative distance and the type of data in which DABs are saved. template class SignalState : public Functionality { // Make sure the actual type arguments are matching our expectations. STATIC_ASSERT((std::is_arithmetic::value), "input data type not arithmetic"); STATIC_ASSERT((std::is_arithmetic::value), "confidence data type is not to arithmetic"); STATIC_ASSERT( (std::is_arithmetic::value), "process data type (DAB and Relative Distance) is not to arithmetic"); public: // The metric to calculate the distance between two points using DistanceMetricAbstraction = Abstraction, PROCDATATYPE> &; // For the convinience to write a shorter data type name using PartFuncReference = PartialFunction &; // using PartFuncReference2 = ; using StepFuncReference = StepFunction &; private: /// SignalStateInfo is a struct of SignalStateInformation that contains /// information about the current signal state. SignalStateInformation SignalStateInfo; /// The metric to calculate the distance between two points DistanceMetricAbstraction DistanceMetric; /// The FuzzyFunctionSampleMatches is the fuzzy function that gives the /// confidence how good the new sample matches another sample in the sample /// history. PartFuncReference FuzzyFunctionSampleMatches; /// The FuzzyFunctionSampleMismatches is the fuzzy function that gives the /// confidence how bad the new sample matches another sample in the sample /// history. PartFuncReference FuzzyFunctionSampleMismatches; /// The FuzzyFunctionNumOfSamplesMatches is the fuzzy function that gives the /// confidence how many samples from the sampe history match the new sample. StepFuncReference FuzzyFunctionNumOfSamplesMatches; /// The FuzzyFunctionNumOfSamplesMismatches is the fuzzy function that gives /// the confidence how many samples from the sampe history mismatch the new /// sample. StepFuncReference FuzzyFunctionNumOfSamplesMismatches; /// The FuzzyFunctionSampleValid is the fuzzy function that gives the /// confidence how good one matches another sample in the sample /// history. This is done to evaluate whether a state is valid. PartFuncReference FuzzyFunctionSampleValid; /// The FuzzyFunctionSampleInvalid is the fuzzy function that gives the /// confidence how bad one sample matches another sample in the sample /// history. This is done to evaluate whether a state is invalid. PartFuncReference FuzzyFunctionSampleInvalid; /// The FuzzyFunctionNumOfSamplesValid is the fuzzy function that gives the /// confidence how many samples from the sample history match another sample. /// This is done to evaluate whether a state is valid. StepFuncReference FuzzyFunctionNumOfSamplesValid; /// The FuzzyFunctionNumOfSamplesInvalid is the fuzzy function that gives /// the confidence how many samples from the sample history mismatch another /// sample. This is done to evaluate whether a state is invalid. StepFuncReference FuzzyFunctionNumOfSamplesInvalid; /// The FuzzyFunctionSignalIsDriftingDown is the fuzzy function that gives the /// confidence how likely it is that the signal (resp. the state of a signal) /// is drifting down. PartFuncReference FuzzyFunctionSignalIsDriftingDown; /// The FuzzyFunctionSignalIsDriftingUp is the fuzzy function that gives the /// confidence how likely it is that the signal (resp. the state of a signal) /// is drifting up. PartFuncReference FuzzyFunctionSignalIsDriftingUp; /// The FuzzyFunctionSignalIsStable is the fuzzy function that gives the /// confidence how likely it is that the signal (resp. the state of a signal) /// is stable (not drifting). PartFuncReference FuzzyFunctionSignalIsStable; /// TODO: description PartialFunction &FuzzyFunctionSignalConditionLookBack; /// TODO: description PartialFunction &FuzzyFunctionSignalConditionHistoryDesicion; /// TODO: description uint32_t DriftLookbackRange; /// SampleHistory is a history in that the last sample values are stored. DynamicLengthHistory SampleHistory; /// DAB is a (usually) small history of the last sample values of which a /// average is calculated if the DAB is full. DynamicLengthHistory DAB; /// DABHistory is a history in that the last DABs (to be exact, the averages /// of the last DABs) are stored. DynamicLengthHistory, HistoryPolicy::FIFO> DABHistory; /// LowestConfidenceMatchingHistory is a history in that the lowest confidence /// for the current sample matches all history samples are saved. DynamicLengthHistory LowestConfidenceMatchingHistory; /// HighestConfidenceMatchingHistory is a history in that the highest /// confidence for the current sample matches all history samples are saved. DynamicLengthHistory HighestConfidenceMismatchingHistory; /// TempConfidenceMatching is the confidence how good a sample matches the /// state. However, the value of this variable is only needed temporarly. CONFDATATYPE TempConfidenceMatching = 0; /// TempConfidenceMatching is the confidence how bad a sample matches the /// state. However, the value of this variable is only needed temporarly. CONFDATATYPE TempConfidenceMismatching = 0; + /// For the linear regression + PROCDATATYPE MeanX; + + /// For the linear regression + PROCDATATYPE RegressionDivisor; + public: /// Creates an instance by setting all parameters /// \param SignalStateID The Id of the SignalStateinfo \c /// SignalStateInformation. /// /// \param DistanceMetric the distance metric to calculate the distance /// between two points /// /// \param FuzzyFunctionSampleMatches The FuzzyFunctionSampleMatches is the /// fuzzy function that gives the confidence how good the new sample matches /// another sample in the sample history. /// /// \param FuzzyFunctionSampleMismatches The FuzzyFunctionSampleMismatches is /// the fuzzy function that gives the confidence how bad the new sample /// matches another sample in the sample history. /// /// \param FuzzyFunctionNumOfSamplesMatches The /// FuzzyFunctionNumOfSamplesMatches is the fuzzy function that gives the /// confidence how many samples from the sampe history match the new sample. /// /// \param FuzzyFunctionNumOfSamplesMismatches The /// FuzzyFunctionNumOfSamplesMismatches is the fuzzy function that gives the /// confidence how many samples from the sampe history mismatch the new /// sample. /// /// \param FuzzyFunctionSignalIsDriftingDown The /// FuzzyFunctionSignalIsDriftingDown is the fuzzy function that gives the /// confidence how likely it is that the signal (resp. the state of a signal) /// is drifting down. /// /// /// \param FuzzyFunctionSignalIsDriftingUp The FuzzyFunctionSignalIsDriftingUp /// is the fuzzy function that gives the confidence how likely it is that the /// signal (resp. the state of a signal) is drifting down. /// /// \param FuzzyFunctionSignalIsStable The FuzzyFunctionSignalIsStable is the /// fuzzy function that gives the confidence how likely it is that the signal /// (resp. the state of a signal) is stable (not drifting). /// /// \param SampleHistorySize Size of the Sample History \c /// DynamicLengthHistory . SampleHistory is a history in that the last sample /// values are stored. /// SignalState( uint32_t SignalStateID, SignalProperties SignalProperty, uint32_t SampleHistorySize, uint32_t DABSize, DistanceMetricAbstraction DistanceMetric, PartFuncReference FuzzyFunctionSampleMatches, PartFuncReference FuzzyFunctionSampleMismatches, StepFuncReference FuzzyFunctionNumOfSamplesMatches, StepFuncReference FuzzyFunctionNumOfSamplesMismatches, PartFuncReference FuzzyFunctionSampleValid, PartFuncReference FuzzyFunctionSampleInvalid, StepFuncReference FuzzyFunctionNumOfSamplesValid, StepFuncReference FuzzyFunctionNumOfSamplesInvalid, PartFuncReference FuzzyFunctionSignalIsDriftingDown, PartFuncReference FuzzyFunctionSignalIsDriftingUp, PartFuncReference FuzzyFunctionSignalIsStable, PartialFunction &FuzzyFunctionSignalConditionLookBack, PartialFunction &FuzzyFunctionSignalConditionHistoryDesicion, uint32_t DriftLookbackRange) noexcept : SignalStateInfo{SignalStateID, SignalProperty}, DistanceMetric(DistanceMetric), FuzzyFunctionSampleMatches(FuzzyFunctionSampleMatches), FuzzyFunctionSampleMismatches(FuzzyFunctionSampleMismatches), FuzzyFunctionNumOfSamplesMatches(FuzzyFunctionNumOfSamplesMatches), FuzzyFunctionNumOfSamplesMismatches( FuzzyFunctionNumOfSamplesMismatches), FuzzyFunctionSampleValid(FuzzyFunctionSampleValid), FuzzyFunctionSampleInvalid(FuzzyFunctionSampleInvalid), FuzzyFunctionNumOfSamplesValid(FuzzyFunctionNumOfSamplesValid), FuzzyFunctionNumOfSamplesInvalid(FuzzyFunctionNumOfSamplesInvalid), FuzzyFunctionSignalIsDriftingDown(FuzzyFunctionSignalIsDriftingDown), FuzzyFunctionSignalIsDriftingUp(FuzzyFunctionSignalIsDriftingUp), FuzzyFunctionSignalIsStable(FuzzyFunctionSignalIsStable), FuzzyFunctionSignalConditionLookBack( FuzzyFunctionSignalConditionLookBack), FuzzyFunctionSignalConditionHistoryDesicion( FuzzyFunctionSignalConditionHistoryDesicion), DriftLookbackRange(DriftLookbackRange), SampleHistory(SampleHistorySize), DAB(DABSize), DABHistory(DriftLookbackRange + 1), LowestConfidenceMatchingHistory(SampleHistorySize), - HighestConfidenceMismatchingHistory(SampleHistorySize) {} + HighestConfidenceMismatchingHistory(SampleHistorySize), + MeanX(DriftLookbackRange/2), + RegressionDivisor(0) { + + for (unsigned int i = 0; i <= DriftLookbackRange; i++) { + RegressionDivisor += (i-MeanX)*(i-MeanX); + } + RegressionDivisor *= DABSize; + } /// Destroys \p this object. ~SignalState(void) = default; void leaveSignalState(void) noexcept { DAB.clear(); SignalStateInfo.NumberOfInsertedSamplesAfterEntrance = 0; SignalStateInfo.StateIsValidAfterReentrance = false; } SignalStateInformation insertSample(INDATATYPE Sample) noexcept { SignalStateInfo.NumberOfInsertedSamplesAfterEntrance++; validateSignalState(Sample); SampleHistory.addEntry(Sample); DAB.addEntry(Sample); if (DAB.full()) { // TODO: try median instead of avg PROCDATATYPE AvgOfDAB = DAB.template average(); DABHistory.addEntry( DABHistoryEntry(AvgOfDAB)); DAB.clear(); } FuzzyFunctionNumOfSamplesMatches.setRightLimit( static_cast(SampleHistory.numberOfEntries())); FuzzyFunctionNumOfSamplesMismatches.setRightLimit( static_cast(SampleHistory.numberOfEntries())); checkSignalStability(); SignalStateInfo.ConfidenceOfMatchingState = TempConfidenceMatching; SignalStateInfo.ConfidenceOfMismatchingState = TempConfidenceMismatching; return SignalStateInfo; } /// Gives the confidence how likely the new sample matches the signal state. /// /// \param Sample is the actual sample of the observed signal. /// /// \return the confidence of the new sample is matching the signal state. CONFDATATYPE confidenceSampleMatchesSignalState(INDATATYPE Sample) noexcept { CONFDATATYPE ConfidenceOfBestCase = 0; DynamicLengthHistory RelativeDistanceHistory(SampleHistory.maxLength()); // Calculate distances to all history samples. for (auto &HistorySample : SampleHistory) { PROCDATATYPE RelativeDistance = DistanceMetric(std::make_pair(Sample, HistorySample)); RelativeDistanceHistory.addEntry(RelativeDistance); } // Sort all calculated distances so that the lowest distance (will get the // highest confidence) is at the beginning. RelativeDistanceHistory.sortAscending(); CONFDATATYPE ConfidenceOfWorstFittingSample = 1; // Case 1 means that one (the best fitting) sample of the history is // compared with the new sample. Case 2 means the two best history samples // are compared with the new sample. And so on. // TODO (future): to accelerate . don't start with 1 start with some higher // number because a low number (i guess lower than 5) will definetely lead // to a low confidence. except the history is not full. // Case 1 means that one (the best fitting) sample of the history is // compared with the new sample. Case 2 means the two best history samples // are compared with the new sample. And so on. for (uint32_t Case = 0; Case < RelativeDistanceHistory.numberOfEntries(); Case++) { CONFDATATYPE ConfidenceFromRelativeDistance; if (std::isinf(RelativeDistanceHistory[Case])) { // TODO (future): if fuzzy is defined in a way that infinity is not 0 it // would be a problem. ConfidenceFromRelativeDistance = 0; } else { ConfidenceFromRelativeDistance = FuzzyFunctionSampleMatches(RelativeDistanceHistory[Case]); } ConfidenceOfWorstFittingSample = fuzzyAND(ConfidenceOfWorstFittingSample, ConfidenceFromRelativeDistance); ConfidenceOfBestCase = fuzzyOR(ConfidenceOfBestCase, fuzzyAND(ConfidenceOfWorstFittingSample, FuzzyFunctionNumOfSamplesMatches( static_cast(Case) + 1))); } TempConfidenceMatching = ConfidenceOfBestCase; return ConfidenceOfBestCase; } /// Gives the confidence how likely the new sample mismatches the signal /// state. /// /// \param Sample is the actual sample of the observed signal. /// /// \return the confidence of the new sample is mismatching the signal state. CONFDATATYPE confidenceSampleMismatchesSignalState(INDATATYPE Sample) noexcept { float ConfidenceOfWorstCase = 1; DynamicLengthHistory RelativeDistanceHistory(SampleHistory.maxLength()); // Calculate distances to all history samples. for (auto &HistorySample : SampleHistory) { RelativeDistanceHistory.addEntry( DistanceMetric(std::make_pair(Sample, HistorySample))); } // Sort all calculated distances so that the highest distance (will get the // lowest confidence) is at the beginning. RelativeDistanceHistory.sortDescending(); CONFDATATYPE ConfidenceOfBestFittingSample = 0; // TODO (future): to accelerate -> don't go until end. Confidences will only // get higher. See comment in "CONFDATATYPE // confidenceSampleMatchesSignalState(INDATATYPE Sample)". // Case 1 means that one (the worst fitting) sample of the history is // compared with the new sample. Case 2 means the two worst history samples // are compared with the new sample. And so on. for (uint32_t Case = 0; Case < RelativeDistanceHistory.numberOfEntries(); Case++) { CONFDATATYPE ConfidenceFromRelativeDistance; if (std::isinf(RelativeDistanceHistory[Case])) { ConfidenceFromRelativeDistance = 1; } else { ConfidenceFromRelativeDistance = FuzzyFunctionSampleMismatches(RelativeDistanceHistory[Case]); } ConfidenceOfBestFittingSample = fuzzyOR(ConfidenceOfBestFittingSample, ConfidenceFromRelativeDistance); ConfidenceOfWorstCase = fuzzyAND(ConfidenceOfWorstCase, fuzzyOR(ConfidenceOfBestFittingSample, FuzzyFunctionNumOfSamplesMismatches( static_cast(Case) + 1))); } TempConfidenceMismatching = ConfidenceOfWorstCase; return ConfidenceOfWorstCase; } /// Gives information about the current signal state. /// /// \return a struct SignalStateInformation that contains information about /// the current signal state. SignalStateInformation signalStateInformation(void) noexcept { return SignalStateInfo; } private: void validateSignalState(INDATATYPE Sample) { // TODO (future): WorstConfidenceDistance and BestConfidenceDistance could // be set already in "CONFDATATYPE // confidenceSampleMatchesSignalState(INDATATYPE Sample)" and "CONFDATATYPE // confidenceSampleMismatchesSignalState(INDATATYPE Sample)" when the new // sample is compared to all history samples. This would save a lot time // because the comparisons are done only once. However, it has to be asured // that the these two functions are called before the insertation, and the // FuzzyFunctions for validation and matching have to be the same! CONFDATATYPE LowestConfidenceMatching = 1; CONFDATATYPE HighestConfidenceMismatching = 0; for (auto &HistorySample : SampleHistory) { // TODO (future): think about using different fuzzy functions for // validation and matching. LowestConfidenceMatching = fuzzyAND(LowestConfidenceMatching, FuzzyFunctionSampleMatches( DistanceMetric(std::make_pair(Sample, HistorySample)))); HighestConfidenceMismatching = fuzzyOR(HighestConfidenceMismatching, FuzzyFunctionSampleMismatches( DistanceMetric(std::make_pair(Sample, HistorySample)))); } LowestConfidenceMatchingHistory.addEntry(LowestConfidenceMatching); HighestConfidenceMismatchingHistory.addEntry(HighestConfidenceMismatching); LowestConfidenceMatching = LowestConfidenceMatchingHistory.lowestEntry(); HighestConfidenceMismatching = HighestConfidenceMismatchingHistory.highestEntry(); SignalStateInfo.ConfidenceStateIsValid = fuzzyAND(LowestConfidenceMatching, FuzzyFunctionNumOfSamplesValid(static_cast( SignalStateInfo.NumberOfInsertedSamplesAfterEntrance))); SignalStateInfo.ConfidenceStateIsInvalid = fuzzyOR(HighestConfidenceMismatching, FuzzyFunctionNumOfSamplesInvalid(static_cast( SignalStateInfo.NumberOfInsertedSamplesAfterEntrance))); if (SignalStateInfo.ConfidenceStateIsValid > SignalStateInfo.ConfidenceStateIsInvalid) { if (SignalStateInfo.StateIsValid) { SignalStateInfo.StateJustGotValid = false; } else { SignalStateInfo.StateJustGotValid = true; } SignalStateInfo.StateIsValid = true; SignalStateInfo.StateIsValidAfterReentrance = true; } } void checkSignalStability(void) { - CONFDATATYPE CurrentConfidenceStable = 0; - CONFDATATYPE CurrentConfidenceStateDriftingDown = 0; - CONFDATATYPE CurrentConfidenceStateDriftingUp = 0; - - CONFDATATYPE HistoryConfidenceStable = 0; - CONFDATATYPE HistoryConfidenceStateDriftingDown = 0; - CONFDATATYPE HistoryConfidenceStateDriftingUp = 0; - - if (DABHistory.numberOfEntries() >= 2) { + if (DABHistory.numberOfEntries() > DriftLookbackRange) { DABHistoryEntry CurrentDAB = DABHistory[DABHistory.numberOfEntries() - 1]; if (CurrentDAB.DABIsCurrent == true) { + CurrentDAB.DABIsCurrent = false; + + PROCDATATYPE MeanY = 0; + PROCDATATYPE k = 0; - // THIS WOULD BE FOR EQUATION NORMALIZATION - // TODO: make the following also for distance measurement when comparing - // sample with state and validate state - /* - // sigma correction - if (NormalizedDistanceMetric - *NormalizableDistanceMetric = dynamic_cast< - NormalizedDistanceMetric *>( - DistanceMetric)) { - // old was safely casted to NewType - NormalizableDistanceMetric->setNorm( - // TODO: (1) Sigma von Sample - // History(!) abholen, (2) irgendwas mit Sigma hier reinschreiben, - // und (3) überlegen wegen zweiter History (länger) für - // Sigmaberechnung - ); - } - */ // Iterate through all history DABs - for (unsigned int t = 1; - t <= DriftLookbackRange && t < DABHistory.numberOfEntries(); t++) { + for (unsigned int t = 0; t <= DriftLookbackRange; t++) { - // Pick one history DAB - DABHistoryEntry DAB2Compare = + DABHistoryEntry DAB_T = DABHistory[DABHistory.numberOfEntries() - (t + 1)]; - - // Calculate distance between most recent (completed) DAB and the - // chosen history DAB - PROCDATATYPE dist = DistanceMetric( - std::make_pair(CurrentDAB.AvgValue, DAB2Compare.AvgValue)); - - // Add current confidences for Stable, drift down and drift up - // together - CurrentConfidenceStable += FuzzyFunctionSignalIsStable(dist); - CurrentConfidenceStateDriftingDown += - FuzzyFunctionSignalIsDriftingDown(dist); - CurrentConfidenceStateDriftingUp += - FuzzyFunctionSignalIsDriftingUp(dist); - - // Add history confidences for Stable, drift down and drift up - // together - HistoryConfidenceStable += DAB2Compare.DecisionDABIsStable; - HistoryConfidenceStateDriftingDown += - DAB2Compare.DecisionDABIsDriftingDown; - HistoryConfidenceStateDriftingUp += - DAB2Compare.DecisionDABIsDriftingUp; + MeanY += DAB_T.AvgValue; } + MeanY /= (DriftLookbackRange+1); - // chose right divisor for average calculation - unsigned int numOfCompares; - if (DriftLookbackRange <= DABHistory.numberOfEntries()) - numOfCompares = DriftLookbackRange; - else - numOfCompares = - static_cast(DABHistory.numberOfEntries() - 1); - - // calculate the average of the current confidence decision - CurrentConfidenceStable /= numOfCompares; - CurrentConfidenceStateDriftingDown /= numOfCompares; - CurrentConfidenceStateDriftingUp /= numOfCompares; - - // store the current confidence decision in current DAB - CurrentDAB.DecisionDABIsStable = CurrentConfidenceStable; - CurrentDAB.DecisionDABIsDriftingDown = - CurrentConfidenceStateDriftingDown; - CurrentDAB.DecisionDABIsDriftingUp = CurrentConfidenceStateDriftingUp; - CurrentDAB.DABIsCurrent = false; - // calculate the confidences for SignalStateInfo (current output) - HistoryConfidenceStable = - (HistoryConfidenceStable + CurrentConfidenceStable) / - (numOfCompares + 1); - HistoryConfidenceStateDriftingDown = - (HistoryConfidenceStateDriftingDown + - CurrentConfidenceStateDriftingDown) / - (numOfCompares + 1); - HistoryConfidenceStateDriftingUp = (HistoryConfidenceStateDriftingUp + - CurrentConfidenceStateDriftingUp) / - (numOfCompares + 1); - - // set SignalStateInfo Confidences - SignalStateInfo.ConfidenceStateIsStable = HistoryConfidenceStable; - SignalStateInfo.ConfidenceStateIsDrifting = - HistoryConfidenceStateDriftingDown > - HistoryConfidenceStateDriftingUp - ? HistoryConfidenceStateDriftingDown - : HistoryConfidenceStateDriftingUp; + for (unsigned int t = 0; t <= DriftLookbackRange; t++) { + DABHistoryEntry DAB_T = + DABHistory[DABHistory.numberOfEntries() - (t + 1)]; + k += (DriftLookbackRange - t - MeanX)*(DAB_T.AvgValue - MeanY); + } + k /= RegressionDivisor; + + SignalStateInfo.ConfidenceStateIsStable = + FuzzyFunctionSignalIsStable(k); SignalStateInfo.ConfidenceStateIsDriftingDown = - HistoryConfidenceStateDriftingDown; + FuzzyFunctionSignalIsDriftingDown(k); SignalStateInfo.ConfidenceStateIsDriftingUp = - HistoryConfidenceStateDriftingUp; + FuzzyFunctionSignalIsDriftingUp(k); + if (SignalStateInfo.ConfidenceStateIsDriftingDown > + SignalStateInfo.ConfidenceStateIsDriftingUp) { + SignalStateInfo.ConfidenceStateIsDrifting = + SignalStateInfo.ConfidenceStateIsDriftingDown; + } else { + SignalStateInfo.ConfidenceStateIsDrifting = + SignalStateInfo.ConfidenceStateIsDriftingUp; + } // set SignalStateInfo StateCondition if (SignalStateInfo.ConfidenceStateIsStable > SignalStateInfo.ConfidenceStateIsDrifting) SignalStateInfo.StateCondition = StateConditions::STABLE; else if (SignalStateInfo.ConfidenceStateIsStable < SignalStateInfo.ConfidenceStateIsDrifting) if (SignalStateInfo.ConfidenceStateIsDriftingDown > SignalStateInfo.ConfidenceStateIsDriftingUp) SignalStateInfo.StateCondition = StateConditions::DRIFTING_DN; else if (SignalStateInfo.ConfidenceStateIsDriftingDown < SignalStateInfo.ConfidenceStateIsDriftingUp) SignalStateInfo.StateCondition = StateConditions::DRIFTING_UP; else SignalStateInfo.StateCondition = StateConditions::UNKNOWN; else SignalStateInfo.StateCondition = StateConditions::UNKNOWN; } } else { SignalStateInfo.ConfidenceStateIsStable = 0; SignalStateInfo.ConfidenceStateIsDrifting = 0; SignalStateInfo.ConfidenceStateIsDriftingDown = 0; SignalStateInfo.ConfidenceStateIsDriftingUp = 0; SignalStateInfo.StateCondition = StateConditions::UNKNOWN; } } }; // namespace agent } // namespace agent } // End namespace rosa #endif // ROSA_AGENT_SIGNALSTATE_HPP