diff --git a/apps/ccam/statehandlerutils.h b/apps/ccam/statehandlerutils.h index 9bf7ee4..fb7b640 100644 --- a/apps/ccam/statehandlerutils.h +++ b/apps/ccam/statehandlerutils.h @@ -1,184 +1,184 @@ #ifndef STATEHANDLERUTILS_H #define STATEHANDLERUTILS_H #include "rosa/agent/Abstraction.hpp" #include "rosa/agent/Confidence.hpp" #include "rosa/agent/FunctionAbstractions.hpp" #include #include #include #include #include "rosa/config/version.h" #include "rosa/agent/SignalStateDetector.hpp" #include "rosa/agent/SystemStateDetector.hpp" #include "rosa/deluxe/DeluxeContext.hpp" #include "rosa/support/csv/CSVReader.hpp" #include "rosa/support/csv/CSVWriter.hpp" #include #include #include #include using namespace rosa; using namespace rosa::agent; using namespace rosa::deluxe; using namespace rosa::terminal; // Signal State using SignalStateTuple = DeluxeTuple; AgentHandle createSignalStateDetectorAgent( std::unique_ptr &C, const std::string &Name, std::shared_ptr< SignalStateDetector> SigSD) { using Input = std::pair, bool>; using Result = Optional; using Handler = std::function; return C->createAgent( Name, Handler([&Name, &SigSD](Input I) -> Result { LOG_INFO_STREAM << "\n******\n" << Name << " " << (I.second ? "" : "") << " value: " << std::get<0>(I.first) << "\n******\n"; auto StateInfo = SigSD->detectSignalState(std::get<0>(I.first)); if (I.second) { SignalStateTuple Res = { std::get<0>(I.first), StateInfo.StateID, StateInfo.SignalProperty, //@benedikt: I changed this // StateInfo.SignalStateConfidence, StateInfo.ConfidenceOfMatchingState, StateInfo.ConfidenceOfMismatchingState, StateInfo.ConfidenceStateIsValid, StateInfo.ConfidenceStateIsInvalid, StateInfo.ConfidenceStateIsStable, StateInfo.ConfidenceStateIsDrifting, StateInfo.StateCondition, StateInfo.NumberOfInsertedSamplesAfterEntrance, - (StateInfo.StateIsValid ? 4 : 0) + - (StateInfo.StateJustGotValid ? 2 : 0) + - (StateInfo.StateIsValidAfterReentrance ? 1 : 0)}; + (uint8_t)((StateInfo.StateIsValid ? 4 : 0) + + (StateInfo.StateJustGotValid ? 2 : 0) + + (StateInfo.StateIsValidAfterReentrance ? 1 : 0))}; return Result(Res); } return Result(); })); } // System State using SystemStateTuple = DeluxeTuple; template struct Handler_helper; template struct function_helper { static_assert(std::conjunction_v...>, "All types need to be identical"); static B function(A valA, As... valAs) { std::vector ar({valA, valAs...}); return func()(ar); } }; template struct Handler_helper<0, ret, functype, typeA, B...> { using handler = function_helper; }; template struct Handler_helper { using handler = typename Handler_helper, B...>::handler; }; template using Handler = typename Handler_helper::handler; // todo: state-detector durschleifen template struct function { ret operator()(A a) { // std::vector out; for (auto tmp1 : a) { // convert tuple to info struct out.push_back({}); (void)tmp1; LOG_INFO_STREAM << "new SignalStateTuple!\n"; } // feed state detector // return result return ret(); } }; using arr = std::vector>; template AgentHandle createSystemStateDetectorAgent( std::unique_ptr &C, const std::string &Name, std::shared_ptr> BrokenDelayFunction, std::shared_ptr> OkDelayFunction) { LOG_TRACE("Creating fixed SystemStateDetectorAgent"); using Input = SignalStateTuple; using Result = Optional; auto HandlerFunction = Handler, arr>, Input>::function; std::shared_ptr< SystemStateDetector> SysSD(new SystemStateDetector( std::numeric_limits::max(), NumOfSlaves, BrokenDelayFunction, OkDelayFunction)); return C->createAgent(Name, std::function(HandlerFunction)); } AgentHandle createSystemStateDetectorAgent( std::unique_ptr &C, const std::string &Name, size_t NumOfSlaves, std::shared_ptr> BrokenDelayFunction, std::shared_ptr> OkDelayFunction) { LOG_TRACE("Creating dynamic SystemStateDetectorAgent"); switch (NumOfSlaves) { // clang-format off case 2: return createSystemStateDetectorAgent< 2>(C, Name, BrokenDelayFunction, OkDelayFunction); case 3: return createSystemStateDetectorAgent< 3>(C, Name, BrokenDelayFunction, OkDelayFunction); case 4: return createSystemStateDetectorAgent< 4>(C, Name, BrokenDelayFunction, OkDelayFunction); case 5: return createSystemStateDetectorAgent< 5>(C, Name, BrokenDelayFunction, OkDelayFunction); case 6: return createSystemStateDetectorAgent< 6>(C, Name, BrokenDelayFunction, OkDelayFunction); case 7: return createSystemStateDetectorAgent< 7>(C, Name, BrokenDelayFunction, OkDelayFunction); case 8: return createSystemStateDetectorAgent< 8>(C, Name, BrokenDelayFunction, OkDelayFunction); case 9: return createSystemStateDetectorAgent< 9>(C, Name, BrokenDelayFunction, OkDelayFunction); case 10: return createSystemStateDetectorAgent<10>(C, Name, BrokenDelayFunction, OkDelayFunction); case 11: return createSystemStateDetectorAgent<11>(C, Name, BrokenDelayFunction, OkDelayFunction); case 12: return createSystemStateDetectorAgent<12>(C, Name, BrokenDelayFunction, OkDelayFunction); case 13: return createSystemStateDetectorAgent<13>(C, Name, BrokenDelayFunction, OkDelayFunction); case 14: return createSystemStateDetectorAgent<14>(C, Name, BrokenDelayFunction, OkDelayFunction); case 15: return createSystemStateDetectorAgent<15>(C, Name, BrokenDelayFunction, OkDelayFunction); case 16: return createSystemStateDetectorAgent<16>(C, Name, BrokenDelayFunction, OkDelayFunction); case 17: return createSystemStateDetectorAgent<17>(C, Name, BrokenDelayFunction, OkDelayFunction); case 18: return createSystemStateDetectorAgent<18>(C, Name, BrokenDelayFunction, OkDelayFunction); case 19: return createSystemStateDetectorAgent<19>(C, Name, BrokenDelayFunction, OkDelayFunction); case 20: return createSystemStateDetectorAgent<20>(C, Name, BrokenDelayFunction, OkDelayFunction); case 21: return createSystemStateDetectorAgent<21>(C, Name, BrokenDelayFunction, OkDelayFunction); case 22: return createSystemStateDetectorAgent<22>(C, Name, BrokenDelayFunction, OkDelayFunction); case 23: return createSystemStateDetectorAgent<23>(C, Name, BrokenDelayFunction, OkDelayFunction); case 24: return createSystemStateDetectorAgent<24>(C, Name, BrokenDelayFunction, OkDelayFunction); case 25: return createSystemStateDetectorAgent<25>(C, Name, BrokenDelayFunction, OkDelayFunction); case 1: default: return createSystemStateDetectorAgent<1>(C, Name, BrokenDelayFunction, OkDelayFunction); // clang-format on } } #endif // STATEHANDLERUTILS_H diff --git a/examples/CSVFiles/main.cpp b/examples/CSVFiles/main.cpp index 20df4cf..56ac98e 100644 --- a/examples/CSVFiles/main.cpp +++ b/examples/CSVFiles/main.cpp @@ -1,373 +1,373 @@ //===-- examples/CSVFiles/main.cpp ------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file examples/basic-system/basic-system.cpp /// /// \author Edwin Willegger (edwin.willegger@tuwien.ac.at) /// /// \date 2019 /// /// \brief A simple example on the basic \c rosa::csv, \c rosa::iterator and /// \c rosa::writer classes. Focus is on the tuple impementations. /// //===----------------------------------------------------------------------===// #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#include // includes for an complete example to read and write // with sensors and agents. #include "rosa/deluxe/DeluxeContext.hpp" #include "rosa/config/version.h" // includes to test the basic functionality // to read and write tuples. #include "rosa/support/csv/CSVReader.hpp" #include "rosa/support/csv/CSVWriter.hpp" #include "rosa/support/iterator/split_tuple_iterator.hpp" #include "rosa/support/writer/split_tuple_writer.hpp" /// the name of the example const std::string ExampleName = "csvfiles"; /// How many cycles of simulation to perform. const size_t NumberOfSimulationCycles = 10; /// Paths for the CSV files for simulation. /// input csv files const std::string csvPath = "../examples/CSVFiles/"; const std::string csvFileWithHeader = csvPath + "HR-New.csv"; const std::string csvFileNoHeader = csvPath + "HR.csv"; const std::string csvFileHeaderSemi = csvPath + "HR-New-Semicolon.csv"; /// output csv files const std::string csvFileWriteHea = csvPath + "csvwriter_noheader.csv"; const std::string csvFileWriteNoHeaSplit = csvPath + "csvSplitwriter_noheader.csv"; using namespace rosa; /// /// This function tests the basic CSVIterator capablities, and shows you /// how you could work with this class. /// void testtupleCSVReader(void) { // different streams to get the csv data out of the files // file contains header and valid data entries, delimter = ',' std::ifstream file_header_data(csvFileWithHeader); // file contains header and valid data entries, delimter = ',' std::ifstream file_header_data_2(csvFileWithHeader); // file contains header and valid data entries, delimter = ',' std::ifstream file_header_data_3(csvFileWithHeader); // file contains header and valid data entries, delimter = ',' std::ifstream file_header_data_4(csvFileWithHeader); // file contains header and valid data entries, delimter = ',' std::ifstream file_header_data_5(csvFileWithHeader); // file contains header and valid data entries, delimter = ',' std::ifstream file_header_data_6(csvFileWithHeader); // file contains no header an valid data entries, delimter = ',' std::ifstream file2(csvFileNoHeader); // file contains header and valid data entries, delimter = ';' std::ifstream file3(csvFileHeaderSemi); csv::CSVIterator it( file_header_data); - it.setDelimeter(','); + it.setDelimiter(','); it++; it++; // if you iterate over the end of file, the last values // of the file will remain in the data structure but no // error occurs. it++; it++; //------------------------------------------------------------------- // a possiblity to get the data out of the iterator std::tuple value = *it; // // Show the value of one iterator // LOG_INFO("Values are: "); LOG_INFO(std::get<0>(value)); LOG_INFO(std::get<1>(value)); //-------------------------------------------------------------------- // testing differnet parameters to the constructor // uncomment to see that it is not possible to iterate over an vector in the // tuple. // rosa::csv::CSVIterator> it2(file, 1); // try to skip a valid number of lines after the header csv::CSVIterator it2_0(file_header_data_2, 1); // try to skip a valid number of lines after the header, but you assume that // the file has no header // uncomment this line to crash the programm // csv::CSVIterator it2_1(file_header_data_3, // 0, csv::HeaderInformation::HasNoHeader); // try to skip a valid number of lines after the header, but you assume that // the file has no header // uncomment this line to crash the program // csv::CSVIterator it2_2(file_header_data_4, // 1, csv::HeaderInformation::HasNoHeader); // try to skip a valid number of lines of a file without header csv::CSVIterator it2_3( file2, 1, csv::HeaderInformation::HasNoHeader); // try to skip a valid number of lines after the header, but with different // delimeter csv::CSVIterator it2_4( file3, 2, csv::HeaderInformation::HasHeader, ';'); // if you skip more lines than valid, you generate an infinte loop // csv::CSVIterator it3(file_header_data_5, // 500); // if you don't need data from all columns just select the number of columns // you // need. You get the data back from the first column (index 0) to the fourth // column // all values from the fifth column are ignored. csv::CSVIterator it4(file_header_data_6); } /// /// This function tests the basic CSVTupleWriter capablities, and shows you /// how you could work with this class. /// void testtupleCSVWriter(void) { // // Create output writer with an file // std::ofstream file_header_out(csvFileWriteHea); csv::CSVTupleWriter wri(file_header_out); // // Create test tuples // std::tuple values(5, 8.3f, "hallo"); std::tuple values2(3, 8.3f, "end"); // // Create test header lines for the test tuples // std::array header{"zero column", "first column", "second column"}; std::array headerWrong{"zero column", "first column", "second column", "third column"}; std::array headerWrongShort{"zero column", "first column"}; // if you uncomment this line than it would be possible for you to write the // header into the stream // in the next line. // wri.write(values); wri.writeHeader(header); wri.write(values); wri.write(values); // it is not possible to write an additional header into the stream. wri.writeHeader(header); wri.write(values); wri << values; wri << values2; // uncomment this line to see, that you can't write a header with the too many // elements. // wri.writeHeader(headerWrong); // uncomment this line to see, that you can't write a header with the too few // elements. // wri.writeHeader(headerWrongShort); } /// /// This function tests the basic splitTupleIterator capablities, and shows you /// how you could work with this class, this class is used if you want to split /// a CSVIterator in separate parts. /// void testsplitTupleIterator(void) { // // Create deluxe context // std::unique_ptr C = deluxe::DeluxeContext::create(ExampleName); // // Create deluxe sensors. // LOG_INFO("Creating sensors."); // All sensors are created without defining a normal generator function, but // with the default value of the second argument. That, however, requires the // data type to be explicitly defined. This is good for simulation only. // Three different sensors were created, this is just a random number taken. AgentHandle Elem0Sensor = C->createSensor("Element1 Sensor"); AgentHandle Elem1Sensor = C->createSensor("Element2 Sensor"); AgentHandle Elem2Sensor = C->createSensor("Element3 Sensor"); // // Initialize deluxe context for simulation. // C->initializeSimulation(); // Type aliases for iterators using Iterator = rosa::csv::CSVIterator; using IteratorValue = std::tuple; static_assert( std::is_same::value, "Iterator must provide tuples"); // // Open CSV file and register the columns to the corresponding sensors. // std::ifstream TestCSV(csvFileWithHeader); // // Test data looks like: // Element1, Element2, Element3, Element4, Element5 -- is the header line // 3, 5, 8, 9.5, 17 -- first line of values // 100, -8, 30, 18.8, 29 -- other line of values // were also in the file // 5, 20, -100, -200.1, -30 -- if you have less number // of values than simulation rounds all values // -- beyond your last value // will be zero. // get element iterator ranges auto[Elem0Range, Elem1Range, Elem2Range] = iterator::splitTupleIterator(Iterator(TestCSV), Iterator()); // dissect a range into begin and end iterators by structred bindings auto[Elem0Begin, Elem0End] = Elem0Range; // deissect a range with functions auto Elem1Begin = iterator::begin(Elem1Range); auto Elem1End = iterator::end(Elem1Range); C->registerSensorValues(Elem0Sensor, std::move(Elem0Begin), Elem0End); C->registerSensorValues(Elem1Sensor, std::move(Elem1Begin), Elem1End); C->registerSensorValues(Elem2Sensor, std::move(iterator::begin(Elem2Range)), iterator::end(Elem2Range)); // // Simulate. // C->simulate(NumberOfSimulationCycles); } /// /// This function tests the basic splitTupleWriter capablities, and shows you /// how you could work with this class, this class is used if you want to split /// a CSVWriter in separate parts. /// // NOTE (Maxi): I had to add an "f" to some numbers to declare them as float, // otherwise: "C:\Users\maxgot\Source\SoC_RoSA\examples\CSVFiles\main.cpp:314: // warning: C4305: 'argument': truncation from 'double' to 'const float'" void testsplitTupleWriter(void) { // // Create output writer with an file // std::ofstream file_header_out(csvFileWriteNoHeaSplit); csv::CSVTupleWriter wri(file_header_out); // if you omit, the type definition in the template, than auto generated types // were used, // and they may not fit to the used CSVTupleWriter. wri << std::make_tuple(1000, 50.6f, "tuple_created"); auto[T0Writer, T1Writer, T2Writer] = writer::splitTupleWriter( std::move(wri), writer::IncompleteTuplePolicy::Ignore); // writing elements in sequential order into the writer classes, but you can // write the values into the writers in // a random order. T0Writer << (500); T1Writer << (3.0); T2Writer << "splitted writter"; T2Writer << "splitting is cool"; T0Writer << (-30); T1Writer << (-0.004f); // you can also write more often values into a writer and later into the other // writers // all data will be processed correctly into the right order. T0Writer << (1); T0Writer << (2); T1Writer << (-0.4f); T0Writer << (3); T2Writer << "again"; T0Writer << (4); T1Writer << (-0.1f); T1Writer << (-0.2f); T2Writer << "and"; T1Writer << (-0.3f); T2Writer << "splitting"; T2Writer << "once again"; // again writing data of one tuple entry to the different writers in a random // fashion. T1Writer << (-0.004f); T2Writer << "splitting is cool"; T0Writer << (-30); } int main(void) { LOG_INFO_STREAM << library_string() << " -- " << terminal::Color::Red << ExampleName << " example" << terminal::Color::Default << '\n'; // // Testing CSVWriter. // LOG_INFO("Testing CSVWriter CSVTupleItrator implementation: "); testtupleCSVWriter(); // // Testing CSVReader. // LOG_INFO("Testing CSVReader CSVTupleIterator implementation: "); testtupleCSVReader(); // // Testing SplitTupleIterator. // LOG_INFO("Testing SplitTupleIterator: "); testsplitTupleIterator(); // // Testing SplitTupleWriter. // LOG_INFO("Testing SplitTupleWriter: "); testsplitTupleWriter(); // // info that user knows programm has finished. // LOG_INFO("All tests finished."); return 0; } diff --git a/include/rosa/agent/SignalState.hpp b/include/rosa/agent/SignalState.hpp index a4b3cd8..0330201 100644 --- a/include/rosa/agent/SignalState.hpp +++ b/include/rosa/agent/SignalState.hpp @@ -1,469 +1,476 @@ //===-- 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/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"); + + /// TODO: describe + CONFDATATYPE ConfidenceOfMatchingState; + 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; }; /// \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: // For the convinience to write a shorter data type name using PartFuncReference = PartialFunction &; using StepFuncReference = StepFunction &; private: /// SignalStateInfo is a struct of SignalStateInformation that contains /// information about the current signal 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. 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 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; /// 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; //@benedikt: neu (passt das so?) CONFDATATYPE TempConfidenceMatching; CONFDATATYPE TempConfidenceMismatching; public: /// 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, SignalProperties SignalProperty, uint32_t SampleHistorySize, uint32_t DABSize, uint32_t DABHistorySize, PartFuncReference FuzzyFunctionSampleMatches, PartFuncReference FuzzyFunctionSampleMismatches, StepFuncReference FuzzyFunctionNumOfSamplesMatches, StepFuncReference FuzzyFunctionNumOfSamplesMismatches, PartFuncReference FuzzyFunctionSignalIsDrifting, PartFuncReference FuzzyFunctionSignalIsStable) noexcept : //@benedikt/@david: I don't know if i am allowed to initialize it like // that because the struct is a derivate of another struct SignalStateInfo{SignalStateID, StateConditions::UNKNOWN, false, false, false, 0, 0, 0, 0, 0, 0, SignalProperty, 0}, 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.StateIsValidAfterReentrance = false; } SignalStateInformation insertSample(INDATATYPE Sample) noexcept { + SignalStateInfo.NumberOfInsertedSamplesAfterEntrance++; + 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(); //@benedikt (das gehört dazu) 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 = 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. // // 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))); } //@benedikt (das gehört dazu) 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( 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; // 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))); } //@benedikt (das gehört dazu) 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(relativeDistance( Sample, HistorySample))); HighestConfidenceMismatching = fuzzyOR(HighestConfidenceMismatching, FuzzyFunctionSampleMismatches( relativeDistance( Sample, HistorySample))); } LowestConfidenceMatchingHistory.addEntry(LowestConfidenceMatching); HighestConfidenceMismatchingHistory.addEntry(HighestConfidenceMismatching); LowestConfidenceMatching = LowestConfidenceMatchingHistory.lowestEntry(); HighestConfidenceMismatching = HighestConfidenceMismatchingHistory.highestEntry(); SignalStateInfo.ConfidenceStateIsValid = fuzzyAND(LowestConfidenceMatching, FuzzyFunctionNumOfSamplesMatches(static_cast( SignalStateInfo.NumberOfInsertedSamplesAfterEntrance))); SignalStateInfo.ConfidenceStateIsInvalid = fuzzyOR(HighestConfidenceMismatching, FuzzyFunctionNumOfSamplesMismatches(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) { if (DABHistory.numberOfEntries() >= 2) { SignalStateInfo.ConfidenceStateIsStable = FuzzyFunctionSignalIsStable( relativeDistance( DABHistory[DABHistory.numberOfEntries() - 1], DABHistory[0])); SignalStateInfo.ConfidenceStateIsDrifting = FuzzyFunctionSignalIsDrifting( relativeDistance( DABHistory[DABHistory.numberOfEntries() - 1], DABHistory[0])); } else { // @benedikt: I do not know if this "initializing" is the best, but I // think it makes sense because we do not know if it is stable or // drifting. SignalStateInfo.ConfidenceStateIsStable = 0; SignalStateInfo.ConfidenceStateIsDrifting = 0; } //@benedikt: before it was "ConfidenceSignalIsStable >= // ConfidenceSignalIsDrifting" -> stable. However, I think like that it // makes // more sense. What do you mean? if (SignalStateInfo.ConfidenceStateIsStable > SignalStateInfo.ConfidenceStateIsDrifting) { SignalStateInfo.StateCondition = StateConditions::STABLE; } else if (SignalStateInfo.ConfidenceStateIsStable < SignalStateInfo.ConfidenceStateIsDrifting) { SignalStateInfo.StateCondition = StateConditions::DRIFTING; } else { SignalStateInfo.StateCondition = StateConditions::UNKNOWN; } } }; } // End namespace agent } // End namespace rosa #endif // ROSA_AGENT_SIGNALSTATE_HPP diff --git a/include/rosa/agent/State.hpp b/include/rosa/agent/State.hpp index 1e19ef5..d3568a3 100644 --- a/include/rosa/agent/State.hpp +++ b/include/rosa/agent/State.hpp @@ -1,90 +1,87 @@ //===-- rosa/agent/State.hpp ------------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/agent/State.hpp /// /// \author Maximilian Götzinger (maximilian.goetzinger@tuwien.ac.at) /// /// \date 2019 /// /// \brief Definition of *state* *functionality*. /// //===----------------------------------------------------------------------===// #ifndef ROSA_AGENT_STATE_HPP #define ROSA_AGENT_STATE_HPP #include "rosa/agent/Functionality.h" //#include "rosa/agent/FunctionAbstractions.hpp" //#include "rosa/agent/History.hpp" #include "rosa/support/debug.hpp" #include //#include namespace rosa { namespace agent { /// State conditions defining how the condition of a \c rosa::agent::State is /// saved in \c rosa::agent::StateInformation. enum StateConditions : uint8_t { UNKNOWN = 0, ///< The state is unknown STABLE = 1, ///< The state is stable DRIFTING = 2, ///< The state is drifting MALFUNCTIONING = 3 ///< Malfunction }; template struct StateInformation { // Make sure the actual type arguments are matching our expectations. STATIC_ASSERT((std::is_arithmetic::value), "confidence type is not to arithmetic"); /// The StateID stores the ID of the state. unsigned int StateID; /// The StateCondition shows the condition of a state (stable, drifting, or /// unknown) StateConditions StateCondition; /// The StateIsValid 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 StateIsValid; /// The StateJustGotValid shows whether a state got valid (toggled from /// invalid to valid) during the current inserted sample. bool StateJustGotValid; /// The StateIsValidAfterReentrance shows whether a state is valid after the /// variable changed back to it again. bool StateIsValidAfterReentrance; /// TODO: describe - CONFDATATYPE ConfidenceOfMatchingState; - CONFDATATYPE ConfidenceOfMismatchingState; - CONFDATATYPE ConfidenceStateIsValid; CONFDATATYPE ConfidenceStateIsInvalid; CONFDATATYPE ConfidenceStateIsStable; CONFDATATYPE ConfidenceStateIsDrifting; }; template class State : 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"); STATIC_ASSERT((std::is_arithmetic::value), "process type is not to arithmetic"); protected: }; } // End namespace agent } // End namespace rosa #endif // ROSA_AGENT_SIGNALSTATEDETECTOR_HPP diff --git a/include/rosa/agent/SystemState.hpp b/include/rosa/agent/SystemState.hpp index 9179139..07841e0 100644 --- a/include/rosa/agent/SystemState.hpp +++ b/include/rosa/agent/SystemState.hpp @@ -1,252 +1,272 @@ //===-- rosa/agent/SystemState.hpp ------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/agent/SystemState.hpp /// /// \author Maximilian Götzinger (maximilian.goetzinger@tuwien.ac.at) /// /// \date 2019 /// /// \brief Definition of *system state* *functionality*. /// //===----------------------------------------------------------------------===// #ifndef ROSA_AGENT_SYSTEMSTATE_HPP #define ROSA_AGENT_SYSTEMSTATE_HPP #include "rosa/agent/Functionality.h" #include "rosa/agent/SignalState.hpp" #include "rosa/agent/State.hpp" #include "rosa/support/debug.hpp" #include namespace rosa { namespace agent { enum class SystemStateRelation : uint8_t { STATEISMATCHING = 0, ///< The system state is matching ONLYINPUTISMATCHING = 1, ///< Only inputs of the system state are matching ONLYOUTPUTISMATCHING = 2, ///< Only outputs of the system state are matching STATEISMISMATCHING = 3 ///< The system state is mismatching }; /// TODO: write description template struct SystemStateInformation : StateInformation { /// TODO: describe - CONFDATATYPE ConfidenceStateIsFunctioning; - CONFDATATYPE ConfidenceStateIsMalfunctioning; + CONFDATATYPE ConfidenceOfInputsMatchingState; + CONFDATATYPE ConfidenceOfInputsMismatchingState; + CONFDATATYPE ConfidenceOfOutputsMatchingState; + CONFDATATYPE ConfidenceOfOutputsMismatchingState; + CONFDATATYPE ConfidenceSystemIsFunctioning; + CONFDATATYPE ConfidenceSystemIsMalfunctioning; CONFDATATYPE ConfidenceOfAllDecisions; }; // todo: do we need PROCDATATYPE? /// TODO TEXT template class SystemState : public State { // Make sure the actual type arguments are matching our expectations. STATIC_ASSERT(std::is_arithmetic::value, "input data type is not to arithmetic"); STATIC_ASSERT(std::is_arithmetic::value, "confidence abstraction type is not to arithmetic"); STATIC_ASSERT(std::is_arithmetic::value, "process data type is not to arithmetic"); private: /// SignalStateInfo is a struct of SignalStateInformation that contains /// information about the current signal state. SystemStateInformation SystemStateInfo; std::vector> SignalStateInfos; uint32_t NumberOfSignals; public: /// TODO: write description SystemState(uint32_t StateID, uint32_t NumberOfSignals) noexcept : SystemStateInfo{StateID, StateConditions::UNKNOWN, false, false, false, 0, 0, 0, 0, 0, 0, 0, 0, 0}, NumberOfSignals(NumberOfSignals) { //@benedikt: there is now possibility to not doing the resize within these //{}-brackets, right? SignalStateInfos.resize(NumberOfSignals); } /// Destroys \p this object. ~SystemState(void) = default; /// TODO: write description SystemStateInformation insertSignalStateInformation( const std::vector> _SignalStateInfos) noexcept { ASSERT(_SignalStateInfos.size() < NumberOfSignals); bool AllSignalsAreValid = true; bool AtLeastOneSignalJustGotValid = false; bool AllSignalsAreValidAfterReentrance = true; + bool AtLeastOneSignalIsUnknown = false; bool AllSignalsAreStable = true; - CONFDATATYPE CombinedConfidenceOfMatchingState = - _SignalStateInfos.front().ConfidenceOfMatchingState; - CONFDATATYPE CombinedConfidenceOfMismatchingState = - _SignalStateInfos.front().ConfidenceOfMismatchingState; - CONFDATATYPE CombinedConfidenceStateIsValid = - _SignalStateInfos.front().ConfidenceStateIsValid; - CONFDATATYPE CombinedConfidenceStateIsInvalid = - _SignalStateInfos.front().ConfidenceStateIsInvalid; - CONFDATATYPE CombinedConfidenceStateIsStable = - _SignalStateInfos.front().ConfidenceStateIsStable; - CONFDATATYPE CombinedConfidenceStateIsDrifting = - _SignalStateInfos.front().ConfidenceStateIsDrifting; + // TODO: change this + SystemStateInfo.ConfidenceOfInputsMatchingState = 1; + SystemStateInfo.ConfidenceOfInputsMismatchingState = 0; + SystemStateInfo.ConfidenceOfOutputsMatchingState = 1; + SystemStateInfo.ConfidenceOfOutputsMismatchingState = 0; + SystemStateInfo.ConfidenceStateIsValid = 1; + SystemStateInfo.ConfidenceStateIsInvalid = 0; + SystemStateInfo.ConfidenceStateIsStable = 1; + SystemStateInfo.ConfidenceStateIsDrifting = 0; std::size_t counter = 0; for (auto SSI : _SignalStateInfos) { if (!SSI.StateIsValid) AllSignalsAreValid = false; - if (SSI.StateJustGotValid) AtLeastOneSignalJustGotValid = true; - if (!SSI.StateIsValidAfterReentrance) AllSignalsAreValidAfterReentrance = false; + if (SSI.StateCondition == StateConditions::UNKNOWN) + AtLeastOneSignalIsUnknown = true; if (SSI.StateCondition == StateConditions::DRIFTING) AllSignalsAreStable = false; - //@benedikt: instead of the initializing above and the and/or with itself, - // I could make here an if (counter == 0) - CombinedConfidenceOfMatchingState = fuzzyAND( - CombinedConfidenceOfMatchingState, SSI.ConfidenceOfMatchingState); - CombinedConfidenceOfMismatchingState = - fuzzyOR(CombinedConfidenceOfMismatchingState, - SSI.ConfidenceOfMismatchingState); - CombinedConfidenceStateIsValid = - fuzzyAND(CombinedConfidenceStateIsValid, SSI.ConfidenceStateIsValid); - CombinedConfidenceStateIsInvalid = fuzzyOR( - CombinedConfidenceStateIsInvalid, SSI.ConfidenceStateIsInvalid); - CombinedConfidenceStateIsStable = fuzzyAND( - CombinedConfidenceStateIsStable, SSI.ConfidenceStateIsStable); - CombinedConfidenceStateIsDrifting = fuzzyOR( - CombinedConfidenceStateIsDrifting, SSI.ConfidenceStateIsDrifting); + if (SSI.SignalProperty == SignalProperties::INPUT) { + SystemStateInfo.ConfidenceOfInputsMatchingState = + fuzzyAND(SystemStateInfo.ConfidenceOfInputsMatchingState, + SSI.ConfidenceOfMatchingState); + SystemStateInfo.ConfidenceOfInputsMismatchingState = + fuzzyOR(SystemStateInfo.ConfidenceOfInputsMismatchingState, + SSI.ConfidenceOfMismatchingState); + } else { + SystemStateInfo.ConfidenceOfOutputsMatchingState = + fuzzyAND(SystemStateInfo.ConfidenceOfOutputsMatchingState, + SSI.ConfidenceOfMatchingState); + SystemStateInfo.ConfidenceOfOutputsMismatchingState = + fuzzyOR(SystemStateInfo.ConfidenceOfOutputsMismatchingState, + SSI.ConfidenceOfMismatchingState); + } + + SystemStateInfo.ConfidenceStateIsValid = fuzzyAND( + SystemStateInfo.ConfidenceStateIsValid, SSI.ConfidenceStateIsValid); + SystemStateInfo.ConfidenceStateIsInvalid = + fuzzyOR(SystemStateInfo.ConfidenceStateIsInvalid, + SSI.ConfidenceStateIsInvalid); + SystemStateInfo.ConfidenceStateIsStable = fuzzyAND( + SystemStateInfo.ConfidenceStateIsStable, SSI.ConfidenceStateIsStable); + SystemStateInfo.ConfidenceStateIsDrifting = + fuzzyOR(SystemStateInfo.ConfidenceStateIsDrifting, + SSI.ConfidenceStateIsDrifting); this->SignalStateInfos.at(counter) = SSI; counter++; } SystemStateInfo.StateIsValid = AllSignalsAreValid; SystemStateInfo.StateJustGotValid = AllSignalsAreValid && AtLeastOneSignalJustGotValid; SystemStateInfo.StateIsValidAfterReentrance = AllSignalsAreValidAfterReentrance; + if (AtLeastOneSignalIsUnknown) + SystemStateInfo.StateCondition = StateConditions::UNKNOWN; + else if (AllSignalsAreStable) + SystemStateInfo.StateCondition = StateConditions::STABLE; + else + SystemStateInfo.StateCondition = StateConditions::DRIFTING; + return SystemStateInfo; } /// TODO: write description // TODO (future): think about saving the state information in a history SystemStateRelation compareSignalStateInformation( const std::vector> _SignalStateInfos) noexcept { bool inputsAreMatching = true; bool outputsAreMatching = true; std::size_t counter = 0; for (auto SSI : _SignalStateInfos) { if (this->SignalStateInfos.at(counter).StateID != SSI.StateID) { if (SSI.SignalProperty == SignalProperties::INPUT) inputsAreMatching = false; else // SignalProperties::OUTPUT outputsAreMatching = false; } counter++; } if (inputsAreMatching && outputsAreMatching) return SystemStateRelation::STATEISMATCHING; else if (inputsAreMatching && !outputsAreMatching) return SystemStateRelation::ONLYINPUTISMATCHING; else if (!inputsAreMatching && outputsAreMatching) return SystemStateRelation::ONLYOUTPUTISMATCHING; else return SystemStateRelation::STATEISMISMATCHING; } #ifdef ADDITIONAL_FUNCTIONS /// TODO: write description template void insertSignalStateInformation( const std::array, size> &Data) noexcept { ASSERT(size <= NumberOfSignals); std::size_t counter = 0; for (auto tmp : Data) { Signals.at(counter) = tmp; counter++; } } /// TODO: write description template std::enable_if_t>...>, void> insertSignalStateInformation(Types... Data) { // TODO (future): think about saving the state information in a history insertSignalStateInfos( std::array, sizeof...(Data)>( {Data...})); } // returns true if they are identical /// TODO: write description template bool compareSignalStateInformation( const std::array, size> &Data) noexcept { // TODO (future): think about saving the state information in a history std::size_t counter = 0; for (auto tmp : Data) { if (Signals.at(counter) != tmp) return false; counter++; } return true; } // checks only the given amount /// TODO: write description template std::enable_if_t>...>, bool> compareSignalStateInformation(Types... Data) { return compareSignalStateInfos( std::array, sizeof...(Data)>( {Data...})); } #endif /// Gives information about the current signal state. /// /// \return a struct SignalStateInformation that contains information about /// the current signal state. SystemStateInformation systemStateInformation(void) noexcept { return SystemStateInfo; } }; } // End namespace agent } // End namespace rosa #endif // ROSA_AGENT_SYSTEMSTATE_HPP diff --git a/include/rosa/agent/SystemStateDetector.hpp b/include/rosa/agent/SystemStateDetector.hpp index bcff7b4..14139fd 100644 --- a/include/rosa/agent/SystemStateDetector.hpp +++ b/include/rosa/agent/SystemStateDetector.hpp @@ -1,222 +1,235 @@ //===-- 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/SignalState.hpp" #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. -// TODO: think about shifting this in SystemStateDetector and make a -// StateCondition with only stable, drifting, unknown -enum class SystemStateCondition : uint8_t { - STABLE = 0, ///< The system state is stable - DRIFTING = 1, ///< The system state is drifting - MALFUNCTIONING = 2, ///< The system state is malfunctioning - UNKNOWN = 3 ///< The system state is unknown -}; -*/ - /// TODO: write description template class SystemStateDetector : public StateDetector { using StateDetector = StateDetector; using PartFuncPointer = typename StateDetector::PartFuncPointer; private: // For the convinience to write a shorter data type name using SystemStatePtr = std::shared_ptr>; /// TODO: description uint32_t NumberOfSignals; /// 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; /// TODO: description unsigned int TimeOfDisparity; - /// 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; + PartFuncPointer FuzzyFunctionTimeSystemFunctioning; + + /// 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 FuzzyFunctionTimeSystemMalfunctioning; public: // todo zwei parameter für variablen anzahl /// TODO: write description SystemStateDetector( uint32_t MaximumNumberOfSystemStates, uint32_t NumberOfSignals, - PartFuncPointer FuzzyFunctionDelayTimeToGetBroken, - PartFuncPointer FuzzyFunctionDelayTimeToBeWorking) noexcept + PartFuncPointer FuzzyFunctionTimeSystemMalfunctioning, + PartFuncPointer FuzzyFunctionTimeSystemFunctioning) noexcept : NumberOfSignals(NumberOfSignals), CurrentSystemState(nullptr), DetectedSystemStates(MaximumNumberOfSystemStates), TimeOfDisparity(0), - FuzzyFunctionDelayTimeToGetBroken(FuzzyFunctionDelayTimeToGetBroken), - FuzzyFunctionDelayTimeToBeWorking(FuzzyFunctionDelayTimeToBeWorking) { + FuzzyFunctionTimeSystemMalfunctioning( + FuzzyFunctionTimeSystemMalfunctioning), + FuzzyFunctionTimeSystemFunctioning(FuzzyFunctionTimeSystemFunctioning) { //@Benedikt: if I write "NextStateID(1), StateHasChanged(false)" before the //{}-brackets, the compiler tells me: "SystemStateDetector.hpp:72:9: error: // member initializer 'NextStateID'/'StateHasChanged' does not name a // non-static data member or base class" this->NextStateID = 1; this->StateHasChanged = false; } /// Destroys \p this object. ~SystemStateDetector(void) = default; /// TODO: write description SystemStateInformation detectSystemState(std::vector> SignalStateInfos) noexcept { SystemStateInformation SystemStateInfo; if (!CurrentSystemState) { ASSERT(DetectedSystemStates.empty()); SystemStatePtr S = createNewSystemState(); CurrentSystemState = S; SystemStateInfo = CurrentSystemState->insertSignalStateInformation(SignalStateInfos); } else { SystemStateRelation SysStateRel = CurrentSystemState->compareSignalStateInformation(SignalStateInfos); if (SysStateRel == SystemStateRelation::STATEISMATCHING) { TimeOfDisparity = 0; SystemStateInfo = CurrentSystemState->insertSignalStateInformation(SignalStateInfos); } else { // ONLYINPUTISMATCHING, ONLYOUTPUTISMATCHING, STATEISMISMATCHING if (!CurrentSystemState->systemStateInformation().StateIsValid) DetectedSystemStates.deleteEntry(CurrentSystemState); CurrentSystemState = nullptr; SystemStatePtr potentialSystemState = nullptr; // search all saved system states for (auto &SavedSystemState : DetectedSystemStates) { SysStateRel = SavedSystemState->compareSignalStateInformation(SignalStateInfos); if (SysStateRel == SystemStateRelation::STATEISMATCHING) { CurrentSystemState = SavedSystemState; break; } else if (SysStateRel == SystemStateRelation::ONLYINPUTISMATCHING || SysStateRel == SystemStateRelation::ONLYOUTPUTISMATCHING) { + // TODO: choose best matching potentialSystemState = SavedSystemState; } } // actions depending whether state is matchin fully or only half if (CurrentSystemState) { TimeOfDisparity = 0; SystemStateInfo = CurrentSystemState->insertSignalStateInformation( SignalStateInfos); } else if (potentialSystemState) { TimeOfDisparity++; CurrentSystemState = potentialSystemState; SystemStateInfo = CurrentSystemState->systemStateInformation(); } else { SystemStatePtr S = createNewSystemState(); TimeOfDisparity = 0; CurrentSystemState = S; SystemStateInfo = CurrentSystemState->insertSignalStateInformation( SignalStateInfos); } } } // TODO: is this right? if i don't insert if broke, it will never be valid?! // right? - if (!SystemStateInfo.StateIsValid || - !SystemStateInfo.StateIsValidAfterReentrance) { + if (!SystemStateInfo.StateIsValidAfterReentrance) { TimeOfDisparity = 0; } // TODO: maybe make reference instead of pointer - CONFDATATYPE ConfidenceSystemIsMalfunctioning = - FuzzyFunctionDelayTimeToGetBroken->operator()( + SystemStateInfo.ConfidenceSystemIsFunctioning = + (*FuzzyFunctionTimeSystemFunctioning)( static_cast(TimeOfDisparity)); - CONFDATATYPE ConfidenceSystemIsFunctioning = - FuzzyFunctionDelayTimeToBeWorking->operator()( + SystemStateInfo.ConfidenceSystemIsMalfunctioning = + (*FuzzyFunctionTimeSystemMalfunctioning)( static_cast(TimeOfDisparity)); - if (ConfidenceSystemIsMalfunctioning > ConfidenceSystemIsFunctioning) + if (SystemStateInfo.ConfidenceSystemIsMalfunctioning > + SystemStateInfo.ConfidenceSystemIsFunctioning) SystemStateInfo.StateCondition = StateConditions::MALFUNCTIONING; - // TODO: calculate overall confidence + if (SystemStateInfo.StateCondition == StateConditions::UNKNOWN) + // TODO: think about a Confidence calculation when system state is unkown + SystemStateInfo.ConfidenceOfAllDecisions = 0; + else if (SystemStateInfo.StateCondition == StateConditions::STABLE) + SystemStateInfo.ConfidenceOfAllDecisions = fuzzyAND( + fuzzyOR( + fuzzyAND(SystemStateInfo.ConfidenceOfInputsMatchingState, + SystemStateInfo.ConfidenceOfOutputsMatchingState), + fuzzyAND(SystemStateInfo.ConfidenceOfInputsMismatchingState, + SystemStateInfo.ConfidenceOfOutputsMismatchingState)), + SystemStateInfo.ConfidenceSystemIsFunctioning, + SystemStateInfo.ConfidenceStateIsStable, + SystemStateInfo.ConfidenceStateIsValid); + else if (SystemStateInfo.StateCondition == StateConditions::DRIFTING) + SystemStateInfo.ConfidenceOfAllDecisions = + fuzzyAND(SystemStateInfo.ConfidenceOfInputsMatchingState, + SystemStateInfo.ConfidenceOfOutputsMatchingState, + SystemStateInfo.ConfidenceStateIsDrifting, + SystemStateInfo.ConfidenceStateIsValid); + else if (SystemStateInfo.StateCondition == StateConditions::MALFUNCTIONING) + SystemStateInfo.ConfidenceOfAllDecisions = + fuzzyAND(SystemStateInfo.ConfidenceOfInputsMismatchingState, + SystemStateInfo.ConfidenceOfOutputsMismatchingState, + SystemStateInfo.ConfidenceSystemIsMalfunctioning, + SystemStateInfo.ConfidenceStateIsValid); if (SystemStateInfo.StateJustGotValid) { this->NextStateID++; } return SystemStateInfo; } private: /// Creates a new system state and adds it to the system 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. SystemStatePtr createNewSystemState(void) noexcept { SystemStatePtr S(new SystemState( this->NextStateID, this->NumberOfSignals)); DetectedSystemStates.addEntry(S); return S; } }; } // End namespace agent } // End namespace rosa #endif // ROSA_AGENT_SYSTEMSTATEDETECTOR_HPP