diff --git a/apps/ccam/ccam.cpp b/apps/ccam/ccam.cpp index 89ca27f..7f20eb6 100644 --- a/apps/ccam/ccam.cpp +++ b/apps/ccam/ccam.cpp @@ -1,435 +1,452 @@ //===-- apps/ccam/ccam.cpp --------------------------------------*- C++ -*-===// // // The RoSA Framework -- Application CCAM // // Distributed under the terms and conditions of the Boost Software /// License 1.0. // See accompanying file LICENSE. // // If you did not receive a copy of the license file, see // http://www.boost.org/LICENSE_1_0.txt. // //===----------------------------------------------------------------------===// /// /// \file apps/ccam/ccam.cpp /// /// \author Maximilian Goetzinger (maximilian.goetzinger@tuwien.ac.at) /// \author Benedikt Tutzer (benedikt.tutzer@tuwien.ac.at) /// /// \date 2019 /// /// \brief The application CCAM implements the case study from the paper: /// M. Goetzinger, N. TaheriNejad, H. A. Kholerdi, A. Jantsch, E. Willegger, /// T. Glatzl, A.M. Rahmani, T.Sauter, P. Liljeberg: Model - Free Condition /// Monitoring with Confidence /// /// \todo Clean up source files of this app: add standard RoSA header comment /// for own files and do something with 3rd party files... //===----------------------------------------------------------------------===// #include "rosa/agent/Abstraction.hpp" #include "rosa/agent/Confidence.hpp" #include "rosa/agent/FunctionAbstractions.hpp" #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 "rosa/deluxe/DeluxeTuple.hpp" #include #include #include #include #include "configuration.h" #include "statehandlerutils.h" using namespace rosa; using namespace rosa::agent; using namespace rosa::deluxe; using namespace rosa::terminal; const std::string AppName = "CCAM"; int main(int argc, char **argv) { LOG_INFO_STREAM << '\n' << library_string() << " -- " << Color::Red << AppName << "app" << Color::Default << '\n'; // ONLYFORTEST // std::cout << "Starting?" << std::endl; // getchar(); // TSETROFYLNO // // Read the filepath of the config file of the observed system. The filepath // is in the first argument passed to the application. Fuzzy functions etc. // are described in this file. // if (argc < 2) { LOG_ERROR("Specify config File!\nUsage:\n\tccam config.json"); return 1; } std::string ConfigPath = argv[1]; // // Load config file and read in all parameters. Fuzzy functions etc. are // described in this file. // if (!readConfigFile(ConfigPath)) { LOG_ERROR_STREAM << "Could not read config from \"" << ConfigPath << "\"\n"; return 2; } // ONLYFORTEST // Maxi: Do we need the following line? I outcommented it because I think it // is unnecessary. // std::string InputFilePath, OutputFilePath; // TSETROFYLNO // // Create a CCAM context. // LOG_INFO("Creating Context"); std::unique_ptr ContextCCAM = DeluxeContext::create(AppName); // // Create following function. // ____________ // / // / // __________/ // std::shared_ptr> BrokenDelayFunction( new PartialFunction( {{{0, AppConfig.BrokenCounter}, std::make_shared>( 0, 0.f, AppConfig.BrokenCounter, 1.f)}, {{AppConfig.BrokenCounter, std::numeric_limits::max()}, std::make_shared>(1.f, 0.f)}}, 0.f)); // // Create following function. // ____________ // \ // \ // \__________ // std::shared_ptr> OkDelayFunction( new PartialFunction( {{{0, AppConfig.BrokenCounter}, std::make_shared>( 0, 1.f, AppConfig.BrokenCounter, 0.f)}, {{AppConfig.BrokenCounter, std::numeric_limits::max()}, std::make_shared>(0.f, 0.f)}}, 1.f)); // // Create a DeluxeAgent with SystemStateDetector functionality. // LOG_INFO("Create SystemStateDetector agent."); AgentHandle SystemStateDetectorAgent = createSystemStateDetectorAgent( ContextCCAM, "SystemStateDetector", AppConfig.SignalConfigurations.size(), BrokenDelayFunction, OkDelayFunction); // // Set policy of SystemStateDetectorAgent that it wait for all // SignalStateDetectorAgents // std::set pos; for (size_t i = 0; i < AppConfig.SignalConfigurations.size(); ++i) pos.insert(pos.end(), i); ContextCCAM->setExecutionPolicy(SystemStateDetectorAgent, DeluxeExecutionPolicy::awaitAll(pos)); // // Create Vectors for all sensors, all signal related fuzzy functions, all // signal state detectors, all signal state agents, and all input data files. // // @Benedikt: why do we use "std::set" above (positions for master // agent and here "std::vector"? // LOG_INFO("Creating sensors, SignalStateDetector functionalities and their " "Abstractions."); std::vector Sensors; std::vector>> SampleMatchesFunctions; std::vector>> SampleMismatchesFunctions; std::vector>> SignalIsStableFunctions; std::vector>> SignalIsDriftingFunctions; std::vector>> NumOfSamplesMatchFunctions; std::vector>> NumOfSamplesMismatchFunctions; + std::vector>> + NumOfSamplesValidFunctions; + std::vector>> + NumOfSamplesInvalidFunctions; std::vector>> SignalStateDetectors; std::vector SignalStateDetectorAgents; std::vector DataFiles; // // Go through all signal state configurations (number of signals), and create // functionalities for SignalStateDetector. // for (auto SignalConfiguration : AppConfig.SignalConfigurations) { // // Create deluxe sensors. // Sensors.emplace_back( ContextCCAM->createSensor(SignalConfiguration.Name + "_Sensor")); // // Create following function(s). // ____________ // / \ // / \ // __________/ \__________ // // SampleMatchesFunctions.emplace_back(new PartialFunction( { {{-SignalConfiguration.OuterBound, -SignalConfiguration.InnerBound}, std::make_shared>( -SignalConfiguration.OuterBound, 0.f, -SignalConfiguration.InnerBound, 1.f)}, {{-SignalConfiguration.InnerBound, SignalConfiguration.InnerBound}, std::make_shared>(1.f, 0.f)}, {{SignalConfiguration.InnerBound, SignalConfiguration.OuterBound}, std::make_shared>( SignalConfiguration.InnerBound, 1.f, SignalConfiguration.OuterBound, 0.f)}, }, 0)); // // Create following function(s). // ____________ ____________ // \ / // \ / // \__________/ // // SampleMismatchesFunctions.emplace_back(new PartialFunction( { {{-SignalConfiguration.OuterBound, -SignalConfiguration.InnerBound}, std::make_shared>( -SignalConfiguration.OuterBound, 1.f, -SignalConfiguration.InnerBound, 0.f)}, {{-SignalConfiguration.InnerBound, SignalConfiguration.InnerBound}, std::make_shared>(0.f, 0.f)}, {{SignalConfiguration.InnerBound, SignalConfiguration.OuterBound}, std::make_shared>( SignalConfiguration.InnerBound, 0.f, SignalConfiguration.OuterBound, 1.f)}, }, 1)); // // Create following function(s). // ____________ // / \ // / \ // __________/ \__________ // // SignalIsStableFunctions.emplace_back(new PartialFunction( { {{-SignalConfiguration.OuterBoundDrift, -SignalConfiguration.InnerBoundDrift}, std::make_shared>( -SignalConfiguration.OuterBoundDrift, 0.f, -SignalConfiguration.InnerBoundDrift, 1.f)}, {{-SignalConfiguration.InnerBoundDrift, SignalConfiguration.InnerBoundDrift}, std::make_shared>(1.f, 0.f)}, {{SignalConfiguration.InnerBoundDrift, SignalConfiguration.OuterBoundDrift}, std::make_shared>( SignalConfiguration.InnerBoundDrift, 1.f, SignalConfiguration.OuterBoundDrift, 0.f)}, }, 0)); // // Create following function(s). // ____________ ____________ // \ / // \ / // \__________/ // // SignalIsDriftingFunctions.emplace_back(new PartialFunction( { {{-SignalConfiguration.OuterBoundDrift, -SignalConfiguration.InnerBoundDrift}, std::make_shared>( -SignalConfiguration.OuterBoundDrift, 1.f, -SignalConfiguration.InnerBoundDrift, 0.f)}, {{-SignalConfiguration.InnerBoundDrift, SignalConfiguration.InnerBoundDrift}, std::make_shared>(0.f, 0.f)}, {{SignalConfiguration.InnerBoundDrift, SignalConfiguration.OuterBoundDrift}, std::make_shared>( SignalConfiguration.InnerBoundDrift, 0.f, SignalConfiguration.OuterBoundDrift, 1.f)}, }, 1)); // // // // // // NumOfSamplesMatchFunctions.emplace_back(new StepFunction( 1.0f / SignalConfiguration.SampleHistorySize, StepDirection::StepUp)); NumOfSamplesMismatchFunctions.emplace_back(new StepFunction( 1.0f / SignalConfiguration.SampleHistorySize, StepDirection::StepDown)); + // + // + // + // + // + NumOfSamplesValidFunctions.emplace_back(new StepFunction( + 1.0f / SignalConfiguration.SampleHistorySize, StepDirection::StepUp)); + + NumOfSamplesInvalidFunctions.emplace_back(new StepFunction( + 1.0f / SignalConfiguration.SampleHistorySize, StepDirection::StepDown)); + // // Create SignalStateDetector functionality // SignalStateDetectors.emplace_back( new SignalStateDetector( SignalConfiguration.Output ? SignalProperties::OUTPUT : SignalProperties::INPUT, std::numeric_limits::max(), SampleMatchesFunctions.back(), SampleMismatchesFunctions.back(), NumOfSamplesMatchFunctions.back(), NumOfSamplesMismatchFunctions.back(), + NumOfSamplesValidFunctions.back(), + NumOfSamplesInvalidFunctions.back(), SignalIsDriftingFunctions.back(), SignalIsStableFunctions.back(), SignalConfiguration.SampleHistorySize, SignalConfiguration.DABSize, SignalConfiguration.DABHistorySize)); // // Create low-level deluxe agents // SignalStateDetectorAgents.push_back(createSignalStateDetectorAgent( ContextCCAM, SignalConfiguration.Name, SignalStateDetectors.back())); ContextCCAM->setExecutionPolicy( SignalStateDetectorAgents.back(), DeluxeExecutionPolicy::decimation(AppConfig.DownsamplingRate)); // // Connect sensors to low-level agents. // LOG_INFO("Connect sensors to their corresponding low-level agents."); ContextCCAM->connectSensor( SignalStateDetectorAgents.back(), 0, Sensors.back(), SignalConfiguration.Name + "_Sensor ->" + SignalConfiguration.Name + "_SignalStateDetector_Agent-Channel"); ContextCCAM->connectAgents( SystemStateDetectorAgent, SignalStateDetectors.size() - 1, SignalStateDetectorAgents.back(), SignalConfiguration.Name + "_SignalStateDetector_Agent->SystemStateDetector_Agent_Channel"); } // // For simulation output, create a logger agent writing the output of the // high-level agent into a CSV file. // LOG_INFO("Create a logger agent."); // Create CSV writer. std::ofstream OutputCSV(AppConfig.OutputFilePath); for (auto SignalConfiguration : AppConfig.SignalConfigurations) { OutputCSV << SignalConfiguration.Name + ","; } OutputCSV << "StateID,"; OutputCSV << "Confidence State Valid,"; OutputCSV << "Confidence State Invalid,"; OutputCSV << "Confidence Inputs Matching,"; OutputCSV << "Confidence Outputs Matching,"; OutputCSV << "Confidence Inputs Mismatching,"; OutputCSV << "Confidence Outputs Mismatching,"; OutputCSV << "State Condition,"; OutputCSV << "Confidence System Functioning,"; OutputCSV << "Confidence System Malfunctioning,"; OutputCSV << "Overall Confidence,"; OutputCSV << "\n"; // The agent writes each new input value into a CSV file and produces // nothing. using Input = std::pair; using Result = Optional>; using Handler = std::function; std::string Name = "Logger Agent"; AgentHandle LoggerAgent = ContextCCAM->createAgent( "Logger Agent", Handler([&OutputCSV](Input I) -> Result { const SystemStateTuple &T = I.first; OutputCSV << std::get<0>( static_cast &>(T)) << std::endl; return Result(); })); // // Connect the high-level agent to the logger agent. // LOG_INFO("Connect the high-level agent to the logger agent."); ContextCCAM->connectAgents(LoggerAgent, 0, SystemStateDetectorAgent, "SystemStateDetector Channel"); // // Only log if the SystemStateDetector actually ran // ContextCCAM->setExecutionPolicy(LoggerAgent, DeluxeExecutionPolicy::awaitAll({0})); // // Do simulation. // LOG_INFO("Setting up and performing simulation."); // // Initialize deluxe context for simulation. // ContextCCAM->initializeSimulation(); // // Open CSV files and register them for their corresponding sensors. // // Make sure DataFiles will not change capacity while adding elements to it. // Changing capacity moves elements away, which invalidates references // captured by CSVIterator. DataFiles.reserve(AppConfig.SignalConfigurations.size()); uint32_t i = 0; for (auto SignalConfiguration : AppConfig.SignalConfigurations) { DataFiles.emplace_back(SignalConfiguration.InputPath); if (!DataFiles.at(i)) { LOG_ERROR_STREAM << "Cannot open Input File \"" << SignalConfiguration.InputPath << "\" for Signal \"" << SignalConfiguration.Name << "\"" << std::endl; return 3; } ContextCCAM->registerSensorValues(Sensors.at(i), csv::CSVIterator(DataFiles.at(i)), csv::CSVIterator()); i++; } // // Start simulation. // ContextCCAM->simulate(AppConfig.NumberOfSimulationCycles); return 0; } diff --git a/apps/ccam/sample_data/20180529_BrokenSystem/_out.xlsx b/apps/ccam/sample_data/20180529_BrokenSystem/_out.xlsx new file mode 100644 index 0000000..bdbebd9 Binary files /dev/null and b/apps/ccam/sample_data/20180529_BrokenSystem/_out.xlsx differ diff --git a/apps/ccam/sample_data/20180529_Drift/_out.xlsx b/apps/ccam/sample_data/20180529_Drift/_out.xlsx new file mode 100644 index 0000000..43db520 Binary files /dev/null and b/apps/ccam/sample_data/20180529_Drift/_out.xlsx differ diff --git a/apps/ccam/sample_data/20180529_NormalModeOneChange/_out.xlsx b/apps/ccam/sample_data/20180529_NormalModeOneChange/_out.xlsx new file mode 100644 index 0000000..60bdb36 Binary files /dev/null and b/apps/ccam/sample_data/20180529_NormalModeOneChange/_out.xlsx differ diff --git a/apps/ccam/sample_data/20180529_NormalModeOneChange/config.json b/apps/ccam/sample_data/20180529_NormalModeOneChange/config.json index 375539e..d848dc7 100644 --- a/apps/ccam/sample_data/20180529_NormalModeOneChange/config.json +++ b/apps/ccam/sample_data/20180529_NormalModeOneChange/config.json @@ -1,93 +1,93 @@ { "OutputFilePath" : "out.csv", "BrokenCounter" : 20, "NumberOfSimulationCycles" : 20000, "DownsamplingRate" : 50, "SignalConfigurations" : [ { - "Name" : "Test", - "InputPath" : "test.csv", + "Name" : "Voltage", + "InputPath" : "Voltage.csv", "Output" : false, "InnerBound" : 0.01, "OuterBound" : 0.14, "InnerBoundDrift" : 0.10, "OuterBoundDrift" : 0.30, "SampleHistorySize" : 10, "DABSize" : 10, "DABHistorySize" : 5 }, { "Name" : "Temp1", "InputPath" : "Temp1.csv", "Output" : true, "InnerBound" : 0.01, "OuterBound" : 0.14, "InnerBoundDrift" : 0.10, "OuterBoundDrift" : 0.30, "SampleHistorySize" : 10, "DABSize" : 10, "DABHistorySize" : 5 }, { "Name" : "Temp2", "InputPath" : "Temp2.csv", "Output" : true, "InnerBound" : 0.01, "OuterBound" : 0.14, "InnerBoundDrift" : 0.10, "OuterBoundDrift" : 0.30, "SampleHistorySize" : 10, "DABSize" : 10, "DABHistorySize" : 5 }, { "Name" : "SharkyS", "InputPath" : "SharkyS.csv", "Output" : true, "InnerBound" : 0.01, "OuterBound" : 0.14, "InnerBoundDrift" : 0.10, "OuterBoundDrift" : 0.30, "SampleHistorySize" : 10, "DABSize" : 10, "DABHistorySize" : 5 }, { "Name" : "SharkyB", "InputPath" : "SharkyB.csv", "Output" : true, "InnerBound" : 0.01, "OuterBound" : 0.14, "InnerBoundDrift" : 0.10, "OuterBoundDrift" : 0.30, "SampleHistorySize" : 10, "DABSize" : 10, "DABHistorySize" : 5 }, { "Name" : "Dyna", "InputPath" : "Dyna.csv", "Output" : true, "InnerBound" : 0.01, "OuterBound" : 0.14, "InnerBoundDrift" : 0.10, "OuterBoundDrift" : 0.30, "SampleHistorySize" : 10, "DABSize" : 10, "DABHistorySize" : 5 }, { "Name" : "Riels", "InputPath" : "Riels.csv", "Output" : true, "InnerBound" : 0.01, "OuterBound" : 0.14, "InnerBoundDrift" : 0.10, "OuterBoundDrift" : 0.30, "SampleHistorySize" : 10, "DABSize" : 10, "DABHistorySize" : 5 } ] } diff --git a/apps/ccam/sample_data/20180529_NormalModeSeveralChanges/_out.xlsx b/apps/ccam/sample_data/20180529_NormalModeSeveralChanges/_out.xlsx new file mode 100644 index 0000000..d3f305f Binary files /dev/null and b/apps/ccam/sample_data/20180529_NormalModeSeveralChanges/_out.xlsx differ diff --git a/apps/ccam/sample_data/20180529_NormalModeUnchanged/_out.xlsx b/apps/ccam/sample_data/20180529_NormalModeUnchanged/_out.xlsx new file mode 100644 index 0000000..9d4db81 Binary files /dev/null and b/apps/ccam/sample_data/20180529_NormalModeUnchanged/_out.xlsx differ diff --git a/apps/ccam/sample_data/20180529_NormalTwoTimesSameState/_out.xlsx b/apps/ccam/sample_data/20180529_NormalTwoTimesSameState/_out.xlsx new file mode 100644 index 0000000..9b00ca5 Binary files /dev/null and b/apps/ccam/sample_data/20180529_NormalTwoTimesSameState/_out.xlsx differ diff --git a/apps/ccam/statehandlerutils.h b/apps/ccam/statehandlerutils.h index 675c9aa..ab627e6 100644 --- a/apps/ccam/statehandlerutils.h +++ b/apps/ccam/statehandlerutils.h @@ -1,266 +1,278 @@ #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; //@Benedikt/@David (New - 04/2020): in the folliwing, we do //"std::get<0>(I.first)" quite often. Would it not be faster if we save this // once in a variable and use this variable. 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"; + << " value: " + << std::get<0>( + static_cast &>(I.first)) + << "\n******\n"; // ONLYFORTEST - bool printFlag = Name == "Test"; + bool printFlag = Name == "Voltage"; if (printFlag) { - std::cout << Name << " - Input " << std::get<0>(I.first) << std::endl; + std::cout << Name << " - Input " + << std::get<0>(static_cast &>(I.first)) + << std::endl; } // TSETROFYLNO // ONLYFORTEST - added second parameter (printFlag) - auto StateInfo = - SigSD->detectSignalState(std::get<0>(I.first), printFlag); + auto StateInfo = SigSD->detectSignalState( + std::get<0>(static_cast &>(I.first)), printFlag); // TSETROFYLNO - added second parameter (printFlag) // ONLYFORTEST if (printFlag) { std::cout << "StateInfo:" << std::endl; std::cout << " > StateID: " << StateInfo.StateID << std::endl; /* std::cout << "In/Output: " << StateInfo.SignalProperty << std::endl; std::cout << "StateCondition: " << StateInfo.StateCondition << std::endl; std::cout << "StateIsValid: " << StateInfo.StateIsValid << std::endl; std::cout << "StateJustGotValid: " << StateInfo.StateJustGotValid << std::endl; std::cout << "StateIsValidAfterReentrance: " << StateInfo.StateIsValidAfterReentrance << std::endl; std::cout << "ConfidenceStateIsValid: " << StateInfo.ConfidenceStateIsValid << std::endl; std::cout << "ConfidenceStateIsInvalid: " << StateInfo.ConfidenceStateIsInvalid << std::endl; std::cout << "ConfidenceStateIsStable: " << StateInfo.ConfidenceStateIsStable << std::endl; std::cout << "ConfidenceStateIsDrifting: " << StateInfo.ConfidenceStateIsDrifting << std::endl; */ - getchar(); + + std::cout << std::endl + << "-------------------------------------------------------" + "-------------------------" + << std::endl + << std::endl; + + // getchar(); } // TSETROFYLNO if (I.second) { SignalStateTuple Res = { - std::get<0>(I.first), + std::get<0>(static_cast &>(I.first)), StateInfo.StateID, StateInfo.SignalProperty, StateInfo.ConfidenceOfMatchingState, StateInfo.ConfidenceOfMismatchingState, StateInfo.ConfidenceStateIsValid, StateInfo.ConfidenceStateIsInvalid, StateInfo.ConfidenceStateIsStable, StateInfo.ConfidenceStateIsDrifting, StateInfo.StateCondition, StateInfo.NumberOfInsertedSamplesAfterEntrance, (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: This is UGLY! std::shared_ptr< SystemStateDetector> SysSD; // todo: state-detector durchschleifen template struct function { ret operator()(A a) { std::vector> SignalStateInfos; std::stringstream OutString; for (auto _SignalStateTuple : a) { // convert tuple to info struct out.push_back({}); OutString << std::get<0>(_SignalStateTuple.first) << ","; SignalStateInformation Info; Info.StateID = std::get<1>(_SignalStateTuple.first); Info.SignalProperty = static_cast(std::get<2>(_SignalStateTuple.first)); Info.ConfidenceOfMatchingState = std::get<3>(_SignalStateTuple.first); Info.ConfidenceOfMismatchingState = std::get<4>(_SignalStateTuple.first); Info.ConfidenceStateIsValid = std::get<5>(_SignalStateTuple.first); Info.ConfidenceStateIsInvalid = std::get<6>(_SignalStateTuple.first); Info.ConfidenceStateIsStable = std::get<7>(_SignalStateTuple.first); Info.ConfidenceStateIsDrifting = std::get<8>(_SignalStateTuple.first); Info.StateCondition = static_cast(std::get<9>(_SignalStateTuple.first)); Info.NumberOfInsertedSamplesAfterEntrance = std::get<10>(_SignalStateTuple.first); Info.StateIsValid = (std::get<11>(_SignalStateTuple.first) & 4) > 0; Info.StateJustGotValid = (std::get<11>(_SignalStateTuple.first) & 2) > 0; Info.StateIsValidAfterReentrance = (std::get<11>(_SignalStateTuple.first) & 1) > 0; SignalStateInfos.push_back(Info); } SystemStateInformation SystemStateInfo = SysSD->detectSystemState(SignalStateInfos); OutString << SystemStateInfo.StateID << ","; OutString << SystemStateInfo.ConfidenceStateIsValid << ","; OutString << SystemStateInfo.ConfidenceStateIsInvalid << ","; OutString << SystemStateInfo.ConfidenceOfInputsMatchingState << ","; OutString << SystemStateInfo.ConfidenceOfInputsMismatchingState << ","; OutString << SystemStateInfo.ConfidenceOfOutputsMatchingState << ","; OutString << SystemStateInfo.ConfidenceOfOutputsMismatchingState << ","; OutString << SystemStateInfo.StateCondition << ","; OutString << SystemStateInfo.ConfidenceSystemIsFunctioning << ","; OutString << SystemStateInfo.ConfidenceSystemIsMalfunctioning << ","; OutString << SystemStateInfo.ConfidenceOfAllDecisions << ","; return ret(std::make_tuple(OutString.str())); } }; 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; std::shared_ptr< SystemStateDetector> _SysSD( new SystemStateDetector( std::numeric_limits::max(), NumOfSlaves, BrokenDelayFunction, OkDelayFunction)); SysSD = _SysSD; auto HandlerFunction = Handler, arr>, Input>::function; 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/include/rosa/agent/SignalState.hpp b/include/rosa/agent/SignalState.hpp index 2ecd93f..993bc66 100644 --- a/include/rosa/agent/SignalState.hpp +++ b/include/rosa/agent/SignalState.hpp @@ -1,486 +1,570 @@ //===-- 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; public: SignalStateInformation(unsigned int SignalStateID, SignalProperties _SignalProperty) { this->StateID = SignalStateID; this->SignalProperty = _SignalProperty; this->StateCondition = StateConditions::UNKNOWN; + this->NumberOfInsertedSamplesAfterEntrance = 0; this->StateIsValid = false; this->StateJustGotValid = false; this->StateIsValidAfterReentrance = false; this->ConfidenceStateIsValid = 0; this->ConfidenceStateIsInvalid = 0; this->ConfidenceStateIsStable = 0; this->ConfidenceStateIsDrifting = 0; } SignalStateInformation() {} }; /// \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; + /// TODO: explanation + StepFuncReference FuzzyFunctionNumOfSamplesValidFunctions; + + /// TODO: explanation + StepFuncReference FuzzyFunctionNumOfSamplesInvalidFunctions; + /// 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 = 0; CONFDATATYPE TempConfidenceMismatching = 0; 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, + StepFuncReference FuzzyFunctionNumOfSamplesValidFunctions, + StepFuncReference FuzzyFunctionNumOfSamplesInvalidFunctions, 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, SignalProperty}, FuzzyFunctionSampleMatches(FuzzyFunctionSampleMatches), FuzzyFunctionSampleMismatches(FuzzyFunctionSampleMismatches), FuzzyFunctionNumOfSamplesMatches(FuzzyFunctionNumOfSamplesMatches), FuzzyFunctionNumOfSamplesMismatches( FuzzyFunctionNumOfSamplesMismatches), + FuzzyFunctionNumOfSamplesValidFunctions( + FuzzyFunctionNumOfSamplesValidFunctions), + FuzzyFunctionNumOfSamplesInvalidFunctions( + FuzzyFunctionNumOfSamplesInvalidFunctions), 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 { + // ONLYFORTEST - 2nd parameter (printFlag) + SignalStateInformation insertSample(INDATATYPE Sample, + bool printFlag) noexcept { SignalStateInfo.NumberOfInsertedSamplesAfterEntrance++; - validateSignalState(Sample); + // QUESTION: Why Validating before inserting? + validateSignalState(Sample, printFlag); SampleHistory.addEntry(Sample); DAB.addEntry(Sample); if (DAB.full()) { PROCDATATYPE AvgOfDAB = DAB.template average(); DABHistory.addEntry(AvgOfDAB); DAB.clear(); } + // validateSignalState(Sample, printFlag); + FuzzyFunctionNumOfSamplesMatches.setRightLimit( static_cast(SampleHistory.numberOfEntries())); FuzzyFunctionNumOfSamplesMismatches.setRightLimit( static_cast(SampleHistory.numberOfEntries())); checkSignalStability(); //@benedikt (das gehört dazu) SignalStateInfo.ConfidenceOfMatchingState = TempConfidenceMatching; SignalStateInfo.ConfidenceOfMismatchingState = TempConfidenceMismatching; + // ONLYFORTEST + if (printFlag) { + std::cout << " > inserted sample." << std::endl; + std::cout << " >>> state valid? -> " + << this->signalStateInformation().StateIsValid << std::endl; + + std::cout << "SampleHistory.numberOfEntries(): " + << SampleHistory.numberOfEntries() << std::endl; + } + // TSETROFYLNO + 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]); } - // printf("AAAAAAAAAAAAAAAA 1\n"); ConfidenceOfWorstFittingSample = fuzzyAND(ConfidenceOfWorstFittingSample, ConfidenceFromRelativeDistance); - // printf("AAAAAAAAAAAAAAAA 2\n"); 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); - // printf("AAAAAAAAAAAAAAAA 3\n"); 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) { + void validateSignalState(INDATATYPE Sample, bool printFlag) { // 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! + + // ONLYFORTEST + if (printFlag) { + std::cout << "-> Before Validation:" << std::endl; + std::cout << " > c_valid = " << SignalStateInfo.ConfidenceStateIsValid + << std::endl; + std::cout << " > c_invalid = " << SignalStateInfo.ConfidenceStateIsInvalid + << std::endl; + } + unsigned int test_counter = 0; + // TSETROFYLNO + CONFDATATYPE LowestConfidenceMatching = 1; CONFDATATYPE HighestConfidenceMismatching = 0; + for (auto &HistorySample : SampleHistory) { // TODO (future): think about using different fuzzy functions for // validation and matching. - // printf("AAAAAAAAAAAAAAAA 4\n"); LowestConfidenceMatching = fuzzyAND( LowestConfidenceMatching, FuzzyFunctionSampleMatches(relativeDistance( Sample, HistorySample))); HighestConfidenceMismatching = fuzzyOR(HighestConfidenceMismatching, FuzzyFunctionSampleMismatches( relativeDistance( Sample, HistorySample))); + + // ONLYFORTEST + if (printFlag) { + test_counter++; + std::cout << " >>> Round " << test_counter + << ": LowMatch = " << LowestConfidenceMatching + << ", HigMism = " << HighestConfidenceMismatching + << std::endl; + } + // TSETROFYLNO } LowestConfidenceMatchingHistory.addEntry(LowestConfidenceMatching); HighestConfidenceMismatchingHistory.addEntry(HighestConfidenceMismatching); LowestConfidenceMatching = LowestConfidenceMatchingHistory.lowestEntry(); HighestConfidenceMismatching = HighestConfidenceMismatchingHistory.highestEntry(); - // printf("AAAAAAAAAAAAAAAA 5\n"); - SignalStateInfo.ConfidenceStateIsValid = - fuzzyAND(LowestConfidenceMatching, - FuzzyFunctionNumOfSamplesMatches(static_cast( - SignalStateInfo.NumberOfInsertedSamplesAfterEntrance))); - - SignalStateInfo.ConfidenceStateIsInvalid = - fuzzyOR(HighestConfidenceMismatching, - FuzzyFunctionNumOfSamplesMismatches(static_cast( - SignalStateInfo.NumberOfInsertedSamplesAfterEntrance))); + // ONLYFORTEST + if (printFlag) { + + std::cout << " >>> Final: LowMatch = " << LowestConfidenceMatching + << ", HigMism = " << HighestConfidenceMismatching << std::endl; + std::cout << " >>> Num: " + << SignalStateInfo.NumberOfInsertedSamplesAfterEntrance + << " -> FuzzyFunctionNumOfSamplesMatches = " + << FuzzyFunctionNumOfSamplesMatches(static_cast( + SignalStateInfo.NumberOfInsertedSamplesAfterEntrance)) + << std::endl; + std::cout << " >>> Num: " + << SignalStateInfo.NumberOfInsertedSamplesAfterEntrance + << " -> FuzzyFunctionNumOfSamplesMismatches = " + << FuzzyFunctionNumOfSamplesMismatches(static_cast( + SignalStateInfo.NumberOfInsertedSamplesAfterEntrance)) + << std::endl; + } + // TSETROFYLNO + + SignalStateInfo.ConfidenceStateIsValid = fuzzyAND( + LowestConfidenceMatching, + FuzzyFunctionNumOfSamplesValidFunctions(static_cast( + SignalStateInfo.NumberOfInsertedSamplesAfterEntrance))); + + SignalStateInfo.ConfidenceStateIsInvalid = fuzzyOR( + HighestConfidenceMismatching, + FuzzyFunctionNumOfSamplesInvalidFunctions(static_cast( + SignalStateInfo.NumberOfInsertedSamplesAfterEntrance))); + + // ONLYFORTEST + if (printFlag) { + std::cout << "-> After Validation:" << std::endl; + std::cout << " > c_valid = " << SignalStateInfo.ConfidenceStateIsValid + << std::endl; + std::cout << " > c_invalid = " << SignalStateInfo.ConfidenceStateIsInvalid + << std::endl; + } + // TSETROFYLNO if (SignalStateInfo.ConfidenceStateIsValid > SignalStateInfo.ConfidenceStateIsInvalid) { + + // ONLYFORTEST + if (printFlag) { + std::cout << " >>> c_valid > c_invalid." << std::endl; + } + // TSETROFYLNO + 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/SignalStateDetector.hpp b/include/rosa/agent/SignalStateDetector.hpp index d35c013..8a7ed50 100644 --- a/include/rosa/agent/SignalStateDetector.hpp +++ b/include/rosa/agent/SignalStateDetector.hpp @@ -1,294 +1,365 @@ //===-- rosa/agent/SignalStateDetector.hpp ----------------------*- C++ -*-===// // // The RoSA Framework // // Distributed under the terms and conditions of the Boost Software License 1.0. // See accompanying file LICENSE. // // If you did not receive a copy of the license file, see // http://www.boost.org/LICENSE_1_0.txt. // //===----------------------------------------------------------------------===// /// /// \file rosa/agent/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 SignalProperty saves whether the monitored signal is an input our /// output signal. SignalProperties SignalProperty; /// 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; + /// TODO: explanation + StepFuncPointer FuzzyFunctionNumOfSamplesValidFunctions; + + /// TODO: explanation + StepFuncPointer FuzzyFunctionNumOfSamplesInvalidFunctions; + /// 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(SignalProperties SignalProperty, uint32_t MaximumNumberOfSignalStates, PartFuncPointer FuzzyFunctionSampleMatches, PartFuncPointer FuzzyFunctionSampleMismatches, StepFuncPointer FuzzyFunctionNumOfSamplesMatches, StepFuncPointer FuzzyFunctionNumOfSamplesMismatches, + StepFuncPointer NumOfSamplesValidFunctions, + StepFuncPointer NumOfSamplesInvalidFunctions, PartFuncPointer FuzzyFunctionSignalIsDrifting, PartFuncPointer FuzzyFunctionSignalIsStable, uint32_t SampleHistorySize, uint32_t DABSize, uint32_t DABHistorySize) noexcept : SignalProperty(SignalProperty), CurrentSignalState(nullptr), DetectedSignalStates(MaximumNumberOfSignalStates), FuzzyFunctionSampleMatches(FuzzyFunctionSampleMatches), FuzzyFunctionSampleMismatches(FuzzyFunctionSampleMismatches), FuzzyFunctionNumOfSamplesMatches(FuzzyFunctionNumOfSamplesMatches), FuzzyFunctionNumOfSamplesMismatches( FuzzyFunctionNumOfSamplesMismatches), + FuzzyFunctionNumOfSamplesValidFunctions(NumOfSamplesValidFunctions), + FuzzyFunctionNumOfSamplesInvalidFunctions(NumOfSamplesInvalidFunctions), FuzzyFunctionSignalIsDrifting(FuzzyFunctionSignalIsDrifting), FuzzyFunctionSignalIsStable(FuzzyFunctionSignalIsStable), SampleHistorySize(SampleHistorySize), DABSize(DABSize), DABHistorySize(DABHistorySize) { this->NextStateID = 1; this->StateHasChanged = false; } /// 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() + // TODO (future): change this function to an operator()-function SignalStateInformation detectSignalState(INDATATYPE Sample, bool printFlag) noexcept { // ONLYFORTEST if (printFlag) std::cout << "SigStateDetector:" << std::endl; // TSETROFYLNO if (!CurrentSignalState) { + ASSERT(DetectedSignalStates.empty()); + SignalStatePtr S = createNewSignalState(); + CurrentSignalState = S; // ONLYFORTEST - if (printFlag) - std::cout << " > create new state" << std::endl; + if (printFlag) { + std::cout << " > No current signal state > create new state" + << std::endl; + std::cout << " >>> state valid? -> " + << CurrentSignalState->signalStateInformation().StateIsValid + << std::endl; + } // TSETROFYLNO - ASSERT(DetectedSignalStates.empty()); - SignalStatePtr S = createNewSignalState(); - CurrentSignalState = S; } else { + // TODO (future): maybe there is a better way than a relative distance + // comparison. Maybe somehow a mix of relative and absolute? CONFDATATYPE ConfidenceSampleMatchesSignalState = CurrentSignalState->confidenceSampleMatchesSignalState(Sample); CONFDATATYPE ConfidenceSampleMismatchesSignalState = CurrentSignalState->confidenceSampleMismatchesSignalState(Sample); this->StateHasChanged = ConfidenceSampleMatchesSignalState <= ConfidenceSampleMismatchesSignalState; + // ONLYFORTEST + if (printFlag) { + std::cout << " > c_matches = " << ConfidenceSampleMatchesSignalState + << std::endl; + std::cout << " > c_mismatches = " + << ConfidenceSampleMismatchesSignalState << std::endl; + } + // TSETROFYLNO + if (this->StateHasChanged) { - if (CurrentSignalState->signalStateInformation().StateIsValid) + // ONLYFORTEST + if (printFlag) { + std::cout << " >>>>>>>>>>>>>> STATE HAS CHANGED." << std::endl; + } + // TSETROFYLNO + + if (CurrentSignalState->signalStateInformation().StateIsValid) { + // ONLYFORTEST + if (printFlag) { + std::cout << " > signal state is valid." << std::endl; + } + // TSETROFYLNO + CurrentSignalState->leaveSignalState(); - else + } else { + // ONLYFORTEST + if (printFlag) { + std::cout << " > signal state is invalid." << std::endl; + } + // TSETROFYLNO + 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; for (auto &SavedSignalState : DetectedSignalStates) { 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) { - // ONLYFORTEST - if (printFlag) - std::cout << " > create new state" << std::endl; - // TSETROFYLNO - SignalStatePtr S = createNewSignalState(); CurrentSignalState = S; + + // ONLYFORTEST + if (printFlag) { + std::cout << " > No current signal state > create new state" + << std::endl; + std::cout + << " >>> state valid? -> " + << CurrentSignalState->signalStateInformation().StateIsValid + << std::endl; + } + // TSETROFYLNO + } + } + // ONLYFORTEST + else { + if (printFlag) { + std::cout << " > SAME STATE" << std::endl; } } + // TSETROFYLNO } + // ONLYFORTEST - 2nd parameter (printFlag) SignalStateInformation SignalStateInfo = - CurrentSignalState->insertSample(Sample); + CurrentSignalState->insertSample(Sample, printFlag); + // TSETROFYLNO - 2nd parameter (printFlag) + + // ONLYFORTEST + if (printFlag) { + std::cout << std::endl + << "Valid = " << SignalStateInfo.StateIsValid << std::endl + << "Just got Valid = " << SignalStateInfo.StateJustGotValid + << std::endl + << std::endl; + } if (SignalStateInfo.StateJustGotValid) { this->NextStateID++; } 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 stateHasChanged(void) noexcept { return this->StateHasChanged; } 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( this->NextStateID, SignalProperty, SampleHistorySize, DABSize, DABHistorySize, *FuzzyFunctionSampleMatches, *FuzzyFunctionSampleMismatches, *FuzzyFunctionNumOfSamplesMatches, - *FuzzyFunctionNumOfSamplesMismatches, *FuzzyFunctionSignalIsDrifting, - *FuzzyFunctionSignalIsStable)); + *FuzzyFunctionNumOfSamplesMismatches, + *FuzzyFunctionNumOfSamplesValidFunctions, + *FuzzyFunctionNumOfSamplesInvalidFunctions, + *FuzzyFunctionSignalIsDrifting, *FuzzyFunctionSignalIsStable)); DetectedSignalStates.addEntry(S); return S; } }; } // End namespace agent } // End namespace rosa #endif // ROSA_AGENT_SIGNALSTATEDETECTOR_HPP