diff --git a/include/rosa/agent/SignalState.hpp b/include/rosa/agent/SignalState.hpp index 4b001a5..f461e5c 100644 --- a/include/rosa/agent/SignalState.hpp +++ b/include/rosa/agent/SignalState.hpp @@ -1,606 +1,617 @@ //===-- 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 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; } 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 FuzzyFunctionSignalIsDrifting is the fuzzy function that gives the /// confidence how likely it is that the signal (resp. the state of a signal) /// is drifting. PartFuncReference FuzzyFunctionSignalIsDrifting; /// 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. std::vector> DABs; /// DABHistory is a history in that the last DABs (to be exact, the averages /// of the last DABs) are stored. std::vector> DABHistories; /// 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; #pragma GCC diagnostic ignored "-Wunused-parameter" 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 FuzzyFunctionSignalIsDrifting The FuzzyFunctionSignalIsDrifting is /// the fuzzy function that gives the confidence how likely it is that the /// signal (resp. the state of a signal) is drifting. /// /// \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. /// /// \param DABSize Size of DAB \c DynamicLengthHistory . DAB is a (usually) /// small history of the last sample values of which a average is calculated /// if the DAB is full. /// /// \param DABHistorySize Size of the DABHistory \c DynamicLengthHistory . /// DABHistory is a history in that the last DABs (to be exact, the averages /// of the last DABs) are stored. /// SignalState( uint32_t SignalStateID, SignalProperties SignalProperty, uint32_t SampleHistorySize, uint32_t DABSize, uint32_t DABHistorySize, DistanceMetricAbstraction DistanceMetric, PartFuncReference FuzzyFunctionSampleMatches, PartFuncReference FuzzyFunctionSampleMismatches, StepFuncReference FuzzyFunctionNumOfSamplesMatches, StepFuncReference FuzzyFunctionNumOfSamplesMismatches, PartFuncReference FuzzyFunctionSampleValid, PartFuncReference FuzzyFunctionSampleInvalid, StepFuncReference FuzzyFunctionNumOfSamplesValid, StepFuncReference FuzzyFunctionNumOfSamplesInvalid, // SAVE CHANGES PartFuncReference FuzzyFunctionSignalIsDrifting, PartFuncReference FuzzyFunctionSignalIsStable, PartialFunction &FuzzyFunctionSignalConditionLookBack, // - SAVE CHANGES 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), FuzzyFunctionSignalIsDrifting(FuzzyFunctionSignalIsDrifting), FuzzyFunctionSignalIsStable(FuzzyFunctionSignalIsStable), // SAVE CHANGES FuzzyFunctionSignalConditionLookBack( FuzzyFunctionSignalConditionLookBack), FuzzyFunctionSignalConditionHistoryDesicion( FuzzyFunctionSignalConditionHistoryDesicion), DriftLookbackRange(DriftLookbackRange), // - SAVE CHANGES SampleHistory(SampleHistorySize), LowestConfidenceMatchingHistory(SampleHistorySize), HighestConfidenceMismatchingHistory(SampleHistorySize) { //DAB(DABSize); DABs.push_back(3); - DABHistories.push_back(DynamicLengthHistory(DABHistorySize)); + DABHistories.push_back(DABHistorySize); - DABs.push_back(DynamicLengthHistory(5)); - DABHistories.push_back(DynamicLengthHistory(DABHistorySize)); + DABs.push_back(5); + DABHistories.push_back(DABHistorySize); - DABs.push_back(DynamicLengthHistory(10)); - DABHistories.push_back(DynamicLengthHistory(DABHistorySize)); + DABs.push_back(10); + DABHistories.push_back(DABHistorySize); - DABs.push_back(DynamicLengthHistory(20)); - DABHistories.push_back(DynamicLengthHistory(DABHistorySize)); + DABs.push_back(20); + DABHistories.push_back(DABHistorySize); } /// Destroys \p this object. ~SignalState(void) = default; void leaveSignalState(void) noexcept { for(auto& dab: DABs) { dab.clear(); } SignalStateInfo.NumberOfInsertedSamplesAfterEntrance = 0; SignalStateInfo.StateIsValidAfterReentrance = false; } SignalStateInformation insertSample(INDATATYPE Sample) noexcept { SignalStateInfo.NumberOfInsertedSamplesAfterEntrance++; validateSignalState(Sample); SampleHistory.addEntry(Sample); unsigned int index = 0; for(auto& DAB: DABs) { DAB.addEntry(Sample); if (DAB.full()) { PROCDATATYPE AvgOfDAB = DAB.template median(); DABHistories[index].addEntry(AvgOfDAB); DAB.clear(); } index++; } 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) { SignalStateInfo.ConfidenceStateIsStable = 0; SignalStateInfo.ConfidenceStateIsDriftingDown = 0; SignalStateInfo.ConfidenceStateIsDriftingUp = 0; - unsigned int Divider = 0; - + + unsigned int numOfActiveHistories = 0; for(auto& DABHistory: DABHistories) { + CONFDATATYPE ConfidenceStateIsStableInHistory = 0; + CONFDATATYPE ConfidenceStateIsDriftingDownInHistory = 0; + CONFDATATYPE ConfidenceStateIsDriftingUpInHistory = 0; + if (DABHistory.numberOfEntries() >= 2) { + + numOfActiveHistories++; + // SAVE CHANGES INDATATYPE CurrentDAB = DABHistory[DABHistory.numberOfEntries() - 1]; INDATATYPE DAB2Compare; for (unsigned int t = 1; t <= DriftLookbackRange && t < DABHistory.numberOfEntries(); t++) { DAB2Compare = DABHistory[DABHistory.numberOfEntries() - (t + 1)]; INDATATYPE dist = DistanceMetric(std::make_pair(CurrentDAB, DAB2Compare)); // AVG - SignalStateInfo.ConfidenceStateIsStable += + ConfidenceStateIsStableInHistory += FuzzyFunctionSignalIsStable(dist); if (CurrentDAB > DAB2Compare) - SignalStateInfo.ConfidenceStateIsDriftingUp += + ConfidenceStateIsDriftingUpInHistory += FuzzyFunctionSignalIsDrifting(dist); else if (CurrentDAB < DAB2Compare) - SignalStateInfo.ConfidenceStateIsDriftingDown += + ConfidenceStateIsDriftingDownInHistory += FuzzyFunctionSignalIsDrifting(dist); } - + unsigned int Divider = 0; if(DriftLookbackRange<=DABHistory.numberOfEntries()) - Divider += DriftLookbackRange; + Divider = DriftLookbackRange; else - Divider += DABHistory.numberOfEntries(); + Divider = DABHistory.numberOfEntries(); + + SignalStateInfo.ConfidenceStateIsStable += ConfidenceStateIsStableInHistory / Divider; + SignalStateInfo.ConfidenceStateIsDriftingDown += ConfidenceStateIsDriftingDownInHistory / Divider; + SignalStateInfo.ConfidenceStateIsDriftingUp += ConfidenceStateIsDriftingUpInHistory / Divider; } } - SignalStateInfo.ConfidenceStateIsStable /= Divider; - SignalStateInfo.ConfidenceStateIsDriftingDown /= Divider; - SignalStateInfo.ConfidenceStateIsDriftingUp /= Divider; + SignalStateInfo.ConfidenceStateIsStable /= numOfActiveHistories; + SignalStateInfo.ConfidenceStateIsDriftingDown /= numOfActiveHistories; + SignalStateInfo.ConfidenceStateIsDriftingUp /= numOfActiveHistories; if (SignalStateInfo.ConfidenceStateIsDriftingDown > SignalStateInfo.ConfidenceStateIsDriftingUp) { SignalStateInfo.ConfidenceStateIsDrifting = SignalStateInfo.ConfidenceStateIsDriftingDown; SignalStateInfo.StateCondition = StateConditions::DRIFTING_DN; } else if (SignalStateInfo.ConfidenceStateIsDriftingUp > SignalStateInfo.ConfidenceStateIsDriftingDown) { SignalStateInfo.ConfidenceStateIsDrifting = SignalStateInfo.ConfidenceStateIsDriftingUp; SignalStateInfo.StateCondition = StateConditions::DRIFTING_UP; } else SignalStateInfo.StateCondition = StateConditions::STABLE; if (SignalStateInfo.ConfidenceStateIsStable > SignalStateInfo.ConfidenceStateIsDrifting) { SignalStateInfo.StateCondition = StateConditions::STABLE; } else if (SignalStateInfo.ConfidenceStateIsStable == SignalStateInfo.ConfidenceStateIsDrifting) SignalStateInfo.StateCondition = StateConditions::UNKNOWN; } }; // namespace agent } // namespace agent } // End namespace rosa #endif // ROSA_AGENT_SIGNALSTATE_HPP