Page MenuHomePhorge

No OneTemporary

Size
80 KB
Referenced Files
None
Subscribers
None
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

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)

Event Timeline