Page MenuHomePhorge

No OneTemporary

Size
61 KB
Referenced Files
None
Subscribers
None
diff --git a/apps/ccam/ccam.cpp b/apps/ccam/ccam.cpp
index 76fc676..973435e 100644
--- a/apps/ccam/ccam.cpp
+++ b/apps/ccam/ccam.cpp
@@ -1,116 +1,71 @@
//===-- apps/ccam/ccam.cpp --------------------------------------*- C++ -*-===//
//
// The RoSA Framework -- Application CCAM
//
//===----------------------------------------------------------------------===//
///
/// \file apps/ccam/ccam.cpp
///
/// \author Maximilian Goetzinger (maximilian.goetzinger@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
//===----------------------------------------------------------------------===//
#include "rosa/agent/FunctionAbstractions.hpp"
#include "rosa/agent/SignalStateDetector.hpp"
#include <iostream>
using namespace rosa::agent;
int main(void) {
- // Just some tests :D
- std::vector vec = {7, 3, 5, 1, 9};
+ /*
+// Just some tests :D
+std::vector vec = {7, 3, 5, 1, 9};
- std::sort(vec.rbegin(), vec.rend());
- // std::reverse(vec.begin(), vec.end());
+std::sort(vec.rbegin(), vec.rend());
+// std::reverse(vec.begin(), vec.end());
- for (auto it = vec.cbegin(); it != vec.cend(); ++it) {
- std::cout << *it << ' ';
- }
+for (auto it = vec.cbegin(); it != vec.cend(); ++it) {
+ std::cout << *it << ' ';
+}
+ */
std::shared_ptr<PartialFunction<float, float>> PartFunc(
new PartialFunction<float, float>(
{
{{0.f, 3.f},
std::make_shared<LinearFunction<float, float>>(0.f, 1.f / 3)},
{{3.f, 6.f},
std::make_shared<LinearFunction<float, float>>(1.f, 0.f)},
{{6.f, 9.f},
std::make_shared<LinearFunction<float, float>>(3.f, -1.f / 3)},
},
0));
std::shared_ptr<StepFunction<float, float>> StepFunc(
new StepFunction<float, float>(1 / 10));
SignalStateDetector<float, float, float, HistoryPolicy::SRWF> TestSigSD(
10000, PartFunc, PartFunc, StepFunc, StepFunc, PartFunc, PartFunc, 10, 5,
1000);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(50.3f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
- TestSigSD.detectSignalState(100.6f);
+ unsigned int i;
+
+ for (i = 1; i <= 30; i++) {
+ TestSigSD.detectSignalState(50.3f);
+ // std::cout << "test";
+ }
+
+ for (; i <= 60; i++) {
+ TestSigSD.detectSignalState(100.6f);
+ }
return 0;
}
diff --git a/include/rosa/agent/History.hpp b/include/rosa/agent/History.hpp
index f8d66d1..4b834c2 100644
--- a/include/rosa/agent/History.hpp
+++ b/include/rosa/agent/History.hpp
@@ -1,548 +1,579 @@
//===-- rosa/agent/History.hpp ----------------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/agent/History.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017
///
/// \brief Definition of *history* *functionality*.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_AGENT_HISTORY_HPP
#define ROSA_AGENT_HISTORY_HPP
#include "rosa/agent/Functionality.h"
#include "rosa/config/config.h"
#include "rosa/support/debug.hpp"
#include "rosa/support/type_helper.hpp"
#include <array>
+#include <limits>
#include <vector>
namespace rosa {
namespace agent {
/// Retention policies defining what a \c rosa::agent::History instance should
/// do when the number of recorded entries reached its capacity.
enum class HistoryPolicy {
SRWF, ///< Stop Recording When Full -- no new entry is recorded when full
FIFO, ///< First In First Out -- overwrite the earliest entry with a new one
LIFO ///< Last In First Out -- overwrite the latest entry with a new one
};
template <typename T, HistoryPolicy P> class History : public Functionality {
public:
History(void) noexcept {}
/// Destroys \p this object.
virtual ~History(void) = default;
/// Tells the retention policy applied to \p this object.
///
/// \return \c rosa::agent::History::P
static constexpr HistoryPolicy policy(void) noexcept { return P; }
/// Tells how many entries may be recorded by \c this object.
///
/// \note The number of entries that are actually recorded may be smaller.
///
/// \return The max number of entries that may be recorded
virtual size_t maxLength(void) const noexcept = 0;
/// Tells how many entries are currently recorded by \p this object.
///
/// \return number of entries currently recorded by \p this object.
///
/// \post The returned value cannot be larger than the capacity of \p this
/// object:\code
/// 0 <= numberOfEntries() && numberOfEntries <= lengthOfHistory()
/// \endcode
virtual size_t numberOfEntries(void) const noexcept = 0;
/// Tells if \p this object has not recorded anything yet.
///
/// \return if \p this object has no entries recorded
bool empty(void) const noexcept { return numberOfEntries() == 0; }
/// Tells if the history reached it's maximum length
///
/// \return if the history reached it's maximum length.
bool full(void) const noexcept { return numberOfEntries() == maxLength(); }
/// Gives a constant lvalue reference to an entry stored in \p this object.
///
/// \note The recorded entries are indexed starting from the latest one.
///
/// \param I the index at which the stored entry to take from
///
/// \pre \p I is a valid index:\code
/// 0 <= I && I < numberOfEntries()
/// \endcode
virtual const T &entry(const size_t I = 0) const noexcept = 0;
/// Removes all entries recorded in \p this object.
virtual void clear() noexcept = 0;
private:
/// Pushes a new entry into the history.
///
/// \note The earliest entry gets overwritten if the history is full.
///
/// \param V value to push into the history
virtual void pushBack(const T &V) noexcept = 0;
/// Replaces the most recent entry in the history.
///
/// \param V value to replace the most current value with
virtual void replaceFront(const T &V) noexcept = 0;
public:
/// Adds a new entry to \p this object and tells if the operation was
/// successful.
///
/// \note Success of the operation depends on the actual policy.
///
/// \param V value to store
///
/// \return if \p V was successfully stored
bool addEntry(const T &V) noexcept {
switch (P) {
default:
ROSA_CRITICAL("unkown HistoryPolicy");
case HistoryPolicy::LIFO:
if (full()) {
replaceFront(V);
return true;
}
case HistoryPolicy::SRWF:
if (full()) {
return false;
}
// \note Fall through to FIFO which unconditionally pushes the new entry.
case HistoryPolicy::FIFO:
// FIFO and SRWF not full.
pushBack(V);
return true;
}
}
/// Tells the trend set by the entries recorded by \p this object.
///
/// The number of steps to go back when calculating the trend is defined as
/// argument to the function.
///
/// \note The number of steps that can be made is limited by the number of
/// entries recorded by \p this object.
///
/// \note The function is made a template only to be able to use
/// \c std::enable_if.
///
/// \tparam X always use the default!
///
/// \param D number of steps to go back in *history*
///
/// \return trend set by analyzed entries
///
/// \pre Statically, \p this object stores signed arithmetic values:\code
/// std::is_arithmetic<T>::value && std::is_signed<T>::value
/// \endcode Dynamically, \p D is a valid number of steps to take:\code
/// 0 <= D && D < lengthOfHistory()
/// \endcode
template <typename X = T>
typename std::enable_if<
std::is_arithmetic<X>::value && std::is_signed<X>::value, X>::type
trend(const size_t D) const noexcept {
STATIC_ASSERT((std::is_same<X, T>::value), "not default template arg");
ASSERT(0 <= D && D < maxLength()); // Boundary check.
if (numberOfEntries() < 2 || D < 1) {
// No entries for computing trend.
return {}; // Zero element of \p T
} else {
// Here at least two entries.
// \c S is the number of steps that can be done.
const size_t S = std::min(numberOfEntries() - 1, D);
size_t I = S;
// Compute trend with linear regression.
size_t SumIndices = 0;
T SumEntries = {};
T SumSquareEntries = {};
T SumProduct = {};
while (I > 0) {
// \note Indexing for the regression starts in the past.
const size_t Index = S - I;
const T Entry = entry(--I);
SumIndices += Index;
SumEntries += Entry;
SumSquareEntries += Entry * Entry;
SumProduct += Entry * Index;
}
return (SumProduct * S - SumEntries * SumIndices) /
(SumSquareEntries * S - SumEntries * SumEntries);
}
}
/// Tells the average absolute difference between consecutive entries recorded
/// by \p this object
/// The number of steps to go back when calculating the average is defined as
/// argument to the function.
///
/// \note The number of steps that can be made is limited by the number of
/// entries recorded by \p this object.
///
/// \note The function is made a template only to be able to use
/// \c std::enable_if.
///
/// \tparam X always use the default!
///
/// \param D number of steps to go back in *history*
///
/// \pre Statically, \p this object stores arithmetic values:\code
/// std::is_arithmetic<T>::value
/// \endcode Dynamically, \p D is a valid number of steps to take:\code
/// 0 <= D && D < lengthOfHistory()
/// \endcode
template <typename X = T>
typename std::enable_if<std::is_arithmetic<X>::value, size_t>::type
averageAbsDiff(const size_t D) const noexcept {
STATIC_ASSERT((std::is_same<X, T>::value), "not default template arg");
ASSERT(0 <= D && D < maxLength()); // Boundary check.
if (numberOfEntries() < 2 || D < 1) {
// No difference to average.
return {}; // Zero element of \p T
} else {
// Here at least two entries.
// \c S is the number of steps that can be done.
const size_t S = std::min(numberOfEntries() - 1, D);
// Sum up differences as non-negative values only, hence using an
// unsigned variable for that.
size_t Diffs = {}; // Init to zero.
// Count down entry indices and sum up all the absolute differences.
size_t I = S;
T Last = entry(I);
while (I > 0) {
T Next = entry(--I);
Diffs += Last < Next ? Next - Last : Last - Next;
Last = Next;
}
// Return the average of the summed differences.
return Diffs / S;
}
}
/// Tells the average of all entries recorded by \p this object
///
/// \tparam R type of the result
template <typename R> R average() const noexcept {
R Average = 0;
for (size_t I = 0; I < numberOfEntries(); I++) {
Average += entry(I);
}
Average /= numberOfEntries();
return Average;
}
};
/// Implements *history* by recording and storing values.
/// The length of the underlying std::array is static and must be set at
/// compile-time
///
/// \note Not thread-safe implementation, which should not be a problem as any
/// instance of \c rosa::agent::Functionality is an internal component of a
/// \c rosa::Agent, which is the basic unit of concurrency.
///
/// \tparam T type of values to store
/// \tparam N number of values to store at most
/// \tparam P retention policy to follow when capacity is reached
///
/// \invariant The size of the underlying \c std::array is `N + 1`:\code
/// max_size() == N + 1 && N == max_size() - 1
/// \endcode
template <typename T, size_t N, HistoryPolicy P>
class StaticLengthHistory : public History<T, P>, private std::array<T, N + 1> {
// Bring into scope inherited functions that are used.
using std::array<T, N + 1>::max_size;
using std::array<T, N + 1>::operator[];
/// The index of the first data element in the circular buffer.
size_t Data;
/// The index of the first empty slot in the circular buffer.
size_t Space;
public:
using History<T, P>::policy;
using History<T, P>::empty;
using History<T, P>::full;
using History<T, P>::addEntry;
using History<T, P>::trend;
using History<T, P>::averageAbsDiff;
/// Creates an instances by initializing the indices for the circular buffer.
StaticLengthHistory(void) noexcept : Data(0), Space(0) {}
/// Destroys \p this object.
~StaticLengthHistory(void) override = default;
/// Tells how many entries may be recorded by \c this object.
///
/// \note The number of entries that are actually recorded may be smaller.
///
/// \return \c rosa::agent::History::N
size_t maxLength(void) const noexcept override { return N; }
/// Tells how many entries are currently recorded by \p this object.
///
/// \return number of entries currently recorded by \p this object.
///
/// \post The returned value cannot be larger than the capacity of \p this
/// object:\code
/// 0 <= numberOfEntries() && numberOfEntries <= lengthOfHistory()
/// \endcode
size_t numberOfEntries(void) const noexcept override {
return Data <= Space ? Space - Data : max_size() - Data + Space;
}
/// Gives a constant lvalue reference to an entry stored in \p this object.
///
/// \note The recorded entries are indexed starting from the latest one.
///
/// \param I the index at which the stored entry to take from
///
/// \pre \p I is a valid index:\code
/// 0 <= I && I < numberOfEntries()
/// \endcode
const T &entry(const size_t I = 0) const noexcept override {
ASSERT(0 <= I && I < numberOfEntries()); // Boundary check.
// Position counted back from the last recorded entry.
typename std::make_signed<const size_t>::type Pos = Space - (1 + I);
// Actual index wrapped around to the end of the buffer if negative.
return (*this)[Pos >= 0 ? Pos : max_size() + Pos];
}
/// Removes all entries recorded in \p this object.
void clear() noexcept override {
Data = 0;
Space = 0;
}
private:
/// Pushes a new entry into the circular buffer.
///
/// \note The earliest entry gets overwritten if the buffer is full.
///
/// \param V value to push into the buffer
void pushBack(const T &V) noexcept override {
// Store value to the first empty slot and step Space index.
(*this)[Space] = V;
Space = (Space + 1) % max_size();
if (Data == Space) {
// Buffer was full, step Data index.
Data = (Data + 1) % max_size();
}
}
/// Replaces the most recent entry in the history.
///
/// \param V value to replace the most current value with
void replaceFront(const T &V) noexcept override {
(*this)[(Space - 1) % max_size()] = V;
}
};
/// Adds a new entry to a \c rosa::agent::History instance.
///
/// \note The result of \c rosa::agent::History::addEntry is ignored.
///
/// \tparam T type of values stored in \p H
/// \tparam N number of values \p H is able to store
/// \tparam P retention policy followed by \p H when capacity is reached
///
/// \param H to add a new entry to
/// \param V value to add to \p H
///
/// \return \p H after adding \p V to it
template <typename T, size_t N, HistoryPolicy P>
StaticLengthHistory<T, N, P> &operator<<(StaticLengthHistory<T, N, P> &H,
const T &V) noexcept {
H.addEntry(V);
return H;
}
/// Implements *DynamicLengthHistory* by recording and storing values.
///
/// \note Not thread-safe implementation, which should not be a problem as any
/// instance of \c rosa::agent::Functionality is an internal component of a
/// \c rosa::Agent, which is the basic unit of concurrency.
///
/// \tparam T type of values to store
/// \tparam P retention policy to follow when capacity is reached
template <typename T, HistoryPolicy P>
class DynamicLengthHistory : public History<T, P>, private std::vector<T> {
//@benedikt: if i dont make these public, I cannot iterate from outside
// through the history. E.g., "for (auto &SavedSignalState :
// DetectedSignalStates)" at line ~297 in "SignalStateDetector.hpp". Do you
// have an idea to make this in a better/more beautiful way?
public:
// Bring into scope inherited functions that are used.
using std::vector<T>::erase;
using std::vector<T>::begin;
using std::vector<T>::end;
using std::vector<T>::rbegin;
using std::vector<T>::rend;
using std::vector<T>::size;
using std::vector<T>::max_size;
using std::vector<T>::resize;
using std::vector<T>::push_back;
using std::vector<T>::pop_back;
using std::vector<T>::operator[];
/// The current length of the DynamicLengthHistory.
size_t Length;
public:
using History<T, P>::policy;
using History<T, P>::empty;
using History<T, P>::full;
using History<T, P>::addEntry;
using History<T, P>::trend;
using History<T, P>::averageAbsDiff;
/// Creates an instances by setting an initial length
DynamicLengthHistory(size_t Length) noexcept : Length(Length) {
this->resize(Length);
}
/// Destroys \p this object.
~DynamicLengthHistory(void) override = default;
/// Tells how many entries may be recorded by \c this object.
///
/// \note The number of entries that are actually recorded may be smaller.
///
/// \return \c rosa::agent::DynamicLengthHistory::N
size_t maxLength(void) const noexcept override { return Length; }
/// Tells how many entries are currently recorded by \p this object.
///
/// \return number of entries currently recorded by \p this object.
///
/// \post The returned value cannot be larger than the capacity of \p this
/// object:\code
/// 0 <= numberOfEntries() && numberOfEntries <=
/// lengthOfHistory() \endcode
size_t numberOfEntries(void) const noexcept { return size(); }
/// Gives a constant lvalue reference to an entry stored in \p this object.
///
/// \note The recorded entries are indexed starting from the latest one.
///
/// \param I the index at which the stored entry to take from
///
/// \pre \p I is a valid index:\code
/// 0 <= I && I < numberOfEntries()
/// \endcode
const T &entry(const size_t I = 0) const noexcept override {
ASSERT(0 <= I && I < numberOfEntries()); // Boundary check.
return this->operator[](size() - I - 1);
}
/// Removes all entries recorded in \p this object.
void clear() noexcept override { erase(begin(), end()); }
/// Sort all entries in ascending order.
void sortAscending(void) noexcept { std::sort(begin(), end()); }
/// Sort all entries in descending order.
void sortDescending(void) noexcept { std::sort(rbegin(), rend()); }
/// Delets one element of the history.
///
/// \param the element which shall be deleted.
// @benedikt: is this ok like that? should there be some "error handling"?
// checking if V is not null, or if V is member of the vector?
void deleteEntry(T &V) { erase(std::find(begin(), end(), V)); }
+ /// Gives back the lowest entry of the history.
+ ///
+ /// \return the lowest entry. In case of an empty history, the maximum value
+ /// of the chosen data type is returned.
+ //@benedikt: please check if it is right
+ T lowestEntry() {
+ auto it = std::min_element(begin(), end());
+
+ if (it == end()) {
+ return std::numeric_limits<T>::max();
+ } else {
+ return *it;
+ }
+ }
+
+ /// Gives back the highest entry of the history.
+ ///
+ /// \return the highest entry. In case of an empty history, the minimum value
+ /// of the chosen data type is returned.
+ //@benedikt: please check if it is right
+ T highestEntry() {
+ auto it = std::max_element(begin(), end());
+
+ if (it == end()) {
+ return std::numeric_limits<T>::min();
+ } else {
+ return *it;
+ }
+ }
+
private:
/// Pushes a new entry into the circular buffer.
///
/// \note The earliest entry gets overwritten if the buffer is full.
///
/// \param V value to push into the buffer
void pushBack(const T &V) noexcept override {
if (full()) {
erase(begin());
}
push_back(V);
}
/// Replaces the most recent entry in the history.
///
/// \param V value to replace the most current value with
void replaceFront(const T &V) noexcept override {
(void)pop_back();
push_back(V);
}
public:
/// Resizes the History length. If the new length is smaller than the number
/// of currently stored values, values are deleted according to the
/// HistoryPolicy.
///
/// @param NewLength The new Length of the History.
void setLength(size_t NewLength) noexcept {
Length = NewLength;
if (NewLength < numberOfEntries()) {
switch (P) {
default:
ROSA_CRITICAL("unkown HistoryPolicy");
case HistoryPolicy::LIFO:
case HistoryPolicy::SRWF:
// Delete last numberOfEntries() - NewLength items from the back
erase(begin() + NewLength, end());
break;
case HistoryPolicy::FIFO:
// Delete last numberOfEntries() - NewLength items from the front
erase(begin(), begin() + (numberOfEntries() - NewLength));
break;
}
}
this->resize(Length);
}
};
/// Adds a new entry to a \c rosa::agent::DynamicLengthHistory instance.
///
/// \note The result of \c rosa::agent::DynamicLengthHistory::addEntry is
/// ignored.
///
/// \tparam T type of values stored in \p H
/// \tparam P retention policy followed by \p H when capacity is reached
///
/// \param H to add a new entry to
/// \param V value to add to \p H
///
/// \return \p H after adding \p V to it
template <typename T, HistoryPolicy P>
DynamicLengthHistory<T, P> &operator<<(DynamicLengthHistory<T, P> &H,
const T &V) noexcept {
H.addEntry(V);
return H;
}
} // End namespace agent
} // End namespace rosa
#endif // ROSA_AGENT_HISTORY_HPP
diff --git a/include/rosa/agent/SignalState.hpp b/include/rosa/agent/SignalState.hpp
index 3a68820..9cde3d9 100644
--- a/include/rosa/agent/SignalState.hpp
+++ b/include/rosa/agent/SignalState.hpp
@@ -1,380 +1,474 @@
//===-- rosa/agent/SignalState.hpp ------------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/agent/SignalState.hpp
///
/// \author Maximilian Götzinger (maximilian.goetzinger@tuwien.ac.at)
///
/// \date 2019
///
/// \brief Definition of *signal state* *functionality*.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_AGENT_SIGNALSTATE_HPP
#define ROSA_AGENT_SIGNALSTATE_HPP
#include "rosa/agent/FunctionAbstractions.hpp"
#include "rosa/agent/Functionality.h"
#include "rosa/agent/History.hpp"
#include "rosa/support/math.hpp"
#include <cstdarg>
namespace rosa {
namespace agent {
/// Signal state conditions defining how the condition of a \c
/// rosa::agent::SignalState is saved in \c rosa::agent::SignalStateInformation.
enum class SignalStateCondition {
STABLE, ///< The signal state is stable
DRIFTING, ///< The signal state is drifting
UNKNOWN ///< The signal state is unknown
};
template <typename CONFDATATYPE> struct SignalStateInformation {
// Make sure the actual type arguments are matching our expectations.
STATIC_ASSERT((std::is_arithmetic<CONFDATATYPE>::value),
"confidence type is not to arithmetic");
/// The signal state ID saved as an unsigned integer number
unsigned int SignalStateID;
/// The SignalStateConfidence shows the overall confidence value of the signal
/// state.
CONFDATATYPE SignalStateConfidence;
/// The SignalStateCondition shows the condition of a signal state (stable or
/// drifting)
SignalStateCondition SignalStateCondition;
+ /// The SignalStateIsValid saves the number of samples which have been
+ /// inserted into the state after entering it.
+ unsigned int NumberOfInsertedSamplesAfterEntrance;
/// The SignalStateIsValid shows whether a signal state is valid or invalid.
/// In this context, valid means that enough samples which are in close
/// proximitry have been inserted into the signal state.
bool SignalStateIsValid;
/// The SignalStateJustGotValid shows whether a signal state got valid
/// (toggled from invalid to valid) during the current inserted sample.
bool SignalStateJustGotValid;
/// The SignalStateIsValidAfterReentrance shows whether a signal state is
/// valid after the variable changed back to it again.
bool SignalStateIsValidAfterReentrance;
+ /// The SignalIsStableNotDrifting shows whether a signa is stable and not
+ /// drifting.
+ bool SignalIsStable;
};
/// \tparam INDATATYPE type of input data, \tparam CONFDATATYPE type of
/// data in that the confidence values are given, \param 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");
private:
// For the convinience to write a shorter data type name
using PartFuncPointer =
std::shared_ptr<PartialFunction<INDATATYPE, CONFDATATYPE>>;
// @Benedikt: are INDATATYPE, CONFDATATYPE right here?
using StepFuncPointer =
std::shared_ptr<StepFunction<INDATATYPE, CONFDATATYPE>>;
/// SignalStateInfo is a struct SignalStateInformation that contains
/// information about the current state.
SignalStateInformation<CONFDATATYPE> SignalStateInfo;
/// The FuzzyFunctionSampleMatches is the fuzzy function that gives the
/// confidence how good the new sample matches another sample in the sample
/// history.
PartFuncPointer FuzzyFunctionSampleMatches;
/// The FuzzyFunctionSampleMismatches is the fuzzy function that gives the
/// confidence how bad the new sample matches another sample in the sample
/// history.
PartFuncPointer FuzzyFunctionSampleMismatches;
/// The FuzzyFunctionNumOfSamplesMatches is the fuzzy function that gives the
/// confidence how many samples from the sampe history match the new sample.
StepFuncPointer FuzzyFunctionNumOfSamplesMatches;
/// The FuzzyFunctionNumOfSamplesMismatches is the fuzzy function that gives
/// the confidence how many samples from the sampe history mismatch the new
/// sample.
StepFuncPointer FuzzyFunctionNumOfSamplesMismatches;
/// 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.
PartFuncPointer 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).
PartFuncPointer FuzzyFunctionSignalIsStable;
/// 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;
- /// The SignalStateIsValid shows whether a signal state is valid or invalid.
- /// In this context, valid means that enough samples which are in close
- /// proximitry have been inserted into the signal state.
- bool SignalStateIsValid;
- /// The SignalStateIsValidAfterReentrance shows whether a signal state is
- /// valid after the variable changed back to it again.
- bool SignalStateIsValidAfterReentrance;
+ /// 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;
public:
// @Maxi doxygen per default doesn't display private attributes of a class. So
// I copied them to the constructor. So the user has more information.
/// Creates an instance by setting all parameters
/// \param SignalStateID The Id of the SignalStateinfo \c
/// SignalStateInformation.
///
/// \param FuzzyFunctionSampleMatches The FuzzyFunctionSampleMatches is the
/// fuzzy function that gives the confidence how good the new sample matches
/// another sample in the sample history.
///
/// \param FuzzyFunctionSampleMismatches The FuzzyFunctionSampleMismatches is
/// the fuzzy function that gives the confidence how bad the new sample
/// matches another sample in the sample history.
///
/// \param FuzzyFunctionNumOfSamplesMatches The
/// FuzzyFunctionNumOfSamplesMatches is the fuzzy function that gives the
/// confidence how many samples from the sampe history match the new sample.
///
/// \param FuzzyFunctionNumOfSamplesMismatches The
/// FuzzyFunctionNumOfSamplesMismatches is the fuzzy function that gives the
/// confidence how many samples from the sampe history mismatch the new
/// sample.
///
/// \param FuzzyFunctionSignalIsDrifting The FuzzyFunctionSignalIsDrifting is
/// the fuzzy function that gives the confidence how likely it is that the
/// signal (resp. the state of a signal) is drifting.
///
/// \param FuzzyFunctionSignalIsStable The FuzzyFunctionSignalIsStable is the
/// fuzzy function that gives the confidence how likely it is that the signal
/// (resp. the state of a signal) is stable (not drifting).
///
/// \param SampleHistorySize Size of the Sample History \c
/// DynamicLengthHistory . SampleHistory is a history in that the last sample
/// values are stored.
///
/// \param DABSize Size of DAB \c DynamicLengthHistory . DAB is a (usually)
/// small history of the last sample values of which a average is calculated
/// if the DAB is full.
///
/// \param DABHistorySize Size of the DABHistory \c DynamicLengthHistory .
/// DABHistory is a history in that the last DABs (to be exact, the averages
/// of the last DABs) are stored.
///
SignalState(unsigned int SignalStateID, unsigned int SampleHistorySize,
unsigned int DABSize, unsigned int DABHistorySize,
PartFuncPointer FuzzyFunctionSampleMatches,
PartFuncPointer FuzzyFunctionSampleMismatches,
StepFuncPointer FuzzyFunctionNumOfSamplesMatches,
StepFuncPointer FuzzyFunctionNumOfSamplesMismatches,
PartFuncPointer FuzzyFunctionSignalIsDrifting,
PartFuncPointer FuzzyFunctionSignalIsStable) noexcept
- : SignalStateInfo{SignalStateID, 0, SignalStateCondition::UNKNOWN,
- false, false, false},
- SampleHistory(SampleHistorySize), DAB(DABSize),
+ : SignalStateInfo{SignalStateID,
+ 0,
+ SignalStateCondition::UNKNOWN,
+ 0,
+ false,
+ false,
+ false},
+ SampleHistory(SampleHistorySize),
+ LowestConfidenceMatchingHistory(SampleHistorySize),
+ HighestConfidenceMismatchingHistory(SampleHistorySize), DAB(DABSize),
DABHistory(DABHistorySize),
FuzzyFunctionSampleMatches(FuzzyFunctionSampleMatches),
FuzzyFunctionSampleMismatches(FuzzyFunctionSampleMismatches),
FuzzyFunctionNumOfSamplesMatches(FuzzyFunctionNumOfSamplesMatches),
FuzzyFunctionNumOfSamplesMismatches(
FuzzyFunctionNumOfSamplesMismatches),
FuzzyFunctionSignalIsDrifting(FuzzyFunctionSignalIsDrifting),
FuzzyFunctionSignalIsStable(FuzzyFunctionSignalIsStable) {}
/// Destroys \p this object.
~SignalState(void) = default;
void leaveSignalState(void) noexcept {
DAB.clear();
- SignalStateIsValidAfterReentrance = false;
+ SignalStateInfo.NumberOfInsertedSamplesAfterEntrance = 0;
+ SignalStateInfo.SignalStateIsValidAfterReentrance = false;
}
SignalStateInformation<CONFDATATYPE>
insertSample(INDATATYPE Sample) noexcept {
+
+ validateSignalState(Sample);
+
SampleHistory.addEntry(Sample);
DAB.addEntry(Sample);
if (DAB.full()) {
PROCDATATYPE AvgOfDAB = DAB.template average<PROCDATATYPE>();
DABHistory.addEntry(AvgOfDAB);
DAB.clear();
}
//@Benedikt: Do I really have to cast here?
FuzzyFunctionNumOfSamplesMatches->setRightLimit(
static_cast<INDATATYPE>(SampleHistory.numberOfEntries()));
FuzzyFunctionNumOfSamplesMismatches->setRightLimit(
static_cast<INDATATYPE>(SampleHistory.numberOfEntries()));
- // TODO: calculate whether signal state is valid and properly set
- // SignalStateIsValid, SignalStateJustGotValid,
- // SignalStateIsValidAfterReentrance
-
- // TODO: check current signal state whether it drifts
-
- // TODO: write in SignalStateInfo
+ checkSignalStability();
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);
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.
for (unsigned int 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
//@benedikt: check if your partialfunctions can take infinity as
// argument
//@benedikt: same as before "->operator()"
ConfidenceFromRelativeDistance = 0;
} else {
ConfidenceFromRelativeDistance = FuzzyFunctionSampleMatches->operator()(
RelativeDistanceHistory[Case]);
}
ConfidenceOfWorstFittingSample = fuzzyAND<CONFDATATYPE>(
2, ConfidenceOfWorstFittingSample, ConfidenceFromRelativeDistance);
//@benedikt: do i have to pass the number 2 to tell the function how many
// arguments are following?
//@benedikt: same as before with "->operator()"
ConfidenceOfBestCase = fuzzyOR<CONFDATATYPE>(
2, ConfidenceOfBestCase,
fuzzyAND<CONFDATATYPE>(2, ConfidenceOfWorstFittingSample,
FuzzyFunctionNumOfSamplesMatches->operator()(
static_cast<CONFDATATYPE>(Case) + 1)));
}
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));
}
// sort all calculated distances so that the highest distance (will get the
// lowest confidence) is at the beginning.
RelativeDistanceHistory.sortDescending();
CONFDATATYPE ConfidenceOfBestFittingSample = 0;
// 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.
// TODO (future): to accelerate -> don't go until end. Confidences will only
// get higher. See comment in "CONFDATATYPE
// confidenceSampleMatchesSignalState(INDATATYPE Sample)".
for (unsigned int Case = 0;
Case < RelativeDistanceHistory.numberOfEntries(); Case++) {
CONFDATATYPE ConfidenceFromRelativeDistance;
if (std::isinf(RelativeDistanceHistory[Case])) {
ConfidenceFromRelativeDistance = 1;
} else {
//@benedikt: I had to change the following line. The outcommented line
// was the original one. I think it is ugly like that (new line). Do you
// have an idea how to make it better/more beautiful?
ConfidenceFromRelativeDistance =
FuzzyFunctionSampleMismatches->operator()(
RelativeDistanceHistory[Case]);
// FuzzyFunctionSampleMismatches(RelativeDistanceHistory[Case]);
}
//@benedikt: do i have to pass the number 2 to tell the function how many
// arguments are following?
ConfidenceOfBestFittingSample = fuzzyOR<CONFDATATYPE>(
2, ConfidenceOfBestFittingSample, ConfidenceFromRelativeDistance);
//@benedikt: do i have to pass the number 2 to tell the function how many
// arguments are following?
//@benedikt: same as before with "->operator()"
ConfidenceOfWorstCase = fuzzyAND<CONFDATATYPE>(
2, ConfidenceOfWorstCase,
fuzzyOR<CONFDATATYPE>(2, ConfidenceOfBestFittingSample,
FuzzyFunctionNumOfSamplesMismatches->operator()(
static_cast<CONFDATATYPE>(Case) + 1)));
}
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.
+ //@benedikt: same with "->operator()"
+ LowestConfidenceMatching =
+ fuzzyAND<CONFDATATYPE>(2, LowestConfidenceMatching,
+ FuzzyFunctionSampleMatches->operator()(
+ relativeDistance<INDATATYPE, PROCDATATYPE>(
+ Sample, HistorySample)));
+ //@benedikt: same with "->operator()"
+ HighestConfidenceMismatching =
+ fuzzyOR<CONFDATATYPE>(2, HighestConfidenceMismatching,
+ FuzzyFunctionSampleMismatches->operator()(
+ relativeDistance<INDATATYPE, PROCDATATYPE>(
+ Sample, HistorySample)));
+ }
+ LowestConfidenceMatchingHistory.addEntry(LowestConfidenceMatching);
+ HighestConfidenceMismatchingHistory.addEntry(HighestConfidenceMismatching);
+
+ LowestConfidenceMatching = LowestConfidenceMatchingHistory.lowestEntry();
+ HighestConfidenceMismatching =
+ HighestConfidenceMismatchingHistory.highestEntry();
+
+ //@benedikt: same with "->operator()"
+ CONFDATATYPE ConfidenceSignalStateIsValid = fuzzyAND<CONFDATATYPE>(
+ 2, LowestConfidenceMatching,
+ FuzzyFunctionNumOfSamplesMatches->operator()(static_cast<INDATATYPE>(
+ SignalStateInfo.NumberOfInsertedSamplesAfterEntrance)));
+ //@benedikt: same with "->operator()"
+ CONFDATATYPE ConfidenceSignalStateIsInvalid = fuzzyOR<CONFDATATYPE>(
+ 2, HighestConfidenceMismatching,
+ FuzzyFunctionNumOfSamplesMismatches->operator()(static_cast<INDATATYPE>(
+ SignalStateInfo.NumberOfInsertedSamplesAfterEntrance)));
+
+ if (ConfidenceSignalStateIsValid > ConfidenceSignalStateIsInvalid) {
+ if (SignalStateInfo.SignalStateIsValid) {
+ SignalStateInfo.SignalStateJustGotValid = false;
+ } else {
+ SignalStateInfo.SignalStateJustGotValid = true;
+ }
+ SignalStateInfo.SignalStateIsValid = true;
+ SignalStateInfo.SignalStateIsValidAfterReentrance = true;
+ }
+ }
+
+ void checkSignalStability(void) {
+ CONFDATATYPE ConfidenceSignalIsStable;
+ CONFDATATYPE ConfidenceSignalIsDrifting;
+
+ if (DABHistory.numberOfEntries() >= 2) {
+ //@benedikt: same "->operator()"
+ ConfidenceSignalIsStable = FuzzyFunctionSignalIsStable->operator()(
+ relativeDistance<INDATATYPE, PROCDATATYPE>(
+ DABHistory[DABHistory.numberOfEntries() - 1], DABHistory[0]));
+ //@benedikt: same "->operator()"
+ ConfidenceSignalIsDrifting = FuzzyFunctionSignalIsDrifting->operator()(
+ relativeDistance<INDATATYPE, PROCDATATYPE>(
+ DABHistory[DABHistory.numberOfEntries() - 1], DABHistory[0]));
+ } else {
+ // QUESTION: is it ok to say stable = 1 and drift = 0, when I simply don't
+ // know because the state is so new. Is there an option for saying don't
+ // know?
+ ConfidenceSignalIsStable = 1;
+ ConfidenceSignalIsDrifting = 0;
+ }
+
+ SignalStateInfo.SignalIsStable =
+ ConfidenceSignalIsStable >= ConfidenceSignalIsDrifting;
+ }
};
} // 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 d1ebec5..bd62965 100644
--- a/include/rosa/agent/SignalStateDetector.hpp
+++ b/include/rosa/agent/SignalStateDetector.hpp
@@ -1,357 +1,285 @@
//===-- rosa/agent/SignalStateDetector.hpp ----------------------------*- C++
//-*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \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/FunctionAbstractions.hpp"
#include "rosa/agent/Functionality.h"
#include "rosa/agent/SignalState.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, \param 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 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");
private:
// For the convinience to write a shorter data type name
using PartFuncPointer =
std::shared_ptr<PartialFunction<INDATATYPE, CONFDATATYPE>>;
using StepFuncPointer =
std::shared_ptr<StepFunction<INDATATYPE, CONFDATATYPE>>;
using SignalStatePtr =
std::shared_ptr<SignalState<INDATATYPE, CONFDATATYPE, PROCDATATYPE>>;
/// The NextSignalStateID is a counter variable which stores the ID which the
/// next signal state shall have.
unsigned int NextSignalStateID;
/// The SignalStateHasChanged is a flag that show whether a signal has changed
/// its state.
bool SignalStateHasChanged;
/// 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 vector in that all detected signal states are
/// saved.
DynamicLengthHistory<SignalStatePtr, HP> DetectedSignalStates;
/// The FuzzyFunctionSampleMatches is the fuzzy function that gives the
/// confidence how good the new sample matches another sample in the sample
/// history.
PartFuncPointer FuzzyFunctionSampleMatches;
/// The FuzzyFunctionSampleMismatches is the fuzzy function that gives the
/// confidence how bad the new sample matches another sample in the sample
/// history.
PartFuncPointer FuzzyFunctionSampleMismatches;
/// The FuzzyFunctionNumOfSamplesMatches is the fuzzy function that gives the
/// confidence how many samples from the sampe history match the new sample.
StepFuncPointer FuzzyFunctionNumOfSamplesMatches;
/// The FuzzyFunctionNumOfSamplesMismatches is the fuzzy function that gives
/// the confidence how many samples from the sampe history mismatch the new
/// sample.
StepFuncPointer FuzzyFunctionNumOfSamplesMismatches;
/// The FuzzyFunctionSignalIsDrifting is the fuzzy function that gives the
/// confidence how likely it is that the signal is drifting.
PartFuncPointer FuzzyFunctionSignalIsDrifting;
/// The FuzzyFunctionSignalIsStable is the fuzzy function that gives the
/// confidence how likely it is that the signal is stable (not drifting).
PartFuncPointer FuzzyFunctionSignalIsStable;
/// SampleHistorySize is the (maximum) size of the sample history.
unsigned int SampleHistorySize;
/// DABSize the size of a DAB (Discrete Average Block).
unsigned int DABSize;
/// DABHistorySize is the (maximum) size of the DAB history.
unsigned int DABHistorySize;
public:
/// Creates an instance by setting all parameters
/// \param FuzzyFunctionSampleMatches The FuzzyFunctionSampleMatches is the
/// fuzzy function that gives the confidence how good the new sample matches
/// another sample in the sample history.
///
/// \param FuzzyFunctionSampleMismatches The FuzzyFunctionSampleMismatches is
/// the fuzzy function that gives the confidence how bad the new sample
/// matches another sample in the sample history.
///
/// \param FuzzyFunctionNumOfSamplesMatches The
/// FuzzyFunctionNumOfSamplesMatches is the fuzzy function that gives the
/// confidence how many samples from the sampe history match the new sample.
///
/// \param FuzzyFunctionNumOfSamplesMismatches The
/// FuzzyFunctionNumOfSamplesMismatches is the fuzzy function that gives the
/// confidence how many samples from the sampe history mismatch the new
/// sample.
///
/// \param FuzzyFunctionSignalIsDrifting The FuzzyFunctionSignalIsDrifting is
/// the fuzzy function that gives the confidence how likely it is that the
/// signal (resp. the state of a signal) is drifting.
///
/// \param FuzzyFunctionSignalIsStable The FuzzyFunctionSignalIsStable is the
/// fuzzy function that gives the confidence how likely it is that the signal
/// (resp. the state of a signal) is stable (not drifting).
///
/// \param SampleHistorySize Sets the History size which will be used by \c
/// SignalState.
///
/// \param DABSize Sets the DAB size which will be used by \c SignalState.
///
/// \param DABHistorySize Sets the size which will be used by \c SignalState.
///
SignalStateDetector(unsigned int MaximumNumberOfSignalStates,
PartFuncPointer FuzzyFunctionSampleMatches,
PartFuncPointer FuzzyFunctionSampleMismatches,
StepFuncPointer FuzzyFunctionNumOfSamplesMatches,
StepFuncPointer FuzzyFunctionNumOfSamplesMismatches,
PartFuncPointer FuzzyFunctionSignalIsDrifting,
PartFuncPointer FuzzyFunctionSignalIsStable,
unsigned int SampleHistorySize, unsigned int DABSize,
unsigned int DABHistorySize) noexcept
: NextSignalStateID(1), SignalStateHasChanged(false),
CurrentSignalState(NULL),
FuzzyFunctionSampleMatches(FuzzyFunctionSampleMatches),
FuzzyFunctionSampleMismatches(FuzzyFunctionSampleMismatches),
FuzzyFunctionNumOfSamplesMatches(FuzzyFunctionNumOfSamplesMatches),
FuzzyFunctionNumOfSamplesMismatches(
FuzzyFunctionNumOfSamplesMismatches),
FuzzyFunctionSignalIsDrifting(FuzzyFunctionSignalIsDrifting),
FuzzyFunctionSignalIsStable(FuzzyFunctionSignalIsStable),
SampleHistorySize(SampleHistorySize), DABSize(DABSize),
DABHistorySize(DABHistorySize),
DetectedSignalStates(MaximumNumberOfSignalStates) {}
/// Destroys \p this object.
~SignalStateDetector(void) = default;
- /// Detects a 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 signal
- /// states.
- ///
- /// \param Sample is the actual sample of the observed signal.
- ///
- /// \return the signal state ID as unsigend integer type. Signal state IDs
- /// start with number 1; that means if there is no current signal state, the
- /// return value is 0.
- unsigned int detectSignalState(INDATATYPE Sample) noexcept {
- SignalStateInformation<CONFDATATYPE> SignalStateInfo =
- detectSignalState__debug(Sample);
- return SignalStateInfo.SignalStateID;
- }
-
- /// Gives information about the current signal state.
- ///
- /// \return a the signal state ID (as unsigned integer type) of the current
- /// signal state. Signal state IDs start with number 1; that means if there is
- /// no current signal state, the return value is 0.
- unsigned int currentSignalStateInformation(void) noexcept {
- SignalStateInformation<CONFDATATYPE> SignalStateInfo =
- currentSignalStateInformation__debug();
- if (SignalStateInfo) {
- return SignalStateInfo.SignalStateID;
- } else {
- return 0;
- }
- }
-
- /// 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 signalStateHasChanged(void) noexcept { return SignalStateHasChanged; }
-
-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>(
- NextSignalStateID, SampleHistorySize, DABSize, DABHistorySize,
- FuzzyFunctionSampleMatches, FuzzyFunctionSampleMismatches,
- FuzzyFunctionNumOfSamplesMatches, FuzzyFunctionNumOfSamplesMismatches,
- FuzzyFunctionSignalIsDrifting, FuzzyFunctionSignalIsStable));
-
- // @benedikt: todo: assert in history, which checks if push_back worked
- DetectedSignalStates.addEntry(S);
-
- return S;
- }
-
-#ifdef SIGNALSTATEDETECTORDEBUGMODE
-public:
-#else
-private:
-#endif // SIGNALSTATEDETECTORDEBUGMODE
-
- // @maxi is this a debug method or is it a method that will be used and
- // you simply want to have access to it in debug mode?
- // debug -> extend the preprocessor around the function
- // access -> remove the __debug from the name ( it is confusing)
- // if you want to have it marked as a debug method for auto
- // complete you can do something like this :
- //
- //#ifdef STATEDETECTORDEBUGMODE
- // public:
- // StateInfoPtr debug_detectState(INDATATYPE Sample) {
- // return detectState(Sample);
- // }
- //#endif // STATEDETECTORDEBUGMODE
- // private :
- // StateInfoPtr detectState(INDATATYPE Sample) { ...
- //
/// 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: return something const.. cannot remember exactly (ask benedikt)
- //
- // maybe: you are returning a pointer to the state info so who ever has that
- // pointer can actually change the information if you want to return only the
- // *current info* return a copy of the state info
- // like this:
- //
- // StateInfoPtr detectState__debug(INDATATYPE Sample) ->
- // StateInformation<CONFTYPE> detectState__debug(INDATATYPE Sample)
- //
- // return CurrentState->stateInformation(); ->
- // return *(CurrentState->stateInformation());
+ /// other parameters).
SignalStateInformation<CONFDATATYPE>
- detectSignalState__debug(INDATATYPE Sample) noexcept {
+ detectSignalState(INDATATYPE Sample) noexcept {
if (!CurrentSignalState) {
ASSERT(DetectedSignalStates.empty());
SignalStatePtr S = createNewSignalState();
CurrentSignalState = S;
} else {
CONFDATATYPE ConfidenceSampleMatchesSignalState =
CurrentSignalState->confidenceSampleMatchesSignalState(Sample);
CONFDATATYPE ConfidenceSampleMismatchesSignalState =
CurrentSignalState->confidenceSampleMismatchesSignalState(Sample);
if (ConfidenceSampleMatchesSignalState >
ConfidenceSampleMismatchesSignalState) {
SignalStateHasChanged = false;
} else {
SignalStateHasChanged = true;
if (CurrentSignalState->signalStateInformation().SignalStateIsValid) {
CurrentSignalState->leaveSignalState();
} else {
//@benedikt: changed from vector to history. can i still do the next
// line?
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;
//@benedikt: same question
for (auto &SavedSignalState : DetectedSignalStates) {
if (SavedSignalState != CurrentSignalState) {
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.SignalStateJustGotValid) {
NextSignalStateID++;
}
return SignalStateInfo;
}
-#ifdef SIGNALSTATEDETECTORDEBUGMODE
-public:
-#else
-private:
-#endif // SIGNALSTATEDETECTORDEBUGMODE
-
/// 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.
+ /// the current signal state or NULL if no current signal state exists.
SignalStateInformation<CONFDATATYPE>
- currentSignalStateInformation__debug(void) noexcept {
+ 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 signalStateHasChanged(void) noexcept { return SignalStateHasChanged; }
+
+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>(
+ NextSignalStateID, SampleHistorySize, DABSize, DABHistorySize,
+ FuzzyFunctionSampleMatches, FuzzyFunctionSampleMismatches,
+ FuzzyFunctionNumOfSamplesMatches, FuzzyFunctionNumOfSamplesMismatches,
+ FuzzyFunctionSignalIsDrifting, FuzzyFunctionSignalIsStable));
+
+ // @benedikt: todo: assert in history, which checks if push_back worked
+ DetectedSignalStates.addEntry(S);
+
+ return S;
+ }
};
} // End namespace agent
} // End namespace rosa
#endif // ROSA_AGENT_SIGNALSTATEDETECTOR_HPP

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jul 3, 10:47 PM (8 h, 35 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
157401
Default Alt Text
(61 KB)

Event Timeline