Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F375501
SignalState.hpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Size
20 KB
Referenced Files
None
Subscribers
None
SignalState.hpp
View Options
//===-- 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, \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"
);
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
;
/// 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
,
0
,
false
,
false
,
false
,
//@maxi added the Signal is stable bool
false
},
FuzzyFunctionSampleMatches
(
FuzzyFunctionSampleMatches
),
FuzzyFunctionSampleMismatches
(
FuzzyFunctionSampleMismatches
),
FuzzyFunctionNumOfSamplesMatches
(
FuzzyFunctionNumOfSamplesMatches
),
FuzzyFunctionNumOfSamplesMismatches
(
FuzzyFunctionNumOfSamplesMismatches
),
FuzzyFunctionSignalIsDrifting
(
FuzzyFunctionSignalIsDrifting
),
FuzzyFunctionSignalIsStable
(
FuzzyFunctionSignalIsStable
),
SampleHistory
(
SampleHistorySize
),
DAB
(
DABSize
),
DABHistory
(
DABHistorySize
),
LowestConfidenceMatchingHistory
(
SampleHistorySize
),
HighestConfidenceMismatchingHistory
(
SampleHistorySize
)
{}
/// Destroys \p this object.
~
SignalState
(
void
)
=
default
;
void
leaveSignalState
(
void
)
noexcept
{
DAB
.
clear
();
SignalStateInfo
.
NumberOfInsertedSamplesAfterEntrance
=
0
;
SignalStateInfo
.
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
()));
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
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Sun, Jun 8, 1:52 AM (1 d, 4 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
150327
Default Alt Text
SignalState.hpp (20 KB)
Attached To
Mode
R20 SoC_Rosa_repo
Attached
Detach File
Event Timeline
Log In to Comment