Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F386396
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Size
80 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/apps/ccam/ccam.cpp b/apps/ccam/ccam.cpp
index 8d157a2..4501cd5 100644
--- a/apps/ccam/ccam.cpp
+++ b/apps/ccam/ccam.cpp
@@ -1,565 +1,576 @@
//===-- 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 <iostream>
#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 <fstream>
#include <limits>
#include <memory>
#include <streambuf>
+#include <string>
#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<Application> 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<PartialFunction<uint32_t, float>> BrokenDelayFunction(
new PartialFunction<uint32_t, float>(
{{{0, AppConfig.BrokenCounter},
std::make_shared<LinearFunction<uint32_t, float>>(
0, 0.f, AppConfig.BrokenCounter, 1.f)},
{{AppConfig.BrokenCounter, std::numeric_limits<uint32_t>::max()},
std::make_shared<LinearFunction<uint32_t, float>>(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<PartialFunction<uint32_t, float>> OkDelayFunction(
new PartialFunction<uint32_t, float>(
{{{0, AppConfig.BrokenCounter},
std::make_shared<LinearFunction<uint32_t, float>>(
0, 1.f, AppConfig.BrokenCounter, 0.f)},
{{AppConfig.BrokenCounter, std::numeric_limits<uint32_t>::max()},
std::make_shared<LinearFunction<uint32_t, float>>(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<size_t> 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<AgentHandle> Sensors;
+ std::vector<std::shared_ptr<Abstraction<std::pair<float, float>, float>>> DistanceMetrics;
std::vector<std::shared_ptr<PartialFunction<float, float>>>
SampleMatchesFunctions;
std::vector<std::shared_ptr<PartialFunction<float, float>>>
SampleMismatchesFunctions;
std::vector<std::shared_ptr<PartialFunction<float, float>>>
SignalIsStableFunctions;
std::vector<std::shared_ptr<PartialFunction<float, float>>>
SignalIsDriftingFunctions;
std::vector<std::shared_ptr<StepFunction<float, float>>>
NumOfSamplesMatchFunctions;
std::vector<std::shared_ptr<StepFunction<float, float>>>
NumOfSamplesMismatchFunctions;
std::vector<std::shared_ptr<PartialFunction<float, float>>>
SampleValidFunctions;
std::vector<std::shared_ptr<PartialFunction<float, float>>>
SampleInvalidFunctions;
std::vector<std::shared_ptr<StepFunction<float, float>>>
NumOfSamplesValidFunctions;
std::vector<std::shared_ptr<StepFunction<float, float>>>
NumOfSamplesInvalidFunctions;
std::vector<std::shared_ptr<
SignalStateDetector<float, float, float, HistoryPolicy::FIFO>>>
SignalStateDetectors;
std::vector<AgentHandle> SignalStateDetectorAgents;
std::vector<std::ifstream> 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<float>(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<float, float>());
+ } else {
+ //default is relative distance
+ DistanceMetrics.emplace_back(new RelativeDistance<float, float>());
+ }
+
SampleMatchesFunctions.emplace_back(new PartialFunction<float, float>(
{
{{-SignalConfiguration.OuterBound, -SignalConfiguration.InnerBound},
std::make_shared<LinearFunction<float, float>>(
-SignalConfiguration.OuterBound, 0.f,
-SignalConfiguration.InnerBound, 1.f)},
{{-SignalConfiguration.InnerBound, SignalConfiguration.InnerBound},
std::make_shared<LinearFunction<float, float>>(1.f, 0.f)},
{{SignalConfiguration.InnerBound, SignalConfiguration.OuterBound},
std::make_shared<LinearFunction<float, float>>(
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<float, float>(
{
{{-SignalConfiguration.OuterBound, -SignalConfiguration.InnerBound},
std::make_shared<LinearFunction<float, float>>(
-SignalConfiguration.OuterBound, 1.f,
-SignalConfiguration.InnerBound, 0.f)},
{{-SignalConfiguration.InnerBound, SignalConfiguration.InnerBound},
std::make_shared<LinearFunction<float, float>>(0.f, 0.f)},
{{SignalConfiguration.InnerBound, SignalConfiguration.OuterBound},
std::make_shared<LinearFunction<float, float>>(
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<float, float>(
{
{{-SignalConfiguration.OuterBoundDrift,
-SignalConfiguration.InnerBoundDrift},
std::make_shared<LinearFunction<float, float>>(
-SignalConfiguration.OuterBoundDrift, 0.f,
-SignalConfiguration.InnerBoundDrift, 1.f)},
{{-SignalConfiguration.InnerBoundDrift,
SignalConfiguration.InnerBoundDrift},
std::make_shared<LinearFunction<float, float>>(1.f, 0.f)},
{{SignalConfiguration.InnerBoundDrift,
SignalConfiguration.OuterBoundDrift},
std::make_shared<LinearFunction<float, float>>(
SignalConfiguration.InnerBoundDrift, 1.f,
SignalConfiguration.OuterBoundDrift, 0.f)},
},
0));
//
// Create following function(s) which shall give information whether a
// signal is drifting.
//
// ____________ ____________
// \ /
// \ /
// \__________/
//
//
SignalIsDriftingFunctions.emplace_back(new PartialFunction<float, float>(
{
{{-SignalConfiguration.OuterBoundDrift,
-SignalConfiguration.InnerBoundDrift},
std::make_shared<LinearFunction<float, float>>(
-SignalConfiguration.OuterBoundDrift, 1.f,
-SignalConfiguration.InnerBoundDrift, 0.f)},
{{-SignalConfiguration.InnerBoundDrift,
SignalConfiguration.InnerBoundDrift},
std::make_shared<LinearFunction<float, float>>(0.f, 0.f)},
{{SignalConfiguration.InnerBoundDrift,
SignalConfiguration.OuterBoundDrift},
std::make_shared<LinearFunction<float, float>>(
SignalConfiguration.InnerBoundDrift, 0.f,
SignalConfiguration.OuterBoundDrift, 1.f)},
},
1));
//
// Create following function(s) which shall give information how many
// history samples match another sample.
//
// ____________
// /
// /
// __________/
//
NumOfSamplesMatchFunctions.emplace_back(new StepFunction<float, float>(
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<float, float>(
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<float, float>(
{
{{-SignalConfiguration.OuterBound, -SignalConfiguration.InnerBound},
std::make_shared<LinearFunction<float, float>>(
-SignalConfiguration.OuterBound, 0.f,
-SignalConfiguration.InnerBound, 1.f)},
{{-SignalConfiguration.InnerBound, SignalConfiguration.InnerBound},
std::make_shared<LinearFunction<float, float>>(1.f, 0.f)},
{{SignalConfiguration.InnerBound, SignalConfiguration.OuterBound},
std::make_shared<LinearFunction<float, float>>(
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<float, float>(
{
{{-SignalConfiguration.OuterBound, -SignalConfiguration.InnerBound},
std::make_shared<LinearFunction<float, float>>(
-SignalConfiguration.OuterBound, 1.f,
-SignalConfiguration.InnerBound, 0.f)},
{{-SignalConfiguration.InnerBound, SignalConfiguration.InnerBound},
std::make_shared<LinearFunction<float, float>>(0.f, 0.f)},
{{SignalConfiguration.InnerBound, SignalConfiguration.OuterBound},
std::make_shared<LinearFunction<float, float>>(
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<float, float>(
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<float, float>(
1.0f / SignalConfiguration.SampleHistorySize, StepDirection::StepDown));
//
// Create SignalStateDetector functionality
//
SignalStateDetectors.emplace_back(
new SignalStateDetector<float, float, float, HistoryPolicy::FIFO>(
SignalConfiguration.Output ? SignalProperties::OUTPUT
: SignalProperties::INPUT,
- std::numeric_limits<int>::max(), SampleMatchesFunctions.back(),
+ std::numeric_limits<int>::max(), DistanceMetrics.back(), SampleMatchesFunctions.back(),
SampleMismatchesFunctions.back(), NumOfSamplesMatchFunctions.back(),
NumOfSamplesMismatchFunctions.back(), SampleValidFunctions.back(),
SampleInvalidFunctions.back(), NumOfSamplesValidFunctions.back(),
NumOfSamplesInvalidFunctions.back(),
SignalIsDriftingFunctions.back(), SignalIsStableFunctions.back(),
SignalConfiguration.SampleHistorySize, SignalConfiguration.DABSize,
SignalConfiguration.DABHistorySize));
//
// 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<SystemStateTuple, bool>;
using Result = Optional<AppTuple<unit_t>>;
using Handler = std::function<Result(Input)>;
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<const std::tuple<std::string> &>(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<float>(DataFiles.at(i)),
csv::CSVIterator<float>());
LOG_INFO_STREAM << "Sensor " << SignalConfiguration.Name
<< " is fed by csv file " << SignalConfiguration.InputPath
<< std::endl;
break;
case DataInterfaceTypes::MQTT: {
hasMQTT = true;
auto it = MQTTIterator<float>(SignalConfiguration.MQTTTopic);
AppCCAM->registerSensorValues(Sensors.at(i), std::move(it),
MQTTIterator<float>());
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 3058baa..c55a7b0 100644
--- a/apps/ccam/configuration.h
+++ b/apps/ccam/configuration.h
@@ -1,97 +1,99 @@
#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 <fstream>
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;
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<SignalConfiguration> 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);
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/DistanceMetrics.hpp b/include/rosa/agent/DistanceMetrics.hpp
new file mode 100644
index 0000000..8b11679
--- /dev/null
+++ b/include/rosa/agent/DistanceMetrics.hpp
@@ -0,0 +1,139 @@
+//===-- rosa/agent/DistanceMetrics.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/DistanceMetrics.hpp
+///
+/// \author Benedikt Tutzer (benedikt.tutzer@tuwien.ac.at)
+///
+/// \date 2020
+///
+/// \brief Definition of *DistanceMetrics* *functionality*.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef ROSA_AGENT_DISTANCEMETRICS_HPP
+#define ROSA_AGENT_DISTANCEMETRICS_HPP
+
+#include "rosa/agent/Abstraction.hpp"
+#include "rosa/agent/Functionality.h"
+
+#include "rosa/support/debug.hpp"
+
+
+namespace rosa {
+namespace agent {
+
+/// Implements \c rosa::agent::Abstraction as the absolute difference between
+/// two values
+///
+/// \note This implementation is supposed to be used to represent a difference-metric
+/// function from an arithmetic domain to an arithmetic range. This is enforced
+/// statically.
+///
+/// \tparam D type of the input values
+/// \tparam R type of the difference
+template <typename D, typename R>
+class AbsoluteDistance : public Abstraction<std::pair<D, D>, R> {
+ // Make sure the actual type arguments are matching our expectations.
+ STATIC_ASSERT((std::is_arithmetic<D>::value), "abstracting not arithmetic");
+ STATIC_ASSERT((std::is_arithmetic<R>::value),
+ "abstracting not to arithmetic");
+
+public:
+ /// Creates an instance by Initializing the underlying \c Abstraction.
+ AbsoluteDistance(void) : Abstraction<std::pair<D, D>, R>(0) { }
+
+ /// Destroys \p this object.
+ ~AbsoluteDistance(void) = default;
+
+ /// Checks wether the Abstraction evaluates to default at the given position
+ ///
+ /// \param V the value at which to check if the function falls back to it's
+ /// default value.
+ ///
+ /// \return false if the value falls into a defined range and the Abstraction
+ /// defined for that range does not fall back to it's default value.
+ bool isDefaultAt(const std::pair<D, D> &V) const noexcept override {
+ (void)(V);
+ return false;
+ }
+
+ /// Calculates the distance-metric for the given value. If this is the first
+ /// value, the Default-Value is returned
+ ///
+ /// \param V value to abstract
+ ///
+ /// \return the absolute distanct
+ R operator()(const std::pair<D, D> &V) const noexcept override {
+ return V.first - V.second;
+ }
+};
+
+/// Implements \c rosa::agent::Abstraction as the relative difference between
+/// two values
+///
+/// \note This implementation is supposed to be used to represent a difference-metric
+/// function from an arithmetic domain to an arithmetic range. This is enforced
+/// statically.
+///
+/// \tparam D type of the input values
+/// \tparam R type of the difference
+template <typename D, typename R>
+class RelativeDistance : public Abstraction<std::pair<D, D>, R> {
+ // Make sure the actual type arguments are matching our expectations.
+ STATIC_ASSERT((std::is_arithmetic<D>::value), "abstracting not arithmetic");
+ STATIC_ASSERT((std::is_arithmetic<R>::value),
+ "abstracting not to arithmetic");
+
+public:
+ /// Creates an instance by Initializing the underlying \c Abstraction.
+ RelativeDistance(void) : Abstraction<std::pair<D, D>, R>(0) { }
+
+ /// Destroys \p this object.
+ ~RelativeDistance(void) = default;
+
+ /// Checks wether the Abstraction evaluates to default at the given position
+ ///
+ /// \param V the value at which to check if the function falls back to it's
+ /// default value.
+ ///
+ /// \return false if the value falls into a defined range and the Abstraction
+ /// defined for that range does not fall back to it's default value.
+ bool isDefaultAt(const std::pair<D, D> &V) const noexcept override {
+ (void)(V);
+ return false;
+ }
+
+ /// Calculates the distance-metric for the given value. If this is the first
+ /// value, the Default-Value is returned
+ ///
+ /// \param V value to abstract
+ ///
+ /// \return the absolute distanct
+ R operator()(const std::pair<D, D> &V) const noexcept override {
+ R Dist = ((R)V.second) - V.first;
+ if (Dist == 0) {
+ return 0;
+ } else {
+ Dist = Dist / V.first;
+ if (Dist < 0) {
+ return -Dist;
+ }
+ }
+ return Dist;
+ }
+};
+
+} // End namespace agent
+} // End namespace rosa
+
+#endif // ROSA_AGENT_DISTANCEMETRICS_HPP
diff --git a/include/rosa/agent/SignalState.hpp b/include/rosa/agent/SignalState.hpp
index 76b4d8e..4d0256f 100644
--- a/include/rosa/agent/SignalState.hpp
+++ b/include/rosa/agent/SignalState.hpp
@@ -1,649 +1,659 @@
//===-- 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 <typename CONFDATATYPE>
struct SignalStateInformation : StateInformation<CONFDATATYPE> {
// Make sure the actual type arguments are matching our expectations.
STATIC_ASSERT((std::is_arithmetic<CONFDATATYPE>::value),
"confidence type is not to arithmetic");
/// ConfidenceOfMatchingState is the confidence how good the new sample
/// matches the state.
CONFDATATYPE ConfidenceOfMatchingState;
/// ConfidenceOfMatchingState is the confidence how bad the new sample
/// matches the state.
CONFDATATYPE ConfidenceOfMismatchingState;
/// The SignalProperty saves whether the monitored signal is an input our
/// output signal.
SignalProperties SignalProperty;
/// The SignalStateIsValid saves the number of samples which have been
/// inserted into the state after entering it.
uint32_t NumberOfInsertedSamplesAfterEntrance;
public:
SignalStateInformation(unsigned int SignalStateID,
SignalProperties _SignalProperty) {
this->StateID = SignalStateID;
this->SignalProperty = _SignalProperty;
this->StateCondition = StateConditions::UNKNOWN;
this->NumberOfInsertedSamplesAfterEntrance = 0;
this->StateIsValid = false;
this->StateJustGotValid = false;
this->StateIsValidAfterReentrance = false;
this->ConfidenceStateIsValid = 0;
this->ConfidenceStateIsInvalid = 0;
this->ConfidenceStateIsStable = 0;
this->ConfidenceStateIsDrifting = 0;
}
SignalStateInformation() = default;
};
/// \tparam INDATATYPE type of input data, \tparam CONFDATATYPE type of
/// data in that the confidence values are given, \tparam PROCDATATYPE type of
/// the relative distance and the type of data in which DABs are saved.
template <typename INDATATYPE, typename CONFDATATYPE, typename PROCDATATYPE>
class SignalState : public Functionality {
// Make sure the actual type arguments are matching our expectations.
STATIC_ASSERT((std::is_arithmetic<INDATATYPE>::value),
"input data type not arithmetic");
STATIC_ASSERT((std::is_arithmetic<CONFDATATYPE>::value),
"confidence data type is not to arithmetic");
STATIC_ASSERT(
(std::is_arithmetic<PROCDATATYPE>::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<std::pair<INDATATYPE, INDATATYPE>, PROCDATATYPE> &;
// For the convinience to write a shorter data type name
using PartFuncReference = PartialFunction<INDATATYPE, CONFDATATYPE> &;
// using PartFuncReference2 = ;
using StepFuncReference = StepFunction<INDATATYPE, CONFDATATYPE> &;
private:
/// SignalStateInfo is a struct of SignalStateInformation that contains
/// information about the current signal state.
SignalStateInformation<CONFDATATYPE> SignalStateInfo;
+ /// The metric to calculate the distance between two points
+ DistanceMetricAbstraction DistanceMetric;
+
/// The FuzzyFunctionSampleMatches is the fuzzy function that gives the
/// confidence how good the new sample matches another sample in the sample
/// history.
PartFuncReference FuzzyFunctionSampleMatches;
/// The FuzzyFunctionSampleMismatches is the fuzzy function that gives the
/// confidence how bad the new sample matches another sample in the sample
/// history.
PartFuncReference FuzzyFunctionSampleMismatches;
/// The FuzzyFunctionNumOfSamplesMatches is the fuzzy function that gives the
/// confidence how many samples from the sampe history match the new sample.
StepFuncReference FuzzyFunctionNumOfSamplesMatches;
/// The FuzzyFunctionNumOfSamplesMismatches is the fuzzy function that gives
/// the confidence how many samples from the sampe history mismatch the new
/// sample.
StepFuncReference FuzzyFunctionNumOfSamplesMismatches;
/// The FuzzyFunctionSampleValid is the fuzzy function that gives the
/// confidence how good one matches another sample in the sample
/// history. This is done to evaluate whether a state is valid.
PartFuncReference FuzzyFunctionSampleValid;
/// The FuzzyFunctionSampleInvalid is the fuzzy function that gives the
/// confidence how bad one sample matches another sample in the sample
/// history. This is done to evaluate whether a state is invalid.
PartFuncReference FuzzyFunctionSampleInvalid;
/// The FuzzyFunctionNumOfSamplesValid is the fuzzy function that gives the
/// confidence how many samples from the sample history match another sample.
/// This is done to evaluate whether a state is valid.
StepFuncReference FuzzyFunctionNumOfSamplesValid;
/// The FuzzyFunctionNumOfSamplesInvalid is the fuzzy function that gives
/// the confidence how many samples from the sample history mismatch another
/// sample. This is done to evaluate whether a state is invalid.
StepFuncReference FuzzyFunctionNumOfSamplesInvalid;
/// The FuzzyFunctionSignalIsDrifting is the fuzzy function that gives the
/// confidence how likely it is that the signal (resp. the state of a signal)
/// is drifting.
PartFuncReference FuzzyFunctionSignalIsDrifting;
/// The FuzzyFunctionSignalIsStable is the fuzzy function that gives the
/// confidence how likely it is that the signal (resp. the state of a signal)
/// is stable (not drifting).
PartFuncReference FuzzyFunctionSignalIsStable;
/// TODO: description
// PartialFunction<uint32_t, float> &FuzzyFunctionSignalConditionLookBack;
/// TODO: description
// PartialFunction<uint32_t, float>
// &FuzzyFunctionSignalConditionHistoryDesicion;
/// TODO: description
// uint32_t DriftLookbackRange;
/// SampleHistory is a history in that the last sample values are stored.
DynamicLengthHistory<INDATATYPE, HistoryPolicy::FIFO> SampleHistory;
/// DAB is a (usually) small history of the last sample values of which a
/// average is calculated if the DAB is full.
DynamicLengthHistory<INDATATYPE, HistoryPolicy::SRWF> DAB;
/// DABHistory is a history in that the last DABs (to be exact, the averages
/// of the last DABs) are stored.
DynamicLengthHistory<PROCDATATYPE, HistoryPolicy::LIFO> DABHistory;
/// LowestConfidenceMatchingHistory is a history in that the lowest confidence
/// for the current sample matches all history samples are saved.
DynamicLengthHistory<INDATATYPE, HistoryPolicy::FIFO>
LowestConfidenceMatchingHistory;
/// HighestConfidenceMatchingHistory is a history in that the highest
/// confidence for the current sample matches all history samples are saved.
DynamicLengthHistory<INDATATYPE, HistoryPolicy::FIFO>
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 FuzzyFunctionSignalIsStable The FuzzyFunctionSignalIsStable is the
/// fuzzy function that gives the confidence how likely it is that the signal
/// (resp. the state of a signal) is stable (not drifting).
///
/// \param SampleHistorySize Size of the Sample History \c
/// DynamicLengthHistory . SampleHistory is a history in that the last sample
/// values are stored.
///
/// \param DABSize Size of DAB \c DynamicLengthHistory . DAB is a (usually)
/// small history of the last sample values of which a average is calculated
/// if the DAB is full.
///
/// \param DABHistorySize Size of the DABHistory \c DynamicLengthHistory .
/// DABHistory is a history in that the last DABs (to be exact, the averages
/// of the last DABs) are stored.
///
SignalState(
uint32_t SignalStateID, SignalProperties SignalProperty,
uint32_t SampleHistorySize, uint32_t DABSize, uint32_t DABHistorySize,
+ DistanceMetricAbstraction DistanceMetric,
PartFuncReference FuzzyFunctionSampleMatches,
PartFuncReference FuzzyFunctionSampleMismatches,
StepFuncReference FuzzyFunctionNumOfSamplesMatches,
StepFuncReference FuzzyFunctionNumOfSamplesMismatches,
PartFuncReference FuzzyFunctionSampleValid,
PartFuncReference FuzzyFunctionSampleInvalid,
StepFuncReference FuzzyFunctionNumOfSamplesValid,
StepFuncReference FuzzyFunctionNumOfSamplesInvalid,
PartFuncReference FuzzyFunctionSignalIsDrifting,
PartFuncReference FuzzyFunctionSignalIsStable //,
// PartialFunction<uint32_t, float> &FuzzyFunctionSignalConditionLookBack,
// PartialFunction<uint32_t, float>
// &FuzzyFunctionSignalConditionHistoryDesicion,
// uint32_t DriftLookbackRange
) noexcept
: SignalStateInfo{SignalStateID, SignalProperty},
+ DistanceMetric(DistanceMetric),
FuzzyFunctionSampleMatches(FuzzyFunctionSampleMatches),
FuzzyFunctionSampleMismatches(FuzzyFunctionSampleMismatches),
FuzzyFunctionNumOfSamplesMatches(FuzzyFunctionNumOfSamplesMatches),
FuzzyFunctionNumOfSamplesMismatches(
FuzzyFunctionNumOfSamplesMismatches),
FuzzyFunctionSampleValid(FuzzyFunctionSampleValid),
FuzzyFunctionSampleInvalid(FuzzyFunctionSampleInvalid),
FuzzyFunctionNumOfSamplesValid(FuzzyFunctionNumOfSamplesValid),
FuzzyFunctionNumOfSamplesInvalid(FuzzyFunctionNumOfSamplesInvalid),
FuzzyFunctionSignalIsDrifting(FuzzyFunctionSignalIsDrifting),
FuzzyFunctionSignalIsStable(FuzzyFunctionSignalIsStable),
// FuzzyFunctionSignalConditionLookBack(
// FuzzyFunctionSignalConditionLookBack),
// FuzzyFunctionSignalConditionHistoryDesicion(
// FuzzyFunctionSignalConditionHistoryDesicion),
// DriftLookbackRange(DriftLookbackRange),
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<CONFDATATYPE>
insertSample(INDATATYPE Sample) noexcept {
SignalStateInfo.NumberOfInsertedSamplesAfterEntrance++;
validateSignalState(Sample);
SampleHistory.addEntry(Sample);
DAB.addEntry(Sample);
if (DAB.full()) {
// Experiment -> exchanged next line with the folowings
// PROCDATATYPE AvgOfDAB = DAB.template average<PROCDATATYPE>();
// 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<PROCDATATYPE>();
PROCDATATYPE AvgOfDAB = DAB.template average<PROCDATATYPE>();
DABHistory.addEntry(AvgOfDAB);
DAB.clear();
}
FuzzyFunctionNumOfSamplesMatches.setRightLimit(
static_cast<INDATATYPE>(SampleHistory.numberOfEntries()));
FuzzyFunctionNumOfSamplesMismatches.setRightLimit(
static_cast<INDATATYPE>(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<PROCDATATYPE, HistoryPolicy::FIFO>
RelativeDistanceHistory(SampleHistory.maxLength());
// Calculate distances to all history samples.
for (auto &HistorySample : SampleHistory) {
- PROCDATATYPE RelativeDistance =
- relativeDistance<INDATATYPE, PROCDATATYPE>(Sample, HistorySample);
+ 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<CONFDATATYPE>(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<PROCDATATYPE, HistoryPolicy::FIFO>
RelativeDistanceHistory(SampleHistory.maxLength());
// Calculate distances to all history samples.
for (auto &HistorySample : SampleHistory) {
RelativeDistanceHistory.addEntry(
- relativeDistance<INDATATYPE, PROCDATATYPE>(Sample, HistorySample));
+ 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<CONFDATATYPE>(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<CONFDATATYPE> signalStateInformation(void) noexcept {
return SignalStateInfo;
}
private:
void validateSignalState(INDATATYPE Sample) {
// TODO (future): WorstConfidenceDistance and BestConfidenceDistance could
// be set already in "CONFDATATYPE
// confidenceSampleMatchesSignalState(INDATATYPE Sample)" and "CONFDATATYPE
// confidenceSampleMismatchesSignalState(INDATATYPE Sample)" when the new
// sample is compared to all history samples. This would save a lot time
// because the comparisons are done only once. However, it has to be asured
// that the these two functions are called before the insertation, and the
// FuzzyFunctions for validation and matching have to be the same!
CONFDATATYPE LowestConfidenceMatching = 1;
CONFDATATYPE HighestConfidenceMismatching = 0;
for (auto &HistorySample : SampleHistory) {
// TODO (future): think about using different fuzzy functions for
// validation and matching.
LowestConfidenceMatching = fuzzyAND(
LowestConfidenceMatching,
- FuzzyFunctionSampleMatches(relativeDistance<INDATATYPE, PROCDATATYPE>(
- Sample, HistorySample)));
+ FuzzyFunctionSampleMatches(DistanceMetric(
+ std::make_pair(Sample, HistorySample))));
HighestConfidenceMismatching =
fuzzyOR(HighestConfidenceMismatching,
FuzzyFunctionSampleMismatches(
- relativeDistance<INDATATYPE, PROCDATATYPE>(
- Sample, HistorySample)));
+ 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<INDATATYPE>(
SignalStateInfo.NumberOfInsertedSamplesAfterEntrance)));
SignalStateInfo.ConfidenceStateIsInvalid =
fuzzyOR(HighestConfidenceMismatching,
FuzzyFunctionNumOfSamplesInvalid(static_cast<INDATATYPE>(
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<INDATATYPE>(TimeOfDisparity));
}
getchar();
*/
SignalStateInfo.ConfidenceStateIsStable = 0;
SignalStateInfo.ConfidenceStateIsDrifting = 0;
/*
std::cout << "ConfidenceStateIsStable (before): "
<< SignalStateInfo.ConfidenceStateIsStable << std::endl;
std::cout << "ConfidenceStateIsDrifting (before): "
<< SignalStateInfo.ConfidenceStateIsDrifting << std::endl;
*/
if (DABHistory.numberOfEntries() >= 2) {
/*
// EXPERIMENTING
for (unsigned int t = 1;
t <= DriftLookbackRange && t < DABHistory.numberOfEntries();
t++) {
// AND
SignalStateInfo.ConfidenceStateIsStable = fuzzyOR(
SignalStateInfo.ConfidenceStateIsStable,
fuzzyAND(
FuzzyFunctionSignalIsStable(
relativeDistance<INDATATYPE, PROCDATATYPE>(
DABHistory[DABHistory.numberOfEntries() - 1],
DABHistory[DABHistory.numberOfEntries() - (t +
1)])), FuzzyFunctionSignalConditionLookBack(t)));
SignalStateInfo.ConfidenceStateIsDrifting = fuzzyOR(
SignalStateInfo.ConfidenceStateIsDrifting,
fuzzyAND(
FuzzyFunctionSignalIsDrifting(
relativeDistance<INDATATYPE, PROCDATATYPE>(
DABHistory[DABHistory.numberOfEntries() - 1],
DABHistory[DABHistory.numberOfEntries() - (t +
1)])), FuzzyFunctionSignalConditionLookBack(t))); */
/*
std::cout
<< "t=" << t
<< ", DABact=" << DABHistory[DABHistory.numberOfEntries() -
1]
<< ", DAB_t-" << t << "="
<< DABHistory[DABHistory.numberOfEntries() - (t + 1)]
<< " / FuzzyStb="
<< FuzzyFunctionSignalIsStable(
relativeDistance<INDATATYPE, PROCDATATYPE>(
DABHistory[DABHistory.numberOfEntries() - 1],
DABHistory[DABHistory.numberOfEntries() - (t +
1)]))
<< ", FuzzyDft="
<< FuzzyFunctionSignalIsDrifting(
relativeDistance<INDATATYPE, PROCDATATYPE>(
DABHistory[DABHistory.numberOfEntries() - 1],
DABHistory[DABHistory.numberOfEntries() - (t +
1)]))
<< ", FuzzyLB=" << FuzzyFunctionSignalConditionLookBack(t)
<< std::endl;
*/
// MULTI
/*
SignalStateInfo.ConfidenceStateIsStable = fuzzyOR(
SignalStateInfo.ConfidenceStateIsStable,
FuzzyFunctionSignalIsStable(
relativeDistance<INDATATYPE, PROCDATATYPE>(
DABHistory[DABHistory.numberOfEntries() - 1],
DABHistory[DABHistory.numberOfEntries() - (t + 1)]))
* FuzzyFunctionSignalConditionLookBack(t));
SignalStateInfo.ConfidenceStateIsDrifting = fuzzyOR(
SignalStateInfo.ConfidenceStateIsDrifting,
FuzzyFunctionSignalIsDrifting(
relativeDistance<INDATATYPE, PROCDATATYPE>(
DABHistory[DABHistory.numberOfEntries() - 1],
DABHistory[DABHistory.numberOfEntries() - (t + 1)]))
* FuzzyFunctionSignalConditionLookBack(t));
*/
// std::cout << "t = " << t << ", HistLength = " <<
// DABHistory.numberOfEntries() << std::endl;
//}
// EXPERIMENTING -> following outcommented block was the published code
SignalStateInfo.ConfidenceStateIsStable = FuzzyFunctionSignalIsStable(
- relativeDistance<INDATATYPE, PROCDATATYPE>(
- DABHistory[DABHistory.numberOfEntries() - 1], DABHistory[0]));
+ DistanceMetric(
+ std::pair(DABHistory[DABHistory.numberOfEntries() - 1], DABHistory[0])));
SignalStateInfo.ConfidenceStateIsDrifting = FuzzyFunctionSignalIsDrifting(
- relativeDistance<INDATATYPE, PROCDATATYPE>(
- DABHistory[DABHistory.numberOfEntries() - 1], DABHistory[0]));
+ DistanceMetric(
+ std::pair(DABHistory[DABHistory.numberOfEntries() - 1], DABHistory[0])));
}
/*
std::cout << "ConfidenceStateIsStable (after): "
<< SignalStateInfo.ConfidenceStateIsStable << std::endl;
std::cout << "ConfidenceStateIsDrifting (after): "
<< SignalStateInfo.ConfidenceStateIsDrifting << std::endl;
*/
/*
else {
// Initializing the following variables because (at this moment) we do not
// know if the signal is stable or drifting.
SignalStateInfo.ConfidenceStateIsStable = 0;
SignalStateInfo.ConfidenceStateIsDrifting = 0;
}
*/
if (SignalStateInfo.ConfidenceStateIsStable >
SignalStateInfo.ConfidenceStateIsDrifting) {
SignalStateInfo.StateCondition = StateConditions::STABLE;
} else if (SignalStateInfo.ConfidenceStateIsStable <
SignalStateInfo.ConfidenceStateIsDrifting) {
SignalStateInfo.StateCondition = StateConditions::DRIFTING;
} else {
SignalStateInfo.StateCondition = StateConditions::UNKNOWN;
/*
if (SignalStateInfo.ConfidenceStateIsStable != 0)
getchar();
*/
}
}
};
} // 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 8a7d3c1..a38794c 100644
--- a/include/rosa/agent/SignalStateDetector.hpp
+++ b/include/rosa/agent/SignalStateDetector.hpp
@@ -1,332 +1,340 @@
//===-- 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 <vector>
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 <typename INDATATYPE, typename CONFDATATYPE, typename PROCDATATYPE,
HistoryPolicy HP>
class SignalStateDetector
: public StateDetector<INDATATYPE, CONFDATATYPE, PROCDATATYPE, HP> {
using StateDetector =
StateDetector<INDATATYPE, CONFDATATYPE, PROCDATATYPE, HP>;
+ 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<SignalState<INDATATYPE, CONFDATATYPE, PROCDATATYPE>>;
/// 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<SignalStatePtr, HP> 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 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<PartialFunction<uint32_t, float>>
FuzzyFunctionSignalConditionLookBack;
/// TODO: describe
std::shared_ptr<PartialFunction<uint32_t, float>>
FuzzyFunctionSignalConditionHistoryDesicion;
/// TODO: describe
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 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,
+ DistanceMetricAbstraction DistanceMetric,
PartFuncPointer FuzzyFunctionSampleMatches,
PartFuncPointer FuzzyFunctionSampleMismatches,
StepFuncPointer FuzzyFunctionNumOfSamplesMatches,
StepFuncPointer FuzzyFunctionNumOfSamplesMismatches,
PartFuncPointer FuzzyFunctionSampleValid,
PartFuncPointer FuzzyFunctionSampleInvalid,
StepFuncPointer FuzzyFunctionNumOfSamplesValid,
StepFuncPointer FuzzyFunctionNumOfSamplesInvalid,
PartFuncPointer FuzzyFunctionSignalIsDrifting,
PartFuncPointer FuzzyFunctionSignalIsStable,
// std::shared_ptr<PartialFunction<uint32_t, float>>
// FuzzyFunctionSignalConditionLookBack,
// std::shared_ptr<PartialFunction<uint32_t, float>>
// FuzzyFunctionSignalConditionHistoryDesicion,
// uint32_t DriftLookbackRange,
uint32_t SampleHistorySize, uint32_t DABSize,
uint32_t DABHistorySize) 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),
FuzzyFunctionSignalIsStable(FuzzyFunctionSignalIsStable),
// FuzzyFunctionSignalConditionLookBack(
// FuzzyFunctionSignalConditionLookBack),
// FuzzyFunctionSignalConditionHistoryDesicion(
// FuzzyFunctionSignalConditionHistoryDesicion),
// DriftLookbackRange(DriftLookbackRange),
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 this function to an operator()-function
SignalStateInformation<CONFDATATYPE>
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<CONFDATATYPE> 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<CONFDATATYPE>
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<INDATATYPE, CONFDATATYPE, PROCDATATYPE>(
this->NextStateID, SignalProperty, SampleHistorySize, DABSize,
- DABHistorySize, *FuzzyFunctionSampleMatches,
+ DABHistorySize, *DistanceMetric, *FuzzyFunctionSampleMatches,
*FuzzyFunctionSampleMismatches, *FuzzyFunctionNumOfSamplesMatches,
*FuzzyFunctionNumOfSamplesMismatches, *FuzzyFunctionSampleValid,
*FuzzyFunctionSampleInvalid, *FuzzyFunctionNumOfSamplesValid,
*FuzzyFunctionNumOfSamplesInvalid, *FuzzyFunctionSignalIsDrifting,
*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/StateDetector.hpp b/include/rosa/agent/StateDetector.hpp
index 6f3d7ce..26d9504 100644
--- a/include/rosa/agent/StateDetector.hpp
+++ b/include/rosa/agent/StateDetector.hpp
@@ -1,64 +1,65 @@
//===-- rosa/agent/StateDetector.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/StateDetector.hpp
///
/// \author Maximilian Götzinger (maximilian.goetzinger@tuwien.ac.at)
///
/// \date 2019
///
/// \brief Definition of *state detector* *functionality*.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_AGENT_STATEDETECTOR_HPP
#define ROSA_AGENT_STATEDETECTOR_HPP
#include "rosa/agent/FunctionAbstractions.hpp"
#include "rosa/agent/History.hpp"
#include <vector>
namespace rosa {
namespace agent {
template <typename INDATATYPE, typename CONFDATATYPE, typename PROCDATATYPE,
HistoryPolicy HP>
class StateDetector : public Functionality {
// Make sure the actual type arguments are matching our expectations.
STATIC_ASSERT((std::is_arithmetic<INDATATYPE>::value),
"input data type not arithmetic");
STATIC_ASSERT((std::is_arithmetic<CONFDATATYPE>::value),
"confidence abstraction type is not to arithmetic");
STATIC_ASSERT((std::is_arithmetic<PROCDATATYPE>::value),
"process type is not to arithmetic");
protected:
+ using DistanceMetricAbstraction = std::shared_ptr<Abstraction<std::pair<INDATATYPE, INDATATYPE>, PROCDATATYPE>>;
using PartFuncPointer =
std::shared_ptr<PartialFunction<INDATATYPE, CONFDATATYPE>>;
using StepFuncPointer =
std::shared_ptr<StepFunction<INDATATYPE, CONFDATATYPE>>;
/// The NextSignalStateID is a counter variable which stores the ID which the
/// next signal state shall have.
uint32_t NextStateID;
/// The SignalStateHasChanged is a flag that show whether a signal has changed
/// its state.
bool StateHasChanged;
};
} // End namespace agent
} // End namespace rosa
#endif // ROSA_AGENT_SIGNALSTATEDETECTOR_HPP
diff --git a/include/rosa/support/math.hpp b/include/rosa/support/math.hpp
index 1df8d7e..7639e27 100644
--- a/include/rosa/support/math.hpp
+++ b/include/rosa/support/math.hpp
@@ -1,156 +1,137 @@
//===-- rosa/support/math.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/support/math.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017
///
/// \brief Math helpers.
///
//===----------------------------------------------------------------------===//
// !!!!!! Please check lines 60 - 180 forward !!!!!!!!!!!!!!
#ifndef ROSA_SUPPORT_MATH_HPP
#define ROSA_SUPPORT_MATH_HPP
#include "debug.hpp"
#include <algorithm>
#include <array>
#include <cmath>
#include <cstdarg>
#include <cstdlib>
#include <limits>
#include <type_traits>
namespace rosa {
/// Computes log base 2 of a number.
///
/// \param N the number to compute log base 2 for
///
/// \return log base 2 of \p N
constexpr size_t log2(const size_t N) {
return ((N < 2) ? 1 : 1 + log2(N / 2));
}
/// Tells the next representable floating point value.
///
/// \tparam T type to operate on
///
/// \note The second type argument enforces \p T being a floating point type,
/// always use the default value!
///
/// \param V value to which find the next representable one
///
/// \return the next representable value of type \p T after value \p V
///
/// \pre Type \p T must be a floating point type, which is enforced by
/// `std::enable_if` in the second type argument.
template <typename T,
typename = std::enable_if_t<std::is_floating_point<T>::value>>
T nextRepresentableFloatingPoint(const T V) {
return std::nextafter(V, std::numeric_limits<T>::infinity());
}
/// Conjuncts two or more values with each other.
///
/// \param Data an array of the data
///
/// \return the conjunction of the values given as parameter.
template <typename CONFDATATYPE, std::size_t size>
CONFDATATYPE fuzzyAND(const std::array<CONFDATATYPE, size> &Data) noexcept {
STATIC_ASSERT(std::is_arithmetic<CONFDATATYPE>::value,
"Type of FuzzyAnd is not arithmetic");
STATIC_ASSERT(size > 1, "Number of Arguments is to little");
for (auto tmp : Data)
ASSERT(tmp <= 1 && tmp >= 0);
return *std::min_element(Data.begin(), Data.end());
}
/// Conjuncts two or more values with each other. It's a wrapper for \c
/// fuzzyAND() [array]
///
/// \param Data first data to get the type explicitly
///
/// \param Datan a package of data
///
/// \note the types of Datan must be the same type as Data
///
/// \return the conjunction of the values given as parameter.
template <typename CONFDATATYPE, typename... _CONFDATATYPE>
std::enable_if_t<
std::conjunction_v<std::is_same<CONFDATATYPE, _CONFDATATYPE>...>,
CONFDATATYPE>
fuzzyAND(const CONFDATATYPE Data, const _CONFDATATYPE... Datan) noexcept {
return fuzzyAND(
std::array<CONFDATATYPE, sizeof...(Datan) + 1>{{Data, Datan...}});
}
/// Disjuncts two or more values with each other.
///
/// \param Data an array with the data.
///
/// \return the disjunction of the values given as parameter.
template <typename CONFDATATYPE, std::size_t size>
CONFDATATYPE fuzzyOR(const std::array<CONFDATATYPE, size> &Data) noexcept {
STATIC_ASSERT(std::is_arithmetic<CONFDATATYPE>::value,
"Type of FuzzyAnd is not arithmetic");
STATIC_ASSERT(size > 1, "Number of Arguments is to little");
ASSERT(std::all_of(Data.begin(), Data.end(),
[](const auto &v) { return v <= 1 && v >= 0; }));
return *std::max_element(Data.begin(), Data.end());
}
/// Disjuncts two or more values with each other. It's a wrapper for \c
/// fuzzyOR() [array]
///
/// \param Data first data to get the type explicitly
///
/// \param Datan a package of data
///
/// \note the types of Datan must be the same type as Data
///
/// \return the disjunction of the values given as parameter.
template <typename CONFDATATYPE, typename... _CONFDATATYPE>
std::enable_if_t<
std::conjunction_v<std::is_same<CONFDATATYPE, _CONFDATATYPE>...>,
CONFDATATYPE>
fuzzyOR(const CONFDATATYPE Data, const _CONFDATATYPE... Datan) noexcept {
return fuzzyOR(
std::array<CONFDATATYPE, sizeof...(Datan) + 1>{{Data, Datan...}});
}
-template <typename INDATATYPE, typename PROCDATATYPE>
-PROCDATATYPE relativeDistance(INDATATYPE NewValue,
- INDATATYPE HistoryValue) noexcept {
- PROCDATATYPE Dist = HistoryValue - NewValue;
-
- if (Dist == 0) {
- return 0;
- } else {
- Dist = Dist / NewValue;
- if (Dist < 0) {
- // TODO: I guess this multiplication here should not be done because
- // it could be that the distance fuzzy functions are not symetrical
- //(negative and positive side)
- Dist = Dist * (-1);
- }
- return (Dist);
- }
-}
-
} // End namespace rosa
#endif // ROSA_SUPPORT_MATH_HPP
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Jul 3, 11:19 AM (1 d, 16 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
157223
Default Alt Text
(80 KB)
Attached To
Mode
R20 SoC_Rosa_repo
Attached
Detach File
Event Timeline
Log In to Comment