diff --git a/include/rosa/agent/SignalState.hpp b/include/rosa/agent/SignalState.hpp index 7f8d206..7557729 100644 --- a/include/rosa/agent/SignalState.hpp +++ b/include/rosa/agent/SignalState.hpp @@ -1,462 +1,528 @@ //===-- 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/FunctionAbstractions.hpp" #include "rosa/agent/Functionality.h" #include "rosa/agent/History.hpp" #include "rosa/support/math.hpp" namespace rosa { namespace agent { /// Signal state conditions defining how the condition of a \c /// rosa::agent::SignalState is saved in \c rosa::agent::SignalStateInformation. enum SignalStateCondition : uint8_t { STABLE = 0, ///< The signal state is stable DRIFTING = 1, ///< The signal state is drifting UNKNOWN = 2 ///< The signal state is unknown }; /// TODO: write description template struct SignalStateInformation { // Make sure the actual type arguments are matching our expectations. STATIC_ASSERT((std::is_arithmetic::value), "confidence type is not to arithmetic"); /// The signal state ID saved as an uint32_teger number uint32_t SignalStateID; /// The SignalStateConfidence shows the overall confidence value of the signal /// state. CONFDATATYPE SignalStateConfidence; /// The SignalStateCondition shows the condition of a signal state (stable, /// drifting, or unknown) SignalStateCondition SignalStateCondition; /// The SignalStateIsValid saves the number of samples which have been /// inserted into the state after entering it. uint32_t NumberOfInsertedSamplesAfterEntrance; /// The SignalStateIsValid shows whether a signal state is valid or invalid. /// In this context, valid means that enough samples which are in close /// proximitry have been inserted into the signal state. bool SignalStateIsValid; /// The SignalStateJustGotValid shows whether a signal state got valid /// (toggled from invalid to valid) during the current inserted sample. bool SignalStateJustGotValid; /// The SignalStateIsValidAfterReentrance shows whether a signal state is /// valid after the variable changed back to it again. bool SignalStateIsValidAfterReentrance; /// The SignalIsStableNotDrifting shows whether a signal is stable and not /// drifting. bool SignalIsStable; }; /// \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"); private: // For the convinience to write a shorter data type name using PartFuncPointer = std::shared_ptr>; using StepFuncPointer = std::shared_ptr>; /// SignalStateInfo is a struct SignalStateInformation that contains /// information about the current state. SignalStateInformation SignalStateInfo; /// The FuzzyFunctionSampleMatches is the fuzzy function that gives the /// confidence how good the new sample matches another sample in the sample /// history. PartFuncPointer FuzzyFunctionSampleMatches; /// The FuzzyFunctionSampleMismatches is the fuzzy function that gives the /// confidence how bad the new sample matches another sample in the sample /// history. PartFuncPointer FuzzyFunctionSampleMismatches; /// The FuzzyFunctionNumOfSamplesMatches is the fuzzy function that gives the /// confidence how many samples from the sampe history match the new sample. StepFuncPointer FuzzyFunctionNumOfSamplesMatches; /// The FuzzyFunctionNumOfSamplesMismatches is the fuzzy function that gives /// the confidence how many samples from the sampe history mismatch the new /// sample. StepFuncPointer FuzzyFunctionNumOfSamplesMismatches; /// 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. PartFuncPointer 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). PartFuncPointer FuzzyFunctionSignalIsStable; /// 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 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; public: // @Maxi doxygen per default doesn't display private attributes of a class. So // I copied them to the constructor. So the user has more information. /// Creates an instance by setting all parameters /// \param SignalStateID The Id of the SignalStateinfo \c /// SignalStateInformation. /// /// \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, uint32_t SampleHistorySize, uint32_t DABSize, uint32_t DABHistorySize, PartFuncPointer FuzzyFunctionSampleMatches, PartFuncPointer FuzzyFunctionSampleMismatches, StepFuncPointer FuzzyFunctionNumOfSamplesMatches, StepFuncPointer FuzzyFunctionNumOfSamplesMismatches, PartFuncPointer FuzzyFunctionSignalIsDrifting, PartFuncPointer FuzzyFunctionSignalIsStable) noexcept : SignalStateInfo{SignalStateID, 0, SignalStateCondition::UNKNOWN, 0, false, false, false, //@maxi added the Signal is stable bool true}, FuzzyFunctionSampleMatches(FuzzyFunctionSampleMatches), FuzzyFunctionSampleMismatches(FuzzyFunctionSampleMismatches), FuzzyFunctionNumOfSamplesMatches(FuzzyFunctionNumOfSamplesMatches), FuzzyFunctionNumOfSamplesMismatches( FuzzyFunctionNumOfSamplesMismatches), FuzzyFunctionSignalIsDrifting(FuzzyFunctionSignalIsDrifting), FuzzyFunctionSignalIsStable(FuzzyFunctionSignalIsStable), SampleHistory(SampleHistorySize), DAB(DABSize), DABHistory(DABHistorySize), LowestConfidenceMatchingHistory(SampleHistorySize), HighestConfidenceMismatchingHistory(SampleHistorySize) {} /// Destroys \p this object. ~SignalState(void) = default; void leaveSignalState(void) noexcept { DAB.clear(); SignalStateInfo.NumberOfInsertedSamplesAfterEntrance = 0; SignalStateInfo.SignalStateIsValidAfterReentrance = false; } SignalStateInformation insertSample(INDATATYPE Sample) noexcept { validateSignalState(Sample); SampleHistory.addEntry(Sample); DAB.addEntry(Sample); if (DAB.full()) { PROCDATATYPE AvgOfDAB = DAB.template average(); DABHistory.addEntry(AvgOfDAB); DAB.clear(); } FuzzyFunctionNumOfSamplesMatches->setRightLimit( static_cast(SampleHistory.numberOfEntries())); FuzzyFunctionNumOfSamplesMismatches->setRightLimit( static_cast(SampleHistory.numberOfEntries())); checkSignalStability(); 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 = relativeDistance(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. 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 //@David: because we are using these operator functions, here I have to // direference in a not (in my opionin) not so beautiful way //("(*FuzzyFunctionSampleMatches)"), or I have to write //"FuzzyFunctionSampleMatches->operator()(...)". Can we just write // functions like "->getBlabla()" or something like that? ConfidenceFromRelativeDistance = 0; } else { ConfidenceFromRelativeDistance = (*FuzzyFunctionSampleMatches)(RelativeDistanceHistory[Case]); } +#if false + //@maxi why the 2? + ConfidenceOfWorstFittingSample = + fuzzyAND((CONFDATATYPE)2, ConfidenceOfWorstFittingSample, + ConfidenceFromRelativeDistance); + + //@maxi you could also use it like this then you can define the type and the size + ConfidenceOfWorstFittingSample = + fuzzyAND({ConfidenceOfWorstFittingSample, + ConfidenceFromRelativeDistance}); +#else + //@maxi is this what you wanted? you don't need to define the data type + // nor the size + ConfidenceOfWorstFittingSample = fuzzyAND(ConfidenceOfWorstFittingSample, + ConfidenceFromRelativeDistance); +#endif - ConfidenceOfWorstFittingSample = fuzzyAND( - 2, ConfidenceOfWorstFittingSample, ConfidenceFromRelativeDistance); //@benedikt: same as before with "->operator()" + //@maxi the same as before +#if false ConfidenceOfBestCase = fuzzyOR( 2, ConfidenceOfBestCase, fuzzyAND(2, ConfidenceOfWorstFittingSample, FuzzyFunctionNumOfSamplesMatches->operator()( static_cast(Case) + 1))); +#else + ConfidenceOfBestCase = + fuzzyOR(ConfidenceOfBestCase, + fuzzyAND(ConfidenceOfWorstFittingSample, + FuzzyFunctionNumOfSamplesMatches->operator()( + static_cast(Case) + 1))); + +#endif } 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( relativeDistance(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; // 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. // TODO (future): to accelerate -> don't go until end. Confidences will only // get higher. See comment in "CONFDATATYPE // confidenceSampleMatchesSignalState(INDATATYPE Sample)". for (uint32_t Case = 0; Case < RelativeDistanceHistory.numberOfEntries(); Case++) { CONFDATATYPE ConfidenceFromRelativeDistance; if (std::isinf(RelativeDistanceHistory[Case])) { ConfidenceFromRelativeDistance = 1; } else { //@benedikt: I had to change the following line. The outcommented line // was the original one. I think it is ugly like that (new line). Do you // have an idea how to make it better/more beautiful? ConfidenceFromRelativeDistance = FuzzyFunctionSampleMismatches->operator()( RelativeDistanceHistory[Case]); } +//@maxi you don't have to define the data type or the amount +#if false ConfidenceOfBestFittingSample = fuzzyOR( 2, ConfidenceOfBestFittingSample, ConfidenceFromRelativeDistance); //@benedikt: same as before with "->operator()" ConfidenceOfWorstCase = fuzzyAND( 2, ConfidenceOfWorstCase, fuzzyOR(2, ConfidenceOfBestFittingSample, FuzzyFunctionNumOfSamplesMismatches->operator()( static_cast(Case) + 1))); +#else + ConfidenceOfBestFittingSample = fuzzyOR(ConfidenceOfBestFittingSample, + ConfidenceFromRelativeDistance); + + //@benedikt: same as before with "->operator()" + ConfidenceOfWorstCase = + fuzzyAND(ConfidenceOfWorstCase, + fuzzyOR(ConfidenceOfBestFittingSample, + FuzzyFunctionNumOfSamplesMismatches->operator()( + static_cast(Case) + 1))); +#endif } 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. //@benedikt: same with "->operator()" + //@maxi you don't have to deine the data type nor the amount +#if false LowestConfidenceMatching = fuzzyAND(2, LowestConfidenceMatching, FuzzyFunctionSampleMatches->operator()( relativeDistance( Sample, HistorySample))); //@benedikt: same with "->operator()" HighestConfidenceMismatching = fuzzyOR(2, HighestConfidenceMismatching, FuzzyFunctionSampleMismatches->operator()( relativeDistance( Sample, HistorySample))); +#else + LowestConfidenceMatching = + fuzzyAND(LowestConfidenceMatching, + FuzzyFunctionSampleMatches->operator()( + relativeDistance( + Sample, HistorySample))); + //@benedikt: same with "->operator()" + HighestConfidenceMismatching = + fuzzyOR(HighestConfidenceMismatching, + FuzzyFunctionSampleMismatches->operator()( + relativeDistance( + Sample, HistorySample))); +#endif } LowestConfidenceMatchingHistory.addEntry(LowestConfidenceMatching); HighestConfidenceMismatchingHistory.addEntry(HighestConfidenceMismatching); LowestConfidenceMatching = LowestConfidenceMatchingHistory.lowestEntry(); HighestConfidenceMismatching = HighestConfidenceMismatchingHistory.highestEntry(); + //@maxi you don't have to define the data type or the amount +#if false //@benedikt: same with "->operator()" CONFDATATYPE ConfidenceSignalStateIsValid = fuzzyAND( 2, LowestConfidenceMatching, FuzzyFunctionNumOfSamplesMatches->operator()(static_cast( SignalStateInfo.NumberOfInsertedSamplesAfterEntrance))); //@benedikt: same with "->operator()" CONFDATATYPE ConfidenceSignalStateIsInvalid = fuzzyOR( 2, HighestConfidenceMismatching, FuzzyFunctionNumOfSamplesMismatches->operator()(static_cast( SignalStateInfo.NumberOfInsertedSamplesAfterEntrance))); +#else + //@benedikt: same with "->operator()" + CONFDATATYPE ConfidenceSignalStateIsValid = fuzzyAND( + LowestConfidenceMatching, + FuzzyFunctionNumOfSamplesMatches->operator()(static_cast( + SignalStateInfo.NumberOfInsertedSamplesAfterEntrance))); + //@benedikt: same with "->operator()" + CONFDATATYPE ConfidenceSignalStateIsInvalid = fuzzyOR( + HighestConfidenceMismatching, + FuzzyFunctionNumOfSamplesMismatches->operator()(static_cast( + SignalStateInfo.NumberOfInsertedSamplesAfterEntrance))); +#endif if (ConfidenceSignalStateIsValid > ConfidenceSignalStateIsInvalid) { if (SignalStateInfo.SignalStateIsValid) { SignalStateInfo.SignalStateJustGotValid = false; } else { SignalStateInfo.SignalStateJustGotValid = true; } SignalStateInfo.SignalStateIsValid = true; SignalStateInfo.SignalStateIsValidAfterReentrance = true; } } void checkSignalStability(void) { CONFDATATYPE ConfidenceSignalIsStable; CONFDATATYPE ConfidenceSignalIsDrifting; if (DABHistory.numberOfEntries() >= 2) { //@benedikt: same "->operator()" ConfidenceSignalIsStable = FuzzyFunctionSignalIsStable->operator()( relativeDistance( DABHistory[DABHistory.numberOfEntries() - 1], DABHistory[0])); //@benedikt: same "->operator()" ConfidenceSignalIsDrifting = FuzzyFunctionSignalIsDrifting->operator()( relativeDistance( DABHistory[DABHistory.numberOfEntries() - 1], DABHistory[0])); } else { // TODO: change to enum ConfidenceSignalIsStable = 1; ConfidenceSignalIsDrifting = 0; } SignalStateInfo.SignalIsStable = ConfidenceSignalIsStable >= ConfidenceSignalIsDrifting; } }; } // End namespace agent } // End namespace rosa #endif // ROSA_AGENT_SIGNALSTATE_HPP diff --git a/include/rosa/agent/SignalStateDetector.hpp b/include/rosa/agent/SignalStateDetector.hpp index 99af791..d7b10e9 100644 --- a/include/rosa/agent/SignalStateDetector.hpp +++ b/include/rosa/agent/SignalStateDetector.hpp @@ -1,272 +1,278 @@ //===-- rosa/agent/SignalStateDetector.hpp ----------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/agent/SignalStateDetector.hpp /// /// \author Maximilian Götzinger (maximilian.goetzinger@tuwien.ac.at) /// /// \date 2019 /// /// \brief Definition of *signal state detector* *functionality*. /// //===----------------------------------------------------------------------===// #ifndef ROSA_AGENT_SIGNALSTATEDETECTOR_HPP #define ROSA_AGENT_SIGNALSTATEDETECTOR_HPP #include "rosa/agent/Functionality.h" #include "rosa/agent/SignalState.hpp" #include "rosa/agent/StateDetector.hpp" #include namespace rosa { namespace agent { /// Implements \c rosa::agent::SignalStateDetector as a functionality that /// detects signal states given on input samples. /// /// \note This implementation is supposed to be used for samples of an /// arithmetic type. /// /// \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 SignalStateDetector : public StateDetector { + // @maxi added them so it is compilable is this what you intended? + using StateDetector = + StateDetector; + using PartFuncPointer = typename StateDetector::PartFuncPointer; + using StepFuncPointer = typename StateDetector::StepFuncPointer; + private: // For the convinience to write a shorter data type name using SignalStatePtr = std::shared_ptr>; /// The NextSignalStateID is a counter variable which stores the ID which the /// next signal state shall have. uint32_t NextSignalStateID; /// The SignalStateHasChanged is a flag that show whether a signal has changed /// its state. bool SignalStateHasChanged; /// The CurrentSignalState is a pointer to the (saved) signal state in which /// the actual variable (signal) of the observed system is. SignalStatePtr CurrentSignalState; /// The DetectedSignalStates is a history in that all detected signal states /// are saved. DynamicLengthHistory DetectedSignalStates; /// The FuzzyFunctionSampleMatches is the fuzzy function that gives the /// confidence how good the new sample matches another sample in the sample /// history. PartFuncPointer FuzzyFunctionSampleMatches; /// The FuzzyFunctionSampleMismatches is the fuzzy function that gives the /// confidence how bad the new sample matches another sample in the sample /// history. PartFuncPointer FuzzyFunctionSampleMismatches; /// The FuzzyFunctionNumOfSamplesMatches is the fuzzy function that gives the /// confidence how many samples from the sampe history match the new sample. StepFuncPointer FuzzyFunctionNumOfSamplesMatches; /// The FuzzyFunctionNumOfSamplesMismatches is the fuzzy function that gives /// the confidence how many samples from the sampe history mismatch the new /// sample. StepFuncPointer FuzzyFunctionNumOfSamplesMismatches; /// The FuzzyFunctionSignalIsDrifting is the fuzzy function that gives the /// confidence how likely it is that the signal is drifting. PartFuncPointer FuzzyFunctionSignalIsDrifting; /// The FuzzyFunctionSignalIsStable is the fuzzy function that gives the /// confidence how likely it is that the signal is stable (not drifting). PartFuncPointer FuzzyFunctionSignalIsStable; /// SampleHistorySize is the (maximum) size of the sample history. uint32_t SampleHistorySize; /// DABSize the size of a DAB (Discrete Average Block). uint32_t DABSize; /// DABHistorySize is the (maximum) size of the DAB history. uint32_t DABHistorySize; public: /// Creates an instance by setting all parameters /// \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 Sets the History size which will be used by \c /// SignalState. /// /// \param DABSize Sets the DAB size which will be used by \c SignalState. /// /// \param DABHistorySize Sets the size which will be used by \c SignalState. /// SignalStateDetector(uint32_t MaximumNumberOfSignalStates, PartFuncPointer FuzzyFunctionSampleMatches, PartFuncPointer FuzzyFunctionSampleMismatches, StepFuncPointer FuzzyFunctionNumOfSamplesMatches, StepFuncPointer FuzzyFunctionNumOfSamplesMismatches, PartFuncPointer FuzzyFunctionSignalIsDrifting, PartFuncPointer FuzzyFunctionSignalIsStable, uint32_t SampleHistorySize, uint32_t DABSize, uint32_t DABHistorySize) noexcept : NextSignalStateID(1), SignalStateHasChanged(false), CurrentSignalState(nullptr), DetectedSignalStates(MaximumNumberOfSignalStates), FuzzyFunctionSampleMatches(FuzzyFunctionSampleMatches), FuzzyFunctionSampleMismatches(FuzzyFunctionSampleMismatches), FuzzyFunctionNumOfSamplesMatches(FuzzyFunctionNumOfSamplesMatches), FuzzyFunctionNumOfSamplesMismatches( FuzzyFunctionNumOfSamplesMismatches), FuzzyFunctionSignalIsDrifting(FuzzyFunctionSignalIsDrifting), FuzzyFunctionSignalIsStable(FuzzyFunctionSignalIsStable), SampleHistorySize(SampleHistorySize), DABSize(DABSize), DABHistorySize(DABHistorySize) {} /// Destroys \p this object. ~SignalStateDetector(void) = default; /// Detects the signal state to which the new sample belongs or create a new /// signal state if the new sample does not match to any of the saved states. /// /// \param Sample is the actual sample of the observed signal. /// /// \return the information of the current signal state (signal state ID and /// other parameters). // TODO (future): change to operator() SignalStateInformation detectSignalState(INDATATYPE Sample) noexcept { if (!CurrentSignalState) { ASSERT(DetectedSignalStates.empty()); SignalStatePtr S = createNewSignalState(); CurrentSignalState = S; } else { CONFDATATYPE ConfidenceSampleMatchesSignalState = CurrentSignalState->confidenceSampleMatchesSignalState(Sample); CONFDATATYPE ConfidenceSampleMismatchesSignalState = CurrentSignalState->confidenceSampleMismatchesSignalState(Sample); if (ConfidenceSampleMatchesSignalState > ConfidenceSampleMismatchesSignalState) { SignalStateHasChanged = false; } else { SignalStateHasChanged = true; if (CurrentSignalState->signalStateInformation().SignalStateIsValid) { CurrentSignalState->leaveSignalState(); } else { DetectedSignalStates.deleteEntry(CurrentSignalState); } // TODO (future): additionally save averages to enable fast iteration // through recorded signl state history (maybe sort vector based on // these average values) CurrentSignalState = nullptr; //@benedikt: same question for (auto &SavedSignalState : DetectedSignalStates) { if (SavedSignalState != CurrentSignalState) { ConfidenceSampleMatchesSignalState = SavedSignalState->confidenceSampleMatchesSignalState(Sample); ConfidenceSampleMismatchesSignalState = SavedSignalState->confidenceSampleMismatchesSignalState(Sample); if (ConfidenceSampleMatchesSignalState > ConfidenceSampleMismatchesSignalState) { // TODO (future): maybe it would be better to compare // ConfidenceSampleMatchesSignalState of all signal states in the // vector in order to find the best matching signal state. CurrentSignalState = SavedSignalState; break; } } } if (!CurrentSignalState) { SignalStatePtr S = createNewSignalState(); CurrentSignalState = S; } } } SignalStateInformation SignalStateInfo = CurrentSignalState->insertSample(Sample); if (SignalStateInfo.SignalStateJustGotValid) { NextSignalStateID++; } return SignalStateInfo; } /// Gives information about the current signal state. /// /// \return a struct SignalStateInformation that contains information about /// the current signal state or NULL if no current signal state exists. SignalStateInformation currentSignalStateInformation(void) noexcept { if (CurrentSignalState) { return CurrentSignalState->signalStateInformation(); } else { return NULL; } } /// Gives information whether a signal state change has happened or not. /// /// \return true if a signal state change has happened, and false if not. bool signalStateHasChanged(void) noexcept { return SignalStateHasChanged; } private: /// Creates a new signal state and adds it to the signal state vector in which /// all known states are saved. /// /// \return a pointer to the newly created signal state or NULL if no state /// could be created. SignalStatePtr createNewSignalState(void) noexcept { SignalStatePtr S(new SignalState( NextSignalStateID, SampleHistorySize, DABSize, DABHistorySize, FuzzyFunctionSampleMatches, FuzzyFunctionSampleMismatches, FuzzyFunctionNumOfSamplesMatches, FuzzyFunctionNumOfSamplesMismatches, FuzzyFunctionSignalIsDrifting, FuzzyFunctionSignalIsStable)); DetectedSignalStates.addEntry(S); return S; } }; } // End namespace agent } // End namespace rosa #endif // ROSA_AGENT_SIGNALSTATEDETECTOR_HPP diff --git a/include/rosa/agent/StateDetector.hpp b/include/rosa/agent/StateDetector.hpp index aa341f6..9bd7430 100644 --- a/include/rosa/agent/StateDetector.hpp +++ b/include/rosa/agent/StateDetector.hpp @@ -1,56 +1,57 @@ //===-- rosa/agent/StateDetector.hpp ----------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/agent/StateDetector.hpp /// /// \author Maximilian Götzinger (maximilian.goetzinger@tuwien.ac.at) /// /// \date 2019 /// /// \brief Definition of *state detector* *functionality*. /// //===----------------------------------------------------------------------===// #ifndef ROSA_AGENT_STATEDETECTOR_HPP #define ROSA_AGENT_STATEDETECTOR_HPP #include "rosa/agent/FunctionAbstractions.hpp" #include "rosa/agent/History.hpp" #include namespace rosa { namespace agent { template class StateDetector : 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 abstraction type is not to arithmetic"); -protected: +public: using PartFuncPointer = std::shared_ptr>; using StepFuncPointer = std::shared_ptr>; +protected: /// The NextSignalStateID is a counter variable which stores the ID which the /// next signal state shall have. unsigned int NextStateID; /// The SignalStateHasChanged is a flag that show whether a signal has changed /// its state. bool StateHasChanged; }; } // End namespace agent } // End namespace rosa #endif // ROSA_AGENT_SIGNALSTATEDETECTOR_HPP diff --git a/include/rosa/agent/SystemStateDetector.hpp b/include/rosa/agent/SystemStateDetector.hpp index ac9072e..31335bf 100644 --- a/include/rosa/agent/SystemStateDetector.hpp +++ b/include/rosa/agent/SystemStateDetector.hpp @@ -1,141 +1,146 @@ //===-- rosa/agent/SystemStateDetector.hpp ----------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/agent/SystemStateDetector.hpp /// /// \author Maximilian Götzinger (maximilian.goetzinger@tuwien.ac.at) /// /// \date 2019 /// /// \brief Definition of *system state detector* *functionality*. /// //===----------------------------------------------------------------------===// #ifndef ROSA_AGENT_SYSTEMSTATEDETECTOR_HPP #define ROSA_AGENT_SYSTEMSTATEDETECTOR_HPP #include "rosa/agent/Functionality.h" #include "rosa/agent/StateDetector.hpp" #include "rosa/agent/SystemState.hpp" #include "rosa/support/debug.hpp" namespace rosa { namespace agent { /// System state conditions defining how the condition of a \c /// rosa::agent::SystemState is saved in \c rosa::agent::SystemStateInformation. enum class SystemStateCondition { STABLE, ///< The system state is stable DRIFTING, ///< The system state is drifting MALFUNCTIONING, ///< The system state is malfunctioning UNKNOWN ///< The system state is unknown }; /// TODO: write description template struct SystemStateInformation { // Make sure the actual type arguments are matching our expectations. STATIC_ASSERT((std::is_arithmetic::value), "confidence type is not to arithmetic"); /// The system state ID saved as an uint32_teger number uint32_t SystemStateID; /// The SystemStateConfidence shows the overall confidence value of the system /// state. CONFDATATYPE OverallDetectionConfidence; /// The SystemStateCondition shows the condition of a system state (stable, /// drifting, malfunctioning, or unknown) //@David: is it ok to name the variable exactly as the type is named? SystemStateCondition SystemStateCondition; /// The SystemStateIsValid saves the number of samples which have been /// inserted into the state after entering it. uint32_t NumberOfInsertedSamplesAfterEntrance; /// The SystemStateIsValid shows whether a state is valid or invalid. /// In this context, valid means that enough samples which are in close /// proximitry have been inserted into the state. bool SystemStateIsValid; /// The SystemStateJustGotValid shows whether a system state got valid /// (toggled from invalid to valid) during the current inserted sample. bool SystemStateJustGotValid; /// The SystemStateIsValidAfterReentrance shows whether a system state is /// valid after the variable changed back to it again. bool SystemStateIsValidAfterReentrance; /// The SystemIsStable shows whether a signa is stable and not /// drifting. bool SystemIsStable; }; /// TODO: write description template class SystemStateDetector : public StateDetector { + //@maxi added them to make it compilable is this what you wanted? + using StateDetector = + StateDetector; + using PartFuncPointer = typename StateDetector::PartFuncPointer; + private: // For the convinience to write a shorter data type name using SystemStatePtr = std::shared_ptr>; /// The NextSystemStateID is a counter variable which stores the ID which /// the /// next system state shall have. uint32_t NextSystemStateID; /// The SystemStateHasChanged is a flag that show whether the observed /// system /// has changed its state. bool SystemStateHasChanged; /// The CurrentSystemState is a pointer to the (saved) system state in which /// the actual state of the observed system is. SystemStatePtr CurrentSystemState; /// The DetectedSystemStates is a history in that all detected system states /// are saved. DynamicLengthHistory DetectedSystemStates; /// The FuzzyFunctionDelayTimeToGetBroken is the fuzzy function that gives /// the confidence whether the system is Broken because of an input change /// without an output change or vice versa. A small time gap between the two /// shall be allowed. PartFuncPointer FuzzyFunctionDelayTimeToGetBroken; /// The FuzzyFunctionDelayTimeToBeWorking is the fuzzy function that gives /// the /// confidence whether the system is still OK allthough an input change /// without an output change or vice versa. PartFuncPointer FuzzyFunctionDelayTimeToBeWorking; public: /// TODO: write description SystemStateDetector( uint32_t MaximumNumberOfSystemStates, PartFuncPointer FuzzyFunctionDelayTimeToGetBroken, PartFuncPointer FuzzyFunctionDelayTimeToBeWorking) noexcept : NextSystemStateID(1), SystemStateHasChanged(false), CurrentSystemState(nullptr), DetectedSystemStates(MaximumNumberOfSystemStates), FuzzyFunctionDelayTimeToGetBroken(FuzzyFunctionDelayTimeToGetBroken), FuzzyFunctionDelayTimeToBeWorking(FuzzyFunctionDelayTimeToBeWorking) {} /// Destroys \p this object. ~SystemStateDetector(void) = default; /// TODO: write description SystemStateInformation detectSystemState(INDATATYPE Sample) noexcept { // dummy line Sample = 1; } }; } // End namespace agent } // End namespace rosa #endif // ROSA_AGENT_SYSTEMSTATEDETECTOR_HPP diff --git a/include/rosa/support/math.hpp b/include/rosa/support/math.hpp index 30e11fb..95a7363 100644 --- a/include/rosa/support/math.hpp +++ b/include/rosa/support/math.hpp @@ -1,153 +1,153 @@ //===-- rosa/support/math.hpp -----------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/support/math.hpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief Math helpers. /// //===----------------------------------------------------------------------===// // !!!!!! Please check lines 60 - 180 forward !!!!!!!!!!!!!! #ifndef ROSA_SUPPORT_MATH_HPP #define ROSA_SUPPORT_MATH_HPP #include "debug.hpp" #include #include #include #include #include #include #include namespace rosa { /// Computes log base 2 of a number. /// /// \param N the number to compute log base 2 for /// /// \return log base 2 of \p N constexpr size_t log2(const size_t N) { return ((N < 2) ? 1 : 1 + log2(N / 2)); } /// Tells the next representable floating point value. /// /// \tparam T type to operate on /// /// \note The second type argument enforces \p T being a floating point type, /// always use the default value! /// /// \param V value to which find the next representable one /// /// \return the next representable value of type \p T after value \p V /// /// \pre Type \p T must be a floating point type, which is enforced by /// `std::enable_if` in the second type argument. template ::value>> T nextRepresentableFloatingPoint(const T V) { return std::nextafter(V, std::numeric_limits::infinity()); } /// Conjuncts two or more values with each other. /// /// \param Data an array of the data /// /// \return the conjunction of the values given as parameter. template CONFDATATYPE fuzzyAND(const std::array & Data) noexcept { STATIC_ASSERT(std::is_arithmetic::value, "Type of FuzzyAnd is not arithmetic"); STATIC_ASSERT(size > 1, "Number of Arguments is to little"); for (auto tmp : Data) ASSERT(tmp <= 1 && tmp >= 0); return *std::min_element(Data.begin(), Data.end()); } /// Conjuncts two or more values with each other. It's a wrapper for \c fuzzyAND() [array] /// /// \param Data first data to get the type explicitly /// /// \param Datan a package of data /// /// \note the types of Datan must be the same type as Data /// /// \return the conjunction of the values given as parameter. template std::enable_if_t< std::conjunction_v...>, CONFDATATYPE> -fuzzyAND(CONFDATATYPE & Data, _CONFDATATYPE&... Datan) noexcept { +fuzzyAND(const CONFDATATYPE Data, const _CONFDATATYPE... Datan) noexcept { return fuzzyAND( std::array{Data, Datan...}); } /// Disjuncts two or more values with each other. /// /// \param Data an array with the data. /// /// \return the disjunction of the values given as parameter. template CONFDATATYPE fuzzyOR(const std::array & Data) noexcept { STATIC_ASSERT(std::is_arithmetic::value, "Type of FuzzyAnd is not arithmetic"); STATIC_ASSERT(size > 1, "Number of Arguments is to little"); ASSERT(std::all_of(Data.begin(), Data.end(), [](const auto &v) { return v <= 1 && v >= 0; })); return *std::max_element(Data.begin(), Data.end()); } /// Disjuncts two or more values with each other. It's a wrapper for \c fuzzyOR() [array] /// /// \param Data first data to get the type explicitly /// /// \param Datan a package of data /// /// \note the types of Datan must be the same type as Data /// /// \return the disjunction of the values given as parameter. template std::enable_if_t< std::conjunction_v...>, CONFDATATYPE> -fuzzyOR(const CONFDATATYPE & Data, const _CONFDATATYPE&... Datan) noexcept { +fuzzyOR(const CONFDATATYPE Data, const _CONFDATATYPE... Datan) noexcept { return fuzzyOR( std::array{Data, Datan...}); } template PROCDATATYPE relativeDistance(INDATATYPE NewValue, INDATATYPE HistoryValue) noexcept { PROCDATATYPE Dist = HistoryValue - NewValue; if (Dist == 0) { return 0; } else { Dist = Dist / NewValue; if (Dist < 0) { // TODO: I guess this multiplication here should not be done because // it could be that the distance fuzzy functions are not symetrical //(negative and positive side) Dist = Dist * (-1); } return (Dist); } } } // End namespace rosa #endif // ROSA_SUPPORT_MATH_HPP