diff --git a/apps/ccam/ccam.cpp b/apps/ccam/ccam.cpp index 9a8f49a..c4c8681 100644 --- a/apps/ccam/ccam.cpp +++ b/apps/ccam/ccam.cpp @@ -1,617 +1,641 @@ //===-- 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/DistanceMetrics.hpp" #include "rosa/agent/FunctionAbstractions.hpp" #include #include "rosa/config/version.h" #include "rosa/agent/SignalStateDetector.hpp" #include "rosa/agent/SystemStateDetector.hpp" #include "rosa/app/Application.hpp" #include "rosa/support/csv/CSVReader.hpp" #include "rosa/support/csv/CSVWriter.hpp" #include "rosa/support/mqtt/MQTTReader.hpp" #include "rosa/app/AppTuple.hpp" #include #include #include #include #include #include "configuration.h" #include "statehandlerutils.h" using namespace rosa; using namespace rosa::agent; using namespace rosa::app; using namespace rosa::terminal; using namespace rosa::mqtt; const std::string AppName = "CCAM"; int main(int argc, char **argv) { LOG_INFO_STREAM << '\n' << library_string() << " -- " << Color::Red << AppName << "app" << Color::Default << '\n'; // // 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; } // // Create a CCAM context. // LOG_INFO("Creating Context"); std::unique_ptr AppCCAM = Application::create(AppName); // // Create following function which shall give information if the time gap // between changed input(s) and changed output(s) shows already a malfunction // of the system. // // ____________ // / // / // __________/ // 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 which shall give information if the time gap // between changed input(s) and changed output(s) still shows a // well-functioning system. // // ____________ // \ // \ // \__________ // 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 AppAgent with SystemStateDetector functionality. // LOG_INFO("Create SystemStateDetector agent."); AgentHandle SystemStateDetectorAgent = createSystemStateDetectorAgent( AppCCAM, "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); AppCCAM->setExecutionPolicy(SystemStateDetectorAgent, AppExecutionPolicy::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. // LOG_INFO("Creating sensors, SignalStateDetector functionalities and their " "Abstractions."); std::vector Sensors; - std::vector, float>>> DistanceMetrics; + std::vector, float>>> + DistanceMetrics; std::vector>> SampleMatchesFunctions; std::vector>> SampleMismatchesFunctions; std::vector>> SignalIsStableFunctions; std::vector>> - SignalIsDriftingFunctions; - // SAVE CHANGES + SignalIsDriftingDownFunctions; + std::vector>> + SignalIsDriftingUpFunctions; std::vector>> SignalConditionLookBackFunctions; std::vector>> SignalConditionHistoryDesicionFunctions; - // - SAVE CHANGES std::vector>> NumOfSamplesMatchFunctions; std::vector>> NumOfSamplesMismatchFunctions; std::vector>> SampleValidFunctions; std::vector>> SampleInvalidFunctions; 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 application sensors. // Sensors.emplace_back( AppCCAM->createSensor(SignalConfiguration.Name + "_Sensor")); // // Create following function(s) which shall give information whether one // sample matches another one (based on the relative distance between them). // // ____________ // / \ // / \ // __________/ \__________ // // - if (std::strcmp(SignalConfiguration.DistanceMetric.c_str(), "absolute") == 0 ) { - DistanceMetrics.emplace_back(new AbsoluteDistance()); - } else if (std::strcmp(SignalConfiguration.DistanceMetric.c_str(), "daniel1") == 0 ) { - DistanceMetrics.emplace_back(new DanielsDistance1()); - } else if (std::strcmp(SignalConfiguration.DistanceMetric.c_str(), "daniel2") == 0 ) { - DistanceMetrics.emplace_back(new DanielsDistance2()); - } else if (std::strcmp(SignalConfiguration.DistanceMetric.c_str(), "daniel3") == 0 ) { - DistanceMetrics.emplace_back(new DanielsDistance3()); - } else if (std::strcmp(SignalConfiguration.DistanceMetric.c_str(), "maxi1") == 0 ) { - DistanceMetrics.emplace_back(new MaxisDistance1()); + if (std::strcmp(SignalConfiguration.DistanceMetric.c_str(), "absolute") == + 0) { + DistanceMetrics.emplace_back(new AbsoluteDistance()); + } else if (std::strcmp(SignalConfiguration.DistanceMetric.c_str(), + "daniel1") == 0) { + DistanceMetrics.emplace_back(new DanielsDistance1()); + } else if (std::strcmp(SignalConfiguration.DistanceMetric.c_str(), + "daniel2") == 0) { + DistanceMetrics.emplace_back(new DanielsDistance2()); + } else if (std::strcmp(SignalConfiguration.DistanceMetric.c_str(), + "daniel3") == 0) { + DistanceMetrics.emplace_back(new DanielsDistance3()); + } else if (std::strcmp(SignalConfiguration.DistanceMetric.c_str(), + "maxi1") == 0) { + DistanceMetrics.emplace_back(new MaxisDistance1()); } else { - //default is relative distance - DistanceMetrics.emplace_back(new RelativeDistance()); + // default is relative distance + DistanceMetrics.emplace_back(new RelativeDistance()); } 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) which shall give information whether one // sample mismatches another one (based on the relative distance between // them). // // ____________ ____________ // \ / // \ / // \__________/ // // 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) which shall give information whether a // signal is stable. // // ____________ // / \ // / \ // __________/ \__________ // // 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) which shall give information whether a - // signal is drifting. + // signal is drifting down. + // + // ____________ + // \ + // \ + // \______________________ // - // ____________ ____________ - // \ / - // \ / - // \__________/ + // + SignalIsDriftingDownFunctions.emplace_back( + new PartialFunction( + { + {{-SignalConfiguration.OuterBoundDrift, + -SignalConfiguration.InnerBoundDrift}, + std::make_shared>( + -SignalConfiguration.OuterBoundDrift, 1.f, + -SignalConfiguration.InnerBoundDrift, 0.f)}, + {{-SignalConfiguration.InnerBoundDrift, + std::numeric_limits::max()}, + std::make_shared>(0.f, 0.f)}, + }, + 1)); + + // + // Create following function(s) which shall give information whether a + // signal is drifting up. + // + // ____________ + // / + // / + // ______________________/ // // - SignalIsDriftingFunctions.emplace_back(new PartialFunction( + SignalIsDriftingUpFunctions.emplace_back(new PartialFunction( { - {{-SignalConfiguration.OuterBoundDrift, - -SignalConfiguration.InnerBoundDrift}, - std::make_shared>( - -SignalConfiguration.OuterBoundDrift, 1.f, - -SignalConfiguration.InnerBoundDrift, 0.f)}, - {{-SignalConfiguration.InnerBoundDrift, + {{std::numeric_limits::min(), 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)); // SAVE CHANGES SignalConditionLookBackFunctions.emplace_back( new PartialFunction( {{{1, SignalConfiguration.DriftLookbackRange + 1}, std::make_shared>( 1, 1.f, SignalConfiguration.DriftLookbackRange + 1, 0.f)}, {{SignalConfiguration.DriftLookbackRange + 1, std::numeric_limits::max()}, std::make_shared>(0.f, 0.f)}}, 1.f)); SignalConditionHistoryDesicionFunctions.emplace_back( new PartialFunction( {{{0, SignalConfiguration.DriftLookbackRange}, std::make_shared>( 0, 0.f, SignalConfiguration.DriftLookbackRange, 1.f)}, {{SignalConfiguration.DriftLookbackRange, std::numeric_limits::max()}, std::make_shared>(1.f, 0.f)}}, 0.f)); // - SAVE CHANGES // // Create following function(s) which shall give information how many // history samples match another sample. // // ____________ // / // / // __________/ // NumOfSamplesMatchFunctions.emplace_back(new StepFunction( 1.0f / SignalConfiguration.SampleHistorySize, StepDirection::StepUp)); // // Create following function(s) which shall give information how many // history samples mismatch another sample. // // ____________ // \ // \ // \__________ // NumOfSamplesMismatchFunctions.emplace_back(new StepFunction( 1.0f / SignalConfiguration.SampleHistorySize, StepDirection::StepDown)); // // Create following function(s) which shall give information how good all // samples in a state match each other. // // ____________ // / \ // / \ // __________/ \__________ // // SampleValidFunctions.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) which shall give information how good all // samples in a state mismatch each other. // // ____________ ____________ // \ / // \ / // \__________/ // // SampleInvalidFunctions.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) which shall give information how many // history samples match each other. // // ____________ // / // / // __________/ // NumOfSamplesValidFunctions.emplace_back(new StepFunction( 1.0f / SignalConfiguration.SampleHistorySize, StepDirection::StepUp)); // // Create following function(s) which shall give information how many // history samples mismatch each other. // // ____________ // \ // \ // \__________ // 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(), DistanceMetrics.back(), SampleMatchesFunctions.back(), - SampleMismatchesFunctions.back(), NumOfSamplesMatchFunctions.back(), + std::numeric_limits::max(), DistanceMetrics.back(), + SampleMatchesFunctions.back(), SampleMismatchesFunctions.back(), + NumOfSamplesMatchFunctions.back(), NumOfSamplesMismatchFunctions.back(), SampleValidFunctions.back(), SampleInvalidFunctions.back(), NumOfSamplesValidFunctions.back(), NumOfSamplesInvalidFunctions.back(), - SignalIsDriftingFunctions.back(), SignalIsStableFunctions.back(), - // SAVE CHANGES + SignalIsDriftingDownFunctions.back(), + SignalIsDriftingUpFunctions.back(), SignalIsStableFunctions.back(), SignalConditionLookBackFunctions.back(), SignalConditionHistoryDesicionFunctions.back(), SignalConfiguration.DriftLookbackRange, - // - SAVE CHANGES - SignalConfiguration.SampleHistorySize, SignalConfiguration.DABSize, - SignalConfiguration.DABHistorySize)); + SignalConfiguration.SampleHistorySize)); // // Create low-level application agents // SignalStateDetectorAgents.push_back(createSignalStateDetectorAgent( AppCCAM, SignalConfiguration.Name, SignalStateDetectors.back())); AppCCAM->setExecutionPolicy( SignalStateDetectorAgents.back(), AppExecutionPolicy::decimation(AppConfig.DownsamplingRate)); // // Connect sensors to low-level agents. // LOG_INFO("Connect sensors to their corresponding low-level agents."); AppCCAM->connectSensor(SignalStateDetectorAgents.back(), 0, Sensors.back(), SignalConfiguration.Name + "_Sensor ->" + SignalConfiguration.Name + "_SignalStateDetector_Agent-Channel"); AppCCAM->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 = AppCCAM->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."); AppCCAM->connectAgents(LoggerAgent, 0, SystemStateDetectorAgent, "SystemStateDetector Channel"); // // Only log if the SystemStateDetector actually ran // AppCCAM->setExecutionPolicy(LoggerAgent, AppExecutionPolicy::awaitAll({0})); // // Do simulation. // LOG_INFO("Setting up and performing simulation."); // // Initialize application for simulation. // AppCCAM->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; bool hasMQTT = false; for (auto SignalConfiguration : AppConfig.SignalConfigurations) { switch (SignalConfiguration.DataInterfaceType) { case DataInterfaceTypes::CSV: 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; } AppCCAM->registerSensorValues(Sensors.at(i), csv::CSVIterator(DataFiles.at(i)), csv::CSVIterator()); LOG_INFO_STREAM << "Sensor " << SignalConfiguration.Name << " is fed by csv file " << SignalConfiguration.InputPath << std::endl; break; case DataInterfaceTypes::MQTT: { hasMQTT = true; auto it = MQTTIterator(SignalConfiguration.MQTTTopic); AppCCAM->registerSensorValues(Sensors.at(i), std::move(it), MQTTIterator()); LOG_INFO_STREAM << "Sensor " << SignalConfiguration.Name << " is fed by MQTT topic " << SignalConfiguration.MQTTTopic << std::endl; break; } default: LOG_ERROR_STREAM << "No data source for " << SignalConfiguration.Name << std::endl; break; } i++; } // // Start simulation. // auto &log = LOG_WARNING_STREAM; log << "Simulation starting."; if (hasMQTT) { log << " Publishing MQTT messages may start."; } log << std::endl; AppCCAM->simulate(AppConfig.NumberOfSimulationCycles); return 0; } diff --git a/apps/ccam/configuration.h b/apps/ccam/configuration.h index 53e79b3..f18aae8 100644 --- a/apps/ccam/configuration.h +++ b/apps/ccam/configuration.h @@ -1,108 +1,104 @@ #ifndef CONFIGURATION_H #define CONFIGURATION_H // clang-tidy off // clang-format off #include "nlohmann/json.hpp" // clang-format on // clang-tidy on #include "rosa/config/version.h" #include "rosa/app/Application.hpp" #include using namespace rosa; using nlohmann::json; enum DataInterfaceTypes { CSV, MQTT }; struct SignalConfiguration { std::string Name; std::string InputPath; std::string MQTTTopic; DataInterfaceTypes DataInterfaceType; bool Output; float InnerBound; float OuterBound; float InnerBoundDrift; float OuterBoundDrift; - // SAVE CHANGES uint32_t DriftLookbackRange; - // - SAVE CHANGES uint32_t SampleHistorySize; uint32_t DABSize; - uint32_t DABHistorySize; std::string DistanceMetric; }; struct AppConfiguration { std::string OutputFilePath; uint32_t BrokenCounter; uint32_t NumberOfSimulationCycles; uint32_t DownsamplingRate; std::vector SignalConfigurations; }; void from_json(const json &J, SignalConfiguration &SC) { J.at("Name").get_to(SC.Name); if (J.contains("InputPath")) { J.at("InputPath").get_to(SC.InputPath); SC.DataInterfaceType = DataInterfaceTypes::CSV; } else if (J.contains("MQTTTopic")) { J.at("MQTTTopic").get_to(SC.MQTTTopic); SC.DataInterfaceType = DataInterfaceTypes::MQTT; } J.at("Output").get_to(SC.Output); J.at("InnerBound").get_to(SC.InnerBound); J.at("OuterBound").get_to(SC.OuterBound); J.at("InnerBoundDrift").get_to(SC.InnerBoundDrift); J.at("OuterBoundDrift").get_to(SC.OuterBoundDrift); if (J.contains("DriftLookbackRange")) { J.at("DriftLookbackRange").get_to(SC.DriftLookbackRange); } else { // TODO: is 1 the best? SC.DriftLookbackRange = 1; } J.at("SampleHistorySize").get_to(SC.SampleHistorySize); J.at("DABSize").get_to(SC.DABSize); - J.at("DABHistorySize").get_to(SC.DABHistorySize); SC.DistanceMetric = J.value("DistanceMetric", "relative"); } void from_json(const json &J, AppConfiguration &AC) { J.at("OutputFilePath").get_to(AC.OutputFilePath); J.at("BrokenCounter").get_to(AC.BrokenCounter); J.at("NumberOfSimulationCycles").get_to(AC.NumberOfSimulationCycles); J.at("DownsamplingRate").get_to(AC.DownsamplingRate); J.at("SignalConfigurations").get_to(AC.SignalConfigurations); } AppConfiguration AppConfig; bool readConfigFile(std::string ConfigPath) { LOG_INFO("READING CONFIG FILE"); LOG_INFO_STREAM << "Looking for config file at \"" << ConfigPath << "\"\n"; std::ifstream ConfigFile; ConfigFile.open(ConfigPath); if (!ConfigFile) { LOG_ERROR("Unable to open config file"); return false; } json ConfigObj; ConfigFile >> ConfigObj; LOG_INFO_STREAM << "Read JSON file as \"" << ConfigObj << "\"\n"; try { ConfigObj.get_to(AppConfig); } catch (nlohmann::detail::type_error ex) { LOG_ERROR("Misformatted Config File"); return false; } return true; } #endif // CONFIGURATION_H diff --git a/include/rosa/agent/SignalState.hpp b/include/rosa/agent/SignalState.hpp index ccad719..04ad2ff 100644 --- a/include/rosa/agent/SignalState.hpp +++ b/include/rosa/agent/SignalState.hpp @@ -1,684 +1,696 @@ //===-- rosa/agent/SignalState.hpp ------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/agent/SignalState.hpp /// /// \author Maximilian Götzinger (maximilian.goetzinger@tuwien.ac.at) /// /// \date 2019 /// /// \brief Definition of *signal state* *functionality*. /// //===----------------------------------------------------------------------===// #ifndef ROSA_AGENT_SIGNALSTATE_HPP #define ROSA_AGENT_SIGNALSTATE_HPP #include "rosa/agent/DistanceMetrics.hpp" #include "rosa/agent/FunctionAbstractions.hpp" #include "rosa/agent/Functionality.h" #include "rosa/agent/History.hpp" #include "rosa/agent/State.hpp" #include "rosa/support/math.hpp" namespace rosa { namespace agent { /// Signal properties defining the properties of the signal which is monitored /// by \c rosa::agent::SignalStateDetector and is saved in \c /// rosa::agent::SignalStateInformation. enum SignalProperties : uint8_t { INPUT = 0, ///< The signal is an input signal OUTPUT = 1 ///< The signal is an output signal }; +/// TODO: write description +template struct DABHistoryEntry { + + /// TODO: write description + PROCDATATYPE AvgValue; + + /// TODO: write description + CONFDATATYPE DecisionDABIsStable; + + /// TODO: write description + CONFDATATYPE DecisionDABIsDriftingDown; + + /// TODO: write description + CONFDATATYPE DecisionDABIsDriftingUp; + + /// TODO: write description + bool DABWasCurrent; + +public: + DABHistoryEntry(PROCDATATYPE AvgValue) { + this->AvgValue = AvgValue; + this->DecisionDABIsStable = 0; + this->DecisionDABIsDriftingDown = 0; + this->DecisionDABIsDriftingUp = 0; + this->DABWasCurrent = false; + } + + DABHistoryEntry() = default; +}; + /// TODO: write description template struct SignalStateInformation : StateInformation { // Make sure the actual type arguments are matching our expectations. STATIC_ASSERT((std::is_arithmetic::value), "confidence type is not to arithmetic"); /// ConfidenceOfMatchingState is the confidence how good the new sample /// matches the state. CONFDATATYPE ConfidenceOfMatchingState; /// ConfidenceOfMatchingState is the confidence how bad the new sample /// matches the state. CONFDATATYPE ConfidenceOfMismatchingState; /// The SignalProperty saves whether the monitored signal is an input our /// output signal. SignalProperties SignalProperty; /// The SignalStateIsValid saves the number of samples which have been /// inserted into the state after entering it. uint32_t NumberOfInsertedSamplesAfterEntrance; public: SignalStateInformation(unsigned int SignalStateID, SignalProperties _SignalProperty) { this->StateID = SignalStateID; this->SignalProperty = _SignalProperty; this->StateCondition = StateConditions::UNKNOWN; this->NumberOfInsertedSamplesAfterEntrance = 0; this->StateIsValid = false; this->StateJustGotValid = false; this->StateIsValidAfterReentrance = false; this->ConfidenceStateIsValid = 0; this->ConfidenceStateIsInvalid = 0; this->ConfidenceStateIsStable = 0; this->ConfidenceStateIsDrifting = 0; + this->ConfidenceStateIsDriftingDown = 0; + this->ConfidenceStateIsDriftingUp = 0; } SignalStateInformation() = default; }; /// \tparam INDATATYPE type of input data, \tparam CONFDATATYPE type of /// data in that the confidence values are given, \tparam PROCDATATYPE type of /// the relative distance and the type of data in which DABs are saved. template class SignalState : public Functionality { // Make sure the actual type arguments are matching our expectations. STATIC_ASSERT((std::is_arithmetic::value), "input data type not arithmetic"); STATIC_ASSERT((std::is_arithmetic::value), "confidence data type is not to arithmetic"); STATIC_ASSERT( (std::is_arithmetic::value), "process data type (DAB and Relative Distance) is not to arithmetic"); public: // The metric to calculate the distance between two points using DistanceMetricAbstraction = Abstraction, PROCDATATYPE> &; // For the convinience to write a shorter data type name using PartFuncReference = PartialFunction &; // using PartFuncReference2 = ; using StepFuncReference = StepFunction &; private: /// SignalStateInfo is a struct of SignalStateInformation that contains /// information about the current signal state. SignalStateInformation SignalStateInfo; /// The metric to calculate the distance between two points DistanceMetricAbstraction DistanceMetric; /// The FuzzyFunctionSampleMatches is the fuzzy function that gives the /// confidence how good the new sample matches another sample in the sample /// history. PartFuncReference FuzzyFunctionSampleMatches; /// The FuzzyFunctionSampleMismatches is the fuzzy function that gives the /// confidence how bad the new sample matches another sample in the sample /// history. PartFuncReference FuzzyFunctionSampleMismatches; /// The FuzzyFunctionNumOfSamplesMatches is the fuzzy function that gives the /// confidence how many samples from the sampe history match the new sample. StepFuncReference FuzzyFunctionNumOfSamplesMatches; /// The FuzzyFunctionNumOfSamplesMismatches is the fuzzy function that gives /// the confidence how many samples from the sampe history mismatch the new /// sample. StepFuncReference FuzzyFunctionNumOfSamplesMismatches; /// The FuzzyFunctionSampleValid is the fuzzy function that gives the /// confidence how good one matches another sample in the sample /// history. This is done to evaluate whether a state is valid. PartFuncReference FuzzyFunctionSampleValid; /// The FuzzyFunctionSampleInvalid is the fuzzy function that gives the /// confidence how bad one sample matches another sample in the sample /// history. This is done to evaluate whether a state is invalid. PartFuncReference FuzzyFunctionSampleInvalid; /// The FuzzyFunctionNumOfSamplesValid is the fuzzy function that gives the /// confidence how many samples from the sample history match another sample. /// This is done to evaluate whether a state is valid. StepFuncReference FuzzyFunctionNumOfSamplesValid; /// The FuzzyFunctionNumOfSamplesInvalid is the fuzzy function that gives /// the confidence how many samples from the sample history mismatch another /// sample. This is done to evaluate whether a state is invalid. StepFuncReference FuzzyFunctionNumOfSamplesInvalid; - /// The FuzzyFunctionSignalIsDrifting is the fuzzy function that gives the + /// The FuzzyFunctionSignalIsDriftingDown is the fuzzy function that gives the + /// confidence how likely it is that the signal (resp. the state of a signal) + /// is drifting down. + PartFuncReference FuzzyFunctionSignalIsDriftingDown; + + /// The FuzzyFunctionSignalIsDriftingUp is the fuzzy function that gives the /// confidence how likely it is that the signal (resp. the state of a signal) - /// is drifting. - PartFuncReference FuzzyFunctionSignalIsDrifting; + /// is drifting up. + PartFuncReference FuzzyFunctionSignalIsDriftingUp; /// The FuzzyFunctionSignalIsStable is the fuzzy function that gives the /// confidence how likely it is that the signal (resp. the state of a signal) /// is stable (not drifting). PartFuncReference FuzzyFunctionSignalIsStable; /// TODO: description PartialFunction &FuzzyFunctionSignalConditionLookBack; /// TODO: description PartialFunction &FuzzyFunctionSignalConditionHistoryDesicion; /// TODO: description uint32_t DriftLookbackRange; /// SampleHistory is a history in that the last sample values are stored. DynamicLengthHistory SampleHistory; /// DAB is a (usually) small history of the last sample values of which a /// average is calculated if the DAB is full. DynamicLengthHistory DAB; /// DABHistory is a history in that the last DABs (to be exact, the averages /// of the last DABs) are stored. - DynamicLengthHistory DABHistory; + DynamicLengthHistory, + HistoryPolicy::FIFO> + DABHistory; /// LowestConfidenceMatchingHistory is a history in that the lowest confidence /// for the current sample matches all history samples are saved. DynamicLengthHistory LowestConfidenceMatchingHistory; /// HighestConfidenceMatchingHistory is a history in that the highest /// confidence for the current sample matches all history samples are saved. DynamicLengthHistory HighestConfidenceMismatchingHistory; /// TempConfidenceMatching is the confidence how good a sample matches the /// state. However, the value of this variable is only needed temporarly. CONFDATATYPE TempConfidenceMatching = 0; /// TempConfidenceMatching is the confidence how bad a sample matches the /// state. However, the value of this variable is only needed temporarly. CONFDATATYPE TempConfidenceMismatching = 0; public: /// Creates an instance by setting all parameters /// \param SignalStateID The Id of the SignalStateinfo \c /// SignalStateInformation. /// /// \param DistanceMetric the distance metric to calculate the distance /// between two points /// /// \param FuzzyFunctionSampleMatches The FuzzyFunctionSampleMatches is the /// fuzzy function that gives the confidence how good the new sample matches /// another sample in the sample history. /// /// \param FuzzyFunctionSampleMismatches The FuzzyFunctionSampleMismatches is /// the fuzzy function that gives the confidence how bad the new sample /// matches another sample in the sample history. /// /// \param FuzzyFunctionNumOfSamplesMatches The /// FuzzyFunctionNumOfSamplesMatches is the fuzzy function that gives the /// confidence how many samples from the sampe history match the new sample. /// /// \param FuzzyFunctionNumOfSamplesMismatches The /// FuzzyFunctionNumOfSamplesMismatches is the fuzzy function that gives the /// confidence how many samples from the sampe history mismatch the new /// sample. /// - /// \param FuzzyFunctionSignalIsDrifting The FuzzyFunctionSignalIsDrifting is - /// the fuzzy function that gives the confidence how likely it is that the - /// signal (resp. the state of a signal) is drifting. + /// \param FuzzyFunctionSignalIsDriftingDown The + /// FuzzyFunctionSignalIsDriftingDown is the fuzzy function that gives the + /// confidence how likely it is that the signal (resp. the state of a signal) + /// is drifting down. + /// + /// + /// \param FuzzyFunctionSignalIsDriftingUp The FuzzyFunctionSignalIsDriftingUp + /// is the fuzzy function that gives the confidence how likely it is that the + /// signal (resp. the state of a signal) is drifting down. /// /// \param FuzzyFunctionSignalIsStable The FuzzyFunctionSignalIsStable is the /// fuzzy function that gives the confidence how likely it is that the signal /// (resp. the state of a signal) is stable (not drifting). /// /// \param SampleHistorySize Size of the Sample History \c /// DynamicLengthHistory . SampleHistory is a history in that the last sample /// values are stored. /// /// \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, + uint32_t SampleHistorySize, uint32_t DABSize, DistanceMetricAbstraction DistanceMetric, PartFuncReference FuzzyFunctionSampleMatches, PartFuncReference FuzzyFunctionSampleMismatches, StepFuncReference FuzzyFunctionNumOfSamplesMatches, StepFuncReference FuzzyFunctionNumOfSamplesMismatches, PartFuncReference FuzzyFunctionSampleValid, PartFuncReference FuzzyFunctionSampleInvalid, StepFuncReference FuzzyFunctionNumOfSamplesValid, StepFuncReference FuzzyFunctionNumOfSamplesInvalid, - // SAVE CHANGES - PartFuncReference FuzzyFunctionSignalIsDrifting, + PartFuncReference FuzzyFunctionSignalIsDriftingDown, + PartFuncReference FuzzyFunctionSignalIsDriftingUp, PartFuncReference FuzzyFunctionSignalIsStable, PartialFunction &FuzzyFunctionSignalConditionLookBack, - // - SAVE CHANGES PartialFunction &FuzzyFunctionSignalConditionHistoryDesicion, uint32_t DriftLookbackRange) noexcept : SignalStateInfo{SignalStateID, SignalProperty}, DistanceMetric(DistanceMetric), FuzzyFunctionSampleMatches(FuzzyFunctionSampleMatches), FuzzyFunctionSampleMismatches(FuzzyFunctionSampleMismatches), FuzzyFunctionNumOfSamplesMatches(FuzzyFunctionNumOfSamplesMatches), FuzzyFunctionNumOfSamplesMismatches( FuzzyFunctionNumOfSamplesMismatches), FuzzyFunctionSampleValid(FuzzyFunctionSampleValid), FuzzyFunctionSampleInvalid(FuzzyFunctionSampleInvalid), FuzzyFunctionNumOfSamplesValid(FuzzyFunctionNumOfSamplesValid), FuzzyFunctionNumOfSamplesInvalid(FuzzyFunctionNumOfSamplesInvalid), - FuzzyFunctionSignalIsDrifting(FuzzyFunctionSignalIsDrifting), + FuzzyFunctionSignalIsDriftingDown(FuzzyFunctionSignalIsDriftingDown), + FuzzyFunctionSignalIsDriftingUp(FuzzyFunctionSignalIsDriftingUp), FuzzyFunctionSignalIsStable(FuzzyFunctionSignalIsStable), - // SAVE CHANGES FuzzyFunctionSignalConditionLookBack( FuzzyFunctionSignalConditionLookBack), FuzzyFunctionSignalConditionHistoryDesicion( FuzzyFunctionSignalConditionHistoryDesicion), DriftLookbackRange(DriftLookbackRange), - // - SAVE CHANGES SampleHistory(SampleHistorySize), DAB(DABSize), - DABHistory(DABHistorySize), + DABHistory(DriftLookbackRange + 1), 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()) { - - // TODO: make soring inside of median - // TODO: make better outlier removal! - // std::sort(DAB.begin(), DAB.end()); - // DAB.erase(DAB.begin(), DAB.begin() + 1); - // DAB.erase(DAB.end() - 1, DAB.end()); - // PROCDATATYPE AvgOfDAB = DAB.template median(); + // TODO: try median instead of avg PROCDATATYPE AvgOfDAB = DAB.template average(); - DABHistory.addEntry(AvgOfDAB); + // DABHistory.addEntry(AvgOfDAB); + DABHistory.addEntry( + DABHistoryEntry(AvgOfDAB)); DAB.clear(); } FuzzyFunctionNumOfSamplesMatches.setRightLimit( static_cast(SampleHistory.numberOfEntries())); FuzzyFunctionNumOfSamplesMismatches.setRightLimit( static_cast(SampleHistory.numberOfEntries())); checkSignalStability(); SignalStateInfo.ConfidenceOfMatchingState = TempConfidenceMatching; SignalStateInfo.ConfidenceOfMismatchingState = TempConfidenceMismatching; return SignalStateInfo; } /// Gives the confidence how likely the new sample matches the signal state. /// /// \param Sample is the actual sample of the observed signal. /// /// \return the confidence of the new sample is matching the signal state. CONFDATATYPE confidenceSampleMatchesSignalState(INDATATYPE Sample) noexcept { CONFDATATYPE ConfidenceOfBestCase = 0; DynamicLengthHistory RelativeDistanceHistory(SampleHistory.maxLength()); // Calculate distances to all history samples. for (auto &HistorySample : SampleHistory) { PROCDATATYPE RelativeDistance = DistanceMetric(std::make_pair(Sample, HistorySample)); RelativeDistanceHistory.addEntry(RelativeDistance); } // Sort all calculated distances so that the lowest distance (will get the // highest confidence) is at the beginning. RelativeDistanceHistory.sortAscending(); CONFDATATYPE ConfidenceOfWorstFittingSample = 1; // Case 1 means that one (the best fitting) sample of the history is // compared with the new sample. Case 2 means the two best history samples // are compared with the new sample. And so on. // TODO (future): to accelerate . don't start with 1 start with some higher // number because a low number (i guess lower than 5) will definetely lead // to a low confidence. except the history is not full. // Case 1 means that one (the best fitting) sample of the history is // compared with the new sample. Case 2 means the two best history samples // are compared with the new sample. And so on. for (uint32_t Case = 0; Case < RelativeDistanceHistory.numberOfEntries(); Case++) { CONFDATATYPE ConfidenceFromRelativeDistance; if (std::isinf(RelativeDistanceHistory[Case])) { // TODO (future): if fuzzy is defined in a way that infinity is not 0 it // would be a problem. ConfidenceFromRelativeDistance = 0; } else { ConfidenceFromRelativeDistance = FuzzyFunctionSampleMatches(RelativeDistanceHistory[Case]); } ConfidenceOfWorstFittingSample = fuzzyAND(ConfidenceOfWorstFittingSample, ConfidenceFromRelativeDistance); ConfidenceOfBestCase = fuzzyOR(ConfidenceOfBestCase, fuzzyAND(ConfidenceOfWorstFittingSample, FuzzyFunctionNumOfSamplesMatches( static_cast(Case) + 1))); } TempConfidenceMatching = ConfidenceOfBestCase; return ConfidenceOfBestCase; } /// Gives the confidence how likely the new sample mismatches the signal /// state. /// /// \param Sample is the actual sample of the observed signal. /// /// \return the confidence of the new sample is mismatching the signal state. CONFDATATYPE confidenceSampleMismatchesSignalState(INDATATYPE Sample) noexcept { float ConfidenceOfWorstCase = 1; DynamicLengthHistory RelativeDistanceHistory(SampleHistory.maxLength()); // Calculate distances to all history samples. for (auto &HistorySample : SampleHistory) { RelativeDistanceHistory.addEntry( DistanceMetric(std::make_pair(Sample, HistorySample))); } // Sort all calculated distances so that the highest distance (will get the // lowest confidence) is at the beginning. RelativeDistanceHistory.sortDescending(); CONFDATATYPE ConfidenceOfBestFittingSample = 0; // TODO (future): to accelerate -> don't go until end. Confidences will only // get higher. See comment in "CONFDATATYPE // confidenceSampleMatchesSignalState(INDATATYPE Sample)". // Case 1 means that one (the worst fitting) sample of the history is // compared with the new sample. Case 2 means the two worst history samples // are compared with the new sample. And so on. for (uint32_t Case = 0; Case < RelativeDistanceHistory.numberOfEntries(); Case++) { CONFDATATYPE ConfidenceFromRelativeDistance; if (std::isinf(RelativeDistanceHistory[Case])) { ConfidenceFromRelativeDistance = 1; } else { ConfidenceFromRelativeDistance = FuzzyFunctionSampleMismatches(RelativeDistanceHistory[Case]); } ConfidenceOfBestFittingSample = fuzzyOR(ConfidenceOfBestFittingSample, ConfidenceFromRelativeDistance); ConfidenceOfWorstCase = fuzzyAND(ConfidenceOfWorstCase, fuzzyOR(ConfidenceOfBestFittingSample, FuzzyFunctionNumOfSamplesMismatches( static_cast(Case) + 1))); } TempConfidenceMismatching = ConfidenceOfWorstCase; return ConfidenceOfWorstCase; } /// Gives information about the current signal state. /// /// \return a struct SignalStateInformation that contains information about /// the current signal state. SignalStateInformation signalStateInformation(void) noexcept { return SignalStateInfo; } private: void validateSignalState(INDATATYPE Sample) { // TODO (future): WorstConfidenceDistance and BestConfidenceDistance could // be set already in "CONFDATATYPE // confidenceSampleMatchesSignalState(INDATATYPE Sample)" and "CONFDATATYPE // confidenceSampleMismatchesSignalState(INDATATYPE Sample)" when the new // sample is compared to all history samples. This would save a lot time // because the comparisons are done only once. However, it has to be asured // that the these two functions are called before the insertation, and the // FuzzyFunctions for validation and matching have to be the same! CONFDATATYPE LowestConfidenceMatching = 1; CONFDATATYPE HighestConfidenceMismatching = 0; for (auto &HistorySample : SampleHistory) { // TODO (future): think about using different fuzzy functions for // validation and matching. LowestConfidenceMatching = fuzzyAND(LowestConfidenceMatching, FuzzyFunctionSampleMatches( DistanceMetric(std::make_pair(Sample, HistorySample)))); HighestConfidenceMismatching = fuzzyOR(HighestConfidenceMismatching, FuzzyFunctionSampleMismatches( DistanceMetric(std::make_pair(Sample, HistorySample)))); } LowestConfidenceMatchingHistory.addEntry(LowestConfidenceMatching); HighestConfidenceMismatchingHistory.addEntry(HighestConfidenceMismatching); LowestConfidenceMatching = LowestConfidenceMatchingHistory.lowestEntry(); HighestConfidenceMismatching = HighestConfidenceMismatchingHistory.highestEntry(); SignalStateInfo.ConfidenceStateIsValid = fuzzyAND(LowestConfidenceMatching, FuzzyFunctionNumOfSamplesValid(static_cast( SignalStateInfo.NumberOfInsertedSamplesAfterEntrance))); SignalStateInfo.ConfidenceStateIsInvalid = fuzzyOR(HighestConfidenceMismatching, FuzzyFunctionNumOfSamplesInvalid(static_cast( SignalStateInfo.NumberOfInsertedSamplesAfterEntrance))); if (SignalStateInfo.ConfidenceStateIsValid > SignalStateInfo.ConfidenceStateIsInvalid) { if (SignalStateInfo.StateIsValid) { SignalStateInfo.StateJustGotValid = false; } else { SignalStateInfo.StateJustGotValid = true; } SignalStateInfo.StateIsValid = true; SignalStateInfo.StateIsValidAfterReentrance = true; } } void checkSignalStability(void) { - /* - std::cout << "LookbackTest: " << std::endl; - for (unsigned int t = 1; t <= DriftLookbackRange + 5; t++) { - std::cout << "t=" << t - << " -> c=" << FuzzyFunctionSignalConditionLookBack(t) - << std::endl; - - //(*FuzzyFunctionTimeSystemFunctioning)( - // static_cast(TimeOfDisparity)); - } - getchar(); -*/ - SignalStateInfo.ConfidenceStateIsStable = 0; - SignalStateInfo.ConfidenceStateIsDrifting = 0; + CONFDATATYPE CurrentConfidenceStable = 0; + CONFDATATYPE CurrentConfidenceStateDriftingDown = 0; + CONFDATATYPE CurrentConfidenceStateDriftingUp = 0; - /* - std::cout << "ConfidenceStateIsStable (before): " - << SignalStateInfo.ConfidenceStateIsStable << std::endl; - std::cout << "ConfidenceStateIsDrifting (before): " - << SignalStateInfo.ConfidenceStateIsDrifting << std::endl; -*/ - - bool DriftDirectionIsUp = true; + CONFDATATYPE HistoryConfidenceStable = 0; + CONFDATATYPE HistoryConfidenceStateDriftingDown = 0; + CONFDATATYPE HistoryConfidenceStateDriftingUp = 0; if (DABHistory.numberOfEntries() >= 2) { - // SAVE CHANGES - INDATATYPE CurrentDAB = DABHistory[DABHistory.numberOfEntries() - 1]; - INDATATYPE DAB2Compare = DABHistory[0]; - - // ########### TODO HERE: calculating up_down + DABHistoryEntry CurrentDAB = + DABHistory[DABHistory.numberOfEntries() - 1]; - uint32_t DriftDnCounter = 0; - uint32_t DriftUpCounter = 0; + if (CurrentDAB.DABWasCurrent == false) { - // EXPERIMENTING - for (unsigned int t = 1; - t <= DriftLookbackRange && t < DABHistory.numberOfEntries(); t++) { - - DAB2Compare = DABHistory[DABHistory.numberOfEntries() - (t + 1)]; + DABHistoryEntry DAB2Compare; + // THIS WOULD BE FOR EQUATION NORMALIZATION // TODO: make the following also for distance measurement when comparing // sample with state and validate state /* // sigma correction if (NormalizedDistanceMetric *NormalizableDistanceMetric = dynamic_cast< NormalizedDistanceMetric *>( DistanceMetric)) { // old was safely casted to NewType NormalizableDistanceMetric->setNorm( // TODO: (1) Sigma von Sample // History(!) abholen, (2) irgendwas mit Sigma hier reinschreiben, // und (3) überlegen wegen zweiter History (länger) für // Sigmaberechnung ); } */ - float dist = DistanceMetric(std::make_pair(CurrentDAB, DAB2Compare)); - - // AVG - SignalStateInfo.ConfidenceStateIsStable += - FuzzyFunctionSignalIsStable(dist); - SignalStateInfo.ConfidenceStateIsDrifting += - FuzzyFunctionSignalIsDrifting(dist); - // TODO: move following outside of the loop with - // "if(DriftLookbackRange<=DABHistory.numberOfEntries())" - if (t == DriftLookbackRange) { - SignalStateInfo.ConfidenceStateIsStable /= DriftLookbackRange; - SignalStateInfo.ConfidenceStateIsDrifting /= DriftLookbackRange; - } else if (t == DABHistory.numberOfEntries() - 1) { - SignalStateInfo.ConfidenceStateIsStable /= - DABHistory.numberOfEntries(); - SignalStateInfo.ConfidenceStateIsDrifting /= - DABHistory.numberOfEntries(); + // Iterate through all history DABs + for (unsigned int t = 1; + t <= DriftLookbackRange && t < DABHistory.numberOfEntries(); t++) { + + // Pick one history DAB + DAB2Compare = DABHistory[DABHistory.numberOfEntries() - (t + 1)]; + + // Calculate distance between most recent (completed) DAB and the + // chosen history DAB + PROCDATATYPE dist = DistanceMetric( + std::make_pair(CurrentDAB.AvgValue, DAB2Compare.AvgValue)); + + // Add current confidences for Stable, drift down and drift up + // together + CurrentConfidenceStable += FuzzyFunctionSignalIsStable(dist); + CurrentConfidenceStateDriftingDown += + FuzzyFunctionSignalIsDriftingDown(dist); + CurrentConfidenceStateDriftingUp += + FuzzyFunctionSignalIsDriftingUp(dist); + + // Add history confidences for Stable, drift down and drift up + // together + HistoryConfidenceStable += DAB2Compare.DecisionDABIsStable; + HistoryConfidenceStateDriftingDown += + DAB2Compare.DecisionDABIsDriftingDown; + HistoryConfidenceStateDriftingUp += + DAB2Compare.DecisionDABIsDriftingUp; } - /* - // AND - SignalStateInfo.ConfidenceStateIsStable = - fuzzyOR(SignalStateInfo.ConfidenceStateIsStable, - fuzzyAND(FuzzyFunctionSignalIsStable(dist), - FuzzyFunctionSignalConditionLookBack(t))); - - SignalStateInfo.ConfidenceStateIsDrifting = - fuzzyOR(SignalStateInfo.ConfidenceStateIsDrifting, - fuzzyAND(FuzzyFunctionSignalIsDrifting(dist), - FuzzyFunctionSignalConditionLookBack(t))); - */ - /* - // MULTI - SignalStateInfo.ConfidenceStateIsStable = - fuzzyOR(SignalStateInfo.ConfidenceStateIsStable, - FuzzyFunctionSignalIsStable( - relativeDistance( - CurrentDAB, DAB2Compare)) * - FuzzyFunctionSignalConditionLookBack(t)); - + // chose right divisor for average calculation + unsigned int numOfCompares; + if (DriftLookbackRange <= DABHistory.numberOfEntries()) + numOfCompares = DriftLookbackRange; + else + numOfCompares = + static_cast(DABHistory.numberOfEntries()); + + // calculate the average of the current confidence decision + CurrentConfidenceStable /= numOfCompares; + CurrentConfidenceStateDriftingDown /= numOfCompares; + CurrentConfidenceStateDriftingUp /= numOfCompares; + + // store the current confidence decision in current DAB + CurrentDAB.DecisionDABIsStable = CurrentConfidenceStable; + CurrentDAB.DecisionDABIsDriftingDown = + CurrentConfidenceStateDriftingDown; + CurrentDAB.DecisionDABIsDriftingUp = CurrentConfidenceStateDriftingUp; + CurrentDAB.DABWasCurrent = true; + + // calculate the confidences for SignalStateInfo (current output) + HistoryConfidenceStable = + (HistoryConfidenceStable + CurrentConfidenceStable) / + (numOfCompares + 1); + HistoryConfidenceStateDriftingDown = + (HistoryConfidenceStateDriftingDown + + CurrentConfidenceStateDriftingDown) / + (numOfCompares + 1); + HistoryConfidenceStateDriftingUp = (HistoryConfidenceStateDriftingUp + + CurrentConfidenceStateDriftingUp) / + (numOfCompares + 1); + + // set SignalStateInfo Confidences + SignalStateInfo.ConfidenceStateIsStable = HistoryConfidenceStable; SignalStateInfo.ConfidenceStateIsDrifting = - fuzzyOR(SignalStateInfo.ConfidenceStateIsDrifting, - FuzzyFunctionSignalIsDrifting( - relativeDistance( - CurrentDAB, DAB2Compare)) * - FuzzyFunctionSignalConditionLookBack(t)); - */ - - if (CurrentDAB > DAB2Compare) - DriftUpCounter++; - else if (CurrentDAB < DAB2Compare) - DriftDnCounter++; - } - // TODO: change something because it is biased if the are equal - DriftDirectionIsUp = DriftUpCounter > DriftDnCounter; - - // following outcommented block was the published code - /* - SignalStateInfo.ConfidenceStateIsStable = - FuzzyFunctionSignalIsStable( - relativeDistance(CurrentDAB, - DAB2Compare)); - SignalStateInfo.ConfidenceStateIsDrifting = - FuzzyFunctionSignalIsDrifting( - relativeDistance(CurrentDAB, - DAB2Compare)); - // TODO: think about a better solution with different confidences - // (stable, up, down, ...) - DriftDirectionIsUp = CurrentDAB > DAB2Compare; - */ - // - SAVE CHANGES - } - - /* - std::cout << "ConfidenceStateIsStable (after): " - << SignalStateInfo.ConfidenceStateIsStable << std::endl; - std::cout << "ConfidenceStateIsDrifting (after): " - << SignalStateInfo.ConfidenceStateIsDrifting << std::endl; - */ - - if (SignalStateInfo.ConfidenceStateIsStable > - SignalStateInfo.ConfidenceStateIsDrifting) { - SignalStateInfo.StateCondition = StateConditions::STABLE; - } else if (SignalStateInfo.ConfidenceStateIsStable < - SignalStateInfo.ConfidenceStateIsDrifting) { - - if (DriftDirectionIsUp) { - SignalStateInfo.StateCondition = StateConditions::DRIFTING_UP; - } else { - SignalStateInfo.StateCondition = StateConditions::DRIFTING_DN; + HistoryConfidenceStateDriftingDown > + HistoryConfidenceStateDriftingUp + ? HistoryConfidenceStateDriftingDown + : HistoryConfidenceStateDriftingUp; + SignalStateInfo.ConfidenceStateIsDriftingDown = + HistoryConfidenceStateDriftingDown; + SignalStateInfo.ConfidenceStateIsDriftingUp = + HistoryConfidenceStateDriftingUp; + + // set SignalStateInfo StateCondition + if (SignalStateInfo.ConfidenceStateIsStable > + SignalStateInfo.ConfidenceStateIsDrifting) + SignalStateInfo.StateCondition = StateConditions::STABLE; + else if (SignalStateInfo.ConfidenceStateIsStable < + SignalStateInfo.ConfidenceStateIsDrifting) + if (SignalStateInfo.ConfidenceStateIsDriftingDown > + SignalStateInfo.ConfidenceStateIsDriftingUp) + SignalStateInfo.StateCondition = StateConditions::DRIFTING_DN; + else if (SignalStateInfo.ConfidenceStateIsDriftingDown < + SignalStateInfo.ConfidenceStateIsDriftingUp) + SignalStateInfo.StateCondition = StateConditions::DRIFTING_UP; + else + SignalStateInfo.StateCondition = StateConditions::UNKNOWN; + else + SignalStateInfo.StateCondition = StateConditions::UNKNOWN; } - /* - SignalStateInfo.StateCondition = StateConditions::DRIFTING; - */ } else { + SignalStateInfo.ConfidenceStateIsStable = 0; + SignalStateInfo.ConfidenceStateIsDrifting = 0; + SignalStateInfo.ConfidenceStateIsDriftingDown = 0; + SignalStateInfo.ConfidenceStateIsDriftingUp = 0; SignalStateInfo.StateCondition = StateConditions::UNKNOWN; } } }; // namespace agent } // namespace agent } // End namespace rosa #endif // ROSA_AGENT_SIGNALSTATE_HPP diff --git a/include/rosa/agent/SignalStateDetector.hpp b/include/rosa/agent/SignalStateDetector.hpp index 795f84a..d8437c5 100644 --- a/include/rosa/agent/SignalStateDetector.hpp +++ b/include/rosa/agent/SignalStateDetector.hpp @@ -1,338 +1,348 @@ //===-- 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 { using StateDetector = StateDetector; - using DistanceMetricAbstraction = typename StateDetector::DistanceMetricAbstraction; + using DistanceMetricAbstraction = + typename StateDetector::DistanceMetricAbstraction; 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 metric to calculate the distance between two points DistanceMetricAbstraction DistanceMetric; /// The FuzzyFunctionSampleMatches is the fuzzy function that gives the /// confidence how good the new sample matches another sample in the sample /// history. This is done to evaluate whether one sample belongs to an /// existing state. PartFuncPointer FuzzyFunctionSampleMatches; /// The FuzzyFunctionSampleMismatches is the fuzzy function that gives the /// confidence how bad the new sample matches another sample in the sample /// history. This is done to evaluate whether one sample does not belong to an /// existing state. PartFuncPointer FuzzyFunctionSampleMismatches; /// The FuzzyFunctionNumOfSamplesMatches is the fuzzy function that gives the /// confidence how many samples from the sample history match the new sample. /// This is done to evaluate whether one sample belongs to an existing state. StepFuncPointer FuzzyFunctionNumOfSamplesMatches; /// The FuzzyFunctionNumOfSamplesMismatches is the fuzzy function that gives /// the confidence how many samples from the sample history mismatch the new /// sample. This is done to evaluate whether one sample does not belong to an /// existing state. StepFuncPointer FuzzyFunctionNumOfSamplesMismatches; /// The FuzzyFunctionSampleValid is the fuzzy function that gives the /// confidence how good one matches another sample in the sample /// history. This is done to evaluate whether a state is valid. PartFuncPointer FuzzyFunctionSampleValid; /// The FuzzyFunctionSampleInvalid is the fuzzy function that gives the /// confidence how bad one sample matches another sample in the sample /// history. This is done to evaluate whether a state is invalid. PartFuncPointer FuzzyFunctionSampleInvalid; /// The FuzzyFunctionNumOfSamplesValid is the fuzzy function that gives the /// confidence how many samples from the sample history match another sample. /// This is done to evaluate whether a state is valid. StepFuncPointer FuzzyFunctionNumOfSamplesValid; /// The FuzzyFunctionNumOfSamplesInvalid is the fuzzy function that gives /// the confidence how many samples from the sample history mismatch another /// sample. This is done to evaluate whether a state is invalid. StepFuncPointer FuzzyFunctionNumOfSamplesInvalid; - /// The FuzzyFunctionSignalIsDrifting is the fuzzy function that gives the - /// confidence how likely it is that the signal is drifting. - PartFuncPointer FuzzyFunctionSignalIsDrifting; + /// The FuzzyFunctionSignalIsDriftingDown is the fuzzy function that gives the + /// confidence how likely it is that the signal is drifting down. + PartFuncPointer FuzzyFunctionSignalIsDriftingDown; + + /// The FuzzyFunctionSignalIsDriftingUp is the fuzzy function that gives the + /// confidence how likely it is that the signal is drifting up. + PartFuncPointer FuzzyFunctionSignalIsDriftingUp; /// The FuzzyFunctionSignalIsStable is the fuzzy function that gives the /// confidence how likely it is that the signal is stable (not drifting). PartFuncPointer FuzzyFunctionSignalIsStable; /// TODO: describe std::shared_ptr> FuzzyFunctionSignalConditionLookBack; /// TODO: describe std::shared_ptr> FuzzyFunctionSignalConditionHistoryDesicion; - /// TODO: describe + /// TODO: describe -> how man steps back in comparison and is also size of + /// DABhistory uint32_t DriftLookbackRange; /// 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 DistanceMetric The metric to calculate the distance between two points + /// \param DistanceMetric The metric to calculate the distance between two + /// points /// /// \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 FuzzyFunctionSignalIsDriftingDown The + /// FuzzyFunctionSignalIsDriftingDown is the fuzzy function that gives the + /// confidence how likely it is that the signal (resp. the state of a signal) + /// is drifting down. + /// + /// \param FuzzyFunctionSignalIsDriftingUp The FuzzyFunctionSignalIsDriftingUp + /// is the fuzzy function that gives the confidence how likely it is that the + /// signal (resp. the state of a signal) is drifting up. /// /// \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, DistanceMetricAbstraction DistanceMetric, PartFuncPointer FuzzyFunctionSampleMatches, PartFuncPointer FuzzyFunctionSampleMismatches, StepFuncPointer FuzzyFunctionNumOfSamplesMatches, StepFuncPointer FuzzyFunctionNumOfSamplesMismatches, PartFuncPointer FuzzyFunctionSampleValid, PartFuncPointer FuzzyFunctionSampleInvalid, StepFuncPointer FuzzyFunctionNumOfSamplesValid, StepFuncPointer FuzzyFunctionNumOfSamplesInvalid, - PartFuncPointer FuzzyFunctionSignalIsDrifting, + PartFuncPointer FuzzyFunctionSignalIsDriftingDown, + PartFuncPointer FuzzyFunctionSignalIsDriftingUp, PartFuncPointer FuzzyFunctionSignalIsStable, std::shared_ptr> FuzzyFunctionSignalConditionLookBack, std::shared_ptr> FuzzyFunctionSignalConditionHistoryDesicion, - uint32_t DriftLookbackRange, uint32_t SampleHistorySize, - uint32_t DABSize, uint32_t DABHistorySize) noexcept + uint32_t DriftLookbackRange, + uint32_t SampleHistorySize) noexcept : SignalProperty(SignalProperty), CurrentSignalState(nullptr), DetectedSignalStates(MaximumNumberOfSignalStates), DistanceMetric(DistanceMetric), FuzzyFunctionSampleMatches(FuzzyFunctionSampleMatches), FuzzyFunctionSampleMismatches(FuzzyFunctionSampleMismatches), FuzzyFunctionNumOfSamplesMatches(FuzzyFunctionNumOfSamplesMatches), FuzzyFunctionNumOfSamplesMismatches( FuzzyFunctionNumOfSamplesMismatches), FuzzyFunctionSampleValid(FuzzyFunctionSampleValid), FuzzyFunctionSampleInvalid(FuzzyFunctionSampleInvalid), FuzzyFunctionNumOfSamplesValid(FuzzyFunctionNumOfSamplesValid), FuzzyFunctionNumOfSamplesInvalid(FuzzyFunctionNumOfSamplesInvalid), - FuzzyFunctionSignalIsDrifting(FuzzyFunctionSignalIsDrifting), + FuzzyFunctionSignalIsDriftingDown(FuzzyFunctionSignalIsDriftingDown), + FuzzyFunctionSignalIsDriftingUp(FuzzyFunctionSignalIsDriftingUp), FuzzyFunctionSignalIsStable(FuzzyFunctionSignalIsStable), FuzzyFunctionSignalConditionLookBack( FuzzyFunctionSignalConditionLookBack), FuzzyFunctionSignalConditionHistoryDesicion( FuzzyFunctionSignalConditionHistoryDesicion), DriftLookbackRange(DriftLookbackRange), - SampleHistorySize(SampleHistorySize), DABSize(DABSize), - DABHistorySize(DABHistorySize) { + SampleHistorySize(SampleHistorySize) { 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 this function to an operator()-function SignalStateInformation detectSignalState(INDATATYPE Sample) noexcept { if (!CurrentSignalState) { 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; if (this->StateHasChanged) { if (CurrentSignalState->signalStateInformation().StateIsValid) CurrentSignalState->leaveSignalState(); else DetectedSignalStates.deleteEntry(CurrentSignalState); // TODO (future): additionally save averages to enable fast iteration // through recorded signl state history (maybe sort vector based on // these average values) CurrentSignalState = nullptr; 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) { SignalStatePtr S = createNewSignalState(); CurrentSignalState = S; } } } SignalStateInformation SignalStateInfo = CurrentSignalState->insertSample(Sample); 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, *DistanceMetric, *FuzzyFunctionSampleMatches, + *DistanceMetric, *FuzzyFunctionSampleMatches, *FuzzyFunctionSampleMismatches, *FuzzyFunctionNumOfSamplesMatches, *FuzzyFunctionNumOfSamplesMismatches, *FuzzyFunctionSampleValid, *FuzzyFunctionSampleInvalid, *FuzzyFunctionNumOfSamplesValid, - *FuzzyFunctionNumOfSamplesInvalid, *FuzzyFunctionSignalIsDrifting, - *FuzzyFunctionSignalIsStable, *FuzzyFunctionSignalConditionLookBack, + *FuzzyFunctionNumOfSamplesInvalid, *FuzzyFunctionSignalIsDriftingDown, + *FuzzyFunctionSignalIsDriftingUp, *FuzzyFunctionSignalIsStable, + *FuzzyFunctionSignalConditionLookBack, *FuzzyFunctionSignalConditionHistoryDesicion, DriftLookbackRange)); DetectedSignalStates.addEntry(S); return S; } }; } // End namespace agent } // End namespace rosa #endif // ROSA_AGENT_SIGNALSTATEDETECTOR_HPP diff --git a/include/rosa/agent/State.hpp b/include/rosa/agent/State.hpp index ca267b5..ae4c775 100644 --- a/include/rosa/agent/State.hpp +++ b/include/rosa/agent/State.hpp @@ -1,97 +1,99 @@ //===-- rosa/agent/State.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/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_DN = '2', ///< The state is drifting down DRIFTING = '3', ///< The state is drifting down or up DRIFTING_UP = '4', ///< The state is drifting up MALFUNCTIONING = '5' ///< 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 ConfidenceStateIsValid; CONFDATATYPE ConfidenceStateIsInvalid; CONFDATATYPE ConfidenceStateIsStable; CONFDATATYPE ConfidenceStateIsDrifting; + CONFDATATYPE ConfidenceStateIsDriftingDown; + CONFDATATYPE ConfidenceStateIsDriftingUp; }; 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