Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F386614
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Size
23 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/include/rosa/agent/State.hpp b/include/rosa/agent/State.hpp
index 39ef8af..e703a41 100644
--- a/include/rosa/agent/State.hpp
+++ b/include/rosa/agent/State.hpp
@@ -1,243 +1,256 @@
//===-- rosa/agent/State.hpp ----------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/agent/State.hpp
///
/// \author Maximilian Götzinger (maximilian.goetzinger@tuwien.ac.at)
///
/// \date 2019
///
/// \brief Definition of *state* *functionality*.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_AGENT_STATE_HPP
#define ROSA_AGENT_STATE_HPP
#include "rosa/agent/FunctionAbstractions.hpp"
#include "rosa/agent/Functionality.h"
#include "rosa/agent/History.hpp"
namespace rosa {
namespace agent {
-// TODO: think about call it VariableStateInformation
/// State conditions defining how the condition of a \c rosa::agent::State is
/// saved in \c rosa::agent::StateInformation.
-enum class StateCondition {
+enum class VariableStateCondition {
STABLE, ///< The state is stable
DRIFTING, ///< The state is drifting
UNKNOWN ///< The state is unknown
};
-template <typename CONFTYPE> struct StateInformation {
+template <typename CONFDATATYPE> struct StateInformation {
// Make sure the actual type arguments are matching our expectations.
- STATIC_ASSERT((std::is_arithmetic<CONFTYPE>::value),
+ STATIC_ASSERT((std::is_arithmetic<CONFDATATYPE>::value),
"confidence type is not to arithmetic");
/// The state ID saved as an unsigned integer number
unsigned int StateID;
/// The StateConfidence shows the overall confidence value of the state.
- CONFTYPE StateConfidence;
- /// The StateCondition shows the condition of a state (stable or drifting)
- StateCondition StateCondition;
+ CONFDATATYPE StateConfidence;
+ /// The VariableStateCondition shows the condition of a state (stable or
+ /// drifting)
+ VariableStateCondition VariableStateCondition;
/// The StateIsValid shows whether a state is valid or invalid. In this
/// context, valid means that enough samples which are in close proximitry
/// have been inserted into the state.
bool StateIsValid;
/// The StateJustGotValid shows whether a state got valid (toggled from
/// invalid to valid) during the current inserted sample.
bool StateJustGotValid;
/// The StateIsValidAfterReentrance shows whether a state is valid after the
/// variable changed back to it again.
bool StateIsValidAfterReentrance;
};
-// TODO: check whethter name of CONFTYPE is good for each context here -> mach
-// einen dritten datatype
-/// \tparam INDATATYPE type of input data, \tparam CONFTYPE is type of
-/// data in that the confidence values are given. It is also the type of data
-/// in which DABs are saved,
-template <typename INDATATYPE, typename CONFTYPE>
+// @Benedikt: now there are 4 datatypes. Do you think we can merge DISTDATATYPE
+// and DABDATATYPE somehow?
+/// \tparam INDATATYPE type of input data, \tparam CONFDATATYPE type of
+/// data in that the confidence values are given, \param DISTDATATYPE type of
+/// the relative distance, \tparam DABDATATYPE type of data in which DABs are
+/// saved.
+template <typename INDATATYPE, typename CONFDATATYPE, typename DISTDATATYPE,
+ typename DABDATATYPE>
class State : 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<CONFTYPE>::value),
+ STATIC_ASSERT((std::is_arithmetic<CONFDATATYPE>::value),
"DAB storage type is not to arithmetic");
private:
// For the convinience to write a shorter data type name
using PartFuncPointer =
- std::shared_ptr<PartialFunction<INDATATYPE, CONFTYPE>>;
- using StateInfoPtr = std::shared_ptr<StateInformation<CONFTYPE>>;
+ std::shared_ptr<PartialFunction<INDATATYPE, CONFDATATYPE>>;
+ using StepFuncPointer =
+ std::shared_ptr<StepFunction<INDATATYPE, CONFDATATYPE>>;
+ using StateInfoPtr = std::shared_ptr<StateInformation<CONFDATATYPE>>;
+ /// XXX - explain
StateInfoPtr StateInfo;
- // TODO: rename fuzzy function
- PartFuncPointer PartialFunctionSampleMatches;
- PartFuncPointer PartialFunctionSampleMismatches;
- std::shared_ptr<StepFunction<INDATATYPE, CONFTYPE>>
- StepFunctionNumOfSamplesMatches;
- std::shared_ptr<StepFunction<INDATATYPE, CONFTYPE>>
- StepFunctionNumOfSamplesMismatches;
- // TODO: partFunc Drift, NoDrift
-
+ /// XXX - explain
+ PartFuncPointer FuzzyFunctionSampleMatches;
+ /// XXX - explain
+ PartFuncPointer FuzzyFunctionSampleMismatches;
+ /// XXX - explain
+ StepFuncPointer FuzzyFunctionNumOfSamplesMatches;
+ /// XXX - explain
+ StepFuncPointer FuzzyFunctionNumOfSamplesMismatches;
+
+ /// XXX - explain
+ PartFuncPointer FuzzyFunctionSignalIsDrifting;
+ /// XXX - explain
+ PartFuncPointer FuzzyFunctionSignalIsStable;
+
+ /// XXX - explain
DynamicLengthHistory<INDATATYPE, HistoryPolicy::FIFO> SampleHistory;
+ /// XXX - explain
DynamicLengthHistory<INDATATYPE, HistoryPolicy::SRWF> DAB;
- DynamicLengthHistory<CONFTYPE, HistoryPolicy::LIFO> DABHistory;
+ /// XXX - explain
+ DynamicLengthHistory<DABDATATYPE, HistoryPolicy::LIFO> DABHistory;
/// The StateIsValid shows whether a state is valid or invalid. In this
/// context, valid means that enough samples which are in close proximitry
/// have been inserted into the state.
bool StateIsValid;
/// The StateIsValidAfterReentrance shows whether a state is valid after the
/// variable changed back to it again.
bool StateIsValidAfterReentrance;
public:
/// Creates an instance by setting all parameters
- State(unsigned int StateID, PartFuncPointer PartialFunctionSampleMatches,
- PartFuncPointer PartialFunctionSampleMismatches,
- std::shared_ptr<StepFunction<INDATATYPE, CONFTYPE>>
- StepFunctionNumOfSamplesMatches,
- std::shared_ptr<StepFunction<INDATATYPE, CONFTYPE>>
- StepFunctionNumOfSamplesMismatches,
+ State(unsigned int StateID, PartFuncPointer FuzzyFunctionSampleMatches,
+ PartFuncPointer FuzzyFunctionSampleMismatches,
+ StepFuncPointer FuzzyFunctionNumOfSamplesMatches,
+ StepFuncPointer FuzzyFunctionNumOfSamplesMismatches,
+ PartFuncPointer FuzzyFunctionSignalIsDrifting,
+ PartFuncPointer FuzzyFunctionSignalIsStable,
unsigned int sampleHistorySize, unsigned int DABSize,
unsigned int DABHistorySize) noexcept
- : StateInfo(StateID, 0, StateCondition::UNKNOWN, false, false),
+ : StateInfo(StateID, 0, VariableStateCondition::UNKNOWN, false, false),
SampleHistory(sampleHistorySize), DAB(DABSize),
DABHistory(DABHistorySize),
- PartialFunctionSampleMatches(PartialFunctionSampleMatches),
- PartialFunctionSampleMismatches(PartialFunctionSampleMismatches),
- StepFunctionNumOfSamplesMatches(StepFunctionNumOfSamplesMatches),
- StepFunctionNumOfSamplesMismatches(StepFunctionNumOfSamplesMismatches) {
- }
+ FuzzyFunctionSampleMatches(FuzzyFunctionSampleMatches),
+ FuzzyFunctionSampleMismatches(FuzzyFunctionSampleMismatches),
+ FuzzyFunctionNumOfSamplesMatches(FuzzyFunctionNumOfSamplesMatches),
+ FuzzyFunctionNumOfSamplesMismatches(
+ FuzzyFunctionNumOfSamplesMismatches),
+ FuzzyFunctionSignalIsDrifting(FuzzyFunctionSignalIsDrifting),
+ FuzzyFunctionSignalIsStable(FuzzyFunctionSignalIsStable) {}
/// Destroys \p this object.
~State(void) = default;
void leaveState(void) {
DAB.clear();
StateIsValidAfterReentrance = false;
}
- // TODO: maybe return immediatly StateInfo
void insertSample(INDATATYPE Sample) {
- // TODO: think about some error handling in case of not beeing able to add
- // an entry or create a new object
SampleHistory.addEntry(Sample);
DAB.addEntry(Sample);
if (DAB.full()) {
- CONFTYPE AvgOfDAB = DAB.template average<CONFTYPE>();
+ DABDATATYPE AvgOfDAB = DAB.template average<DABDATATYPE>();
DABHistory.addEntry(AvgOfDAB);
DAB.clear();
}
- //@Benedikt: stepfunction auch andere richtung
- StepFunctionNumOfSamplesMatches->setRightLimit(
+ // TODO @Benedikt: stepfunction auch andere richtung
+ FuzzyFunctionNumOfSamplesMatches->setRightLimit(
SampleHistory->numberOfEntries());
- StepFunctionNumOfSamplesMismatches->setRightLimit(
+ FuzzyFunctionNumOfSamplesMismatches->setRightLimit(
SampleHistory->numberOfEntries());
// TODO: calculate whether state is valid and properly set StateIsValid,
// StateJustGotValid, StateIsValidAfterReentrance
// TODO: check actual state whether it drifts
// TODO: write in StateInfo
}
// TODO: check this function again
- CONFTYPE
+ CONFDATATYPE
confSampleMatchesState(INDATATYPE sample) {
- CONFTYPE RelDiff;
- CONFTYPE HighestConf = 0;
+ DISTDATATYPE RelDist;
+ CONFDATATYPE HighestConf = 0;
// QUESTION: should I also use a history (array) for that?
- std::vector<CONFTYPE> RelDiffHistValuesAndSampleValue;
+ std::vector<DISTDATATYPE> RelDistHistValuesAndSampleValue;
for (auto &hs : SampleHistory) {
- RelDiff = relativeDifference(sample, hs);
- RelDiffHistValuesAndSampleValue.push_back(RelDiff);
+ RelDist = relativeDistance(sample, hs);
+ RelDistHistValuesAndSampleValue.push_back(RelDist);
}
- sort(begin(RelDiffHistValuesAndSampleValue),
- end(RelDiffHistValuesAndSampleValue));
+ sort(begin(RelDistHistValuesAndSampleValue),
+ end(RelDistHistValuesAndSampleValue));
// TODO (future): to accelerate -> don't start with 1
for (unsigned int numOfHistSamplesIncluded = 1;
- numOfHistSamplesIncluded <= RelDiffHistValuesAndSampleValue.size();
+ numOfHistSamplesIncluded <= RelDistHistValuesAndSampleValue.size();
numOfHistSamplesIncluded++) {
- CONFTYPE LowestConfOfSamplesIncluded = 1;
+ CONFDATATYPE LowestConfOfSamplesIncluded = 1;
unsigned int HistSampleCounter = 0;
- for (auto &D : RelDiffHistValuesAndSampleValue) {
+ for (auto &D : RelDistHistValuesAndSampleValue) {
if (HistSampleCounter >= numOfHistSamplesIncluded)
break;
- CONFTYPE confRelDiff;
+ CONFDATATYPE confRelDist;
// TODO: check if infinity check is needed here?
if (std::isinf(D) == false) {
- confRelDiff = PartialFunctionSampleMatches(D);
+ confRelDist = FuzzyFunctionSampleMatches(D);
} else {
- confRelDiff = 0;
+ confRelDist = 0;
}
// std::min is equal to Fuzzy AND -> maybe using
LowestConfOfSamplesIncluded =
- std::min(LowestConfOfSamplesIncluded, confRelDiff);
+ std::min(LowestConfOfSamplesIncluded, confRelDist);
HistSampleCounter++;
}
// std::max is equal to Fuzzy OR
+ // TODO: change old-style cast to one of these reinterpret_cast,
+ // static_cast, dynamic_cast or const_cast. Which should I use? Or should
+ // the HistSampleCounter variable already be CONFDATATYPE type?
HighestConf =
std::max(HighestConf, std::max(LowestConfOfSamplesIncluded,
- StepFunctionNumOfSamplesMatches(
- (CONFTYPE)HistSampleCounter)));
+ FuzzyFunctionNumOfSamplesMatches(
+ (CONFDATATYPE)HistSampleCounter)));
}
}
- CONFTYPE
+ CONFDATATYPE
confSampleMismatchesState(INDATATYPE sample) {
// TODO: do it in the same way as confSampleMatchesState(INDATATYPE sample)
}
/// Gives information about the current state.
///
/// \return a struct StateInformation that contains information about the
/// current state.
StateInfoPtr stateInformation(void) { return StateInfo; }
private:
- // QUESTION: is such a function already implemented? If not where should put
- // this function?
- // TODO: rename in distance
- // TODO: ask david where to move that
- CONFTYPE relativeDifference(INDATATYPE SampleValue, INDATATYPE HistoryValue) {
- CONFTYPE Diff = HistoryValue - SampleValue;
-
- if (Diff == 0) {
+ // TODO: Ask David where to move that function (or if it should stay here).
+ DISTDATATYPE relativeDistance(INDATATYPE SampleValue,
+ INDATATYPE HistoryValue) {
+ DISTDATATYPE Dist = HistoryValue - SampleValue;
+
+ if (Dist == 0) {
return 0;
} else {
- Diff = Diff / SampleValue;
- if (Diff < 0) {
- Diff = Diff * (-1);
+ Dist = Dist / SampleValue;
+ if (Dist < 0) {
+ Dist = Dist * (-1);
}
- return (Diff);
+ return (Dist);
}
}
};
} // End namespace agent
} // End namespace rosa
#endif // ROSA_AGENT_STATE_HPP
diff --git a/include/rosa/agent/StateDetector.hpp b/include/rosa/agent/StateDetector.hpp
index 7f31f53..2885471 100644
--- a/include/rosa/agent/StateDetector.hpp
+++ b/include/rosa/agent/StateDetector.hpp
@@ -1,267 +1,277 @@
//===-- rosa/agent/StateDetector.hpp ----------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \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/Functionality.h"
#include "rosa/agent/State.hpp"
#include <vector>
namespace rosa {
namespace agent {
/// Implements \c rosa::agent::StateDetector as a functionality that detects
/// states given on input samples.
///
/// \note This implementation is supposed to be used for samples of an
/// arithmetic type.
///
/// \tparam INDATATYPE is the type of input data, \tparam CONFTYPE is type of
/// data in that the confidence values are given
template <typename INDATATYPE, typename CONFTYPE>
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<CONFTYPE>::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, CONFTYPE>>;
+ using StepFuncPointer = std::shared_ptr<StepFunction<INDATATYPE, CONFTYPE>>;
using StatePtr = std::shared_ptr<StateInformation<CONFTYPE>>;
using StateInfoPtr = std::shared_ptr<StateInformation<CONFTYPE>>;
/// The NextStateID is a counter variable which stores the ID which the next
/// state shall have.
unsigned int NextStateID;
/// The StateHasChanged is a flag that show whether a state change has
/// happened.
bool StateHasChanged;
/// The CurrentState is a pointer to the (saved) state in which the actual
/// variable (signal) of the observed system is.
StatePtr CurrentState;
/// The DetectedStates is vector in that all detected states are saved.
std::vector<StatePtr> DetectedStates;
/// The FuzzyFunctionSampleMatches is the fuzzy function that gives the
/// convidence how good the new sample matches another sample in the sample
/// history.
PartFuncPointer FuzzyFunctionSampleMatches;
/// The FuzzyFunctionSampleMatches is the fuzzy function that gives the
/// convidence how bad the new sample matches another sample in the sample
/// history.
PartFuncPointer FuzzyFunctionSampleMismatches;
/// The FuzzyFunctionSampleMatches is the fuzzy function that gives the
/// convidence how many samples from the sampe history match the new sample.
- PartFuncPointer FuzzyFunctionNumOfSamplesMatches;
+ StepFuncPointer FuzzyFunctionNumOfSamplesMatches;
/// The FuzzyFunctionSampleMatches is the fuzzy function that gives the
/// convidence how many samples from the sampe history mismatch the new
/// sample.
- PartFuncPointer FuzzyFunctionNumOfSamplesMismatches;
+ StepFuncPointer FuzzyFunctionNumOfSamplesMismatches;
+
+ /// XXX - explain
+ PartFuncPointer FuzzyFunctionSignalIsDrifting;
+ /// XXX - explain
+ 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
StateDetector(PartFuncPointer FuzzyFunctionSampleMatches,
PartFuncPointer FuzzyFunctionSampleMismatches,
- PartFuncPointer FuzzyFunctionNumOfSamplesMatches,
- PartFuncPointer FuzzyFunctionNumOfSamplesMismatches,
+ StepFuncPointer FuzzyFunctionNumOfSamplesMatches,
+ StepFuncPointer FuzzyFunctionNumOfSamplesMismatches,
+ PartFuncPointer FuzzyFunctionSignalIsDrifting,
+ PartFuncPointer FuzzyFunctionSignalIsStable,
unsigned int SampleHistorySize, unsigned int DABSize,
unsigned int DABHistorySize) noexcept
: NextStateID(1), StateHasChanged(false), CurrentState(NULL),
FuzzyFunctionSampleMatches(FuzzyFunctionSampleMatches),
FuzzyFunctionSampleMismatches(FuzzyFunctionSampleMismatches),
FuzzyFunctionNumOfSamplesMatches(FuzzyFunctionNumOfSamplesMatches),
FuzzyFunctionNumOfSamplesMismatches(
FuzzyFunctionNumOfSamplesMismatches),
+ FuzzyFunctionSignalIsDrifting(FuzzyFunctionSignalIsDrifting),
+ FuzzyFunctionSignalIsStable(FuzzyFunctionSignalIsStable),
SampleHistorySize(SampleHistorySize), DABSize(DABSize),
DABHistorySize(DABHistorySize) {}
/// Destroys \p this object.
~StateDetector(void) = default;
/// Detects the state to which the new sample belongs or create a new 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 state ID as unsigend integer type. State IDs start with number
/// 1; that means if there is no current state, the return value is 0.
unsigned int detectState(INDATATYPE Sample) {
StateInfoPtr StateInfo = detectState__debug(Sample);
return StateInfo->StateID;
}
/// Gives information about the current state.
///
/// \return a the State ID (as unsigned integer type) of the current state.
/// State IDs start with number 1; that means if there is no current state,
/// the return value is 0.
unsigned int currentStateInformation(void) {
StateInfoPtr StateInfo = currentStateInformation__debug();
if (StateInfo) {
return StateInfo->StateID;
} else {
return 0;
}
}
/// Gives information whether a state change has happened or not.
///
/// \return true if a state change has happened, and false if not.
bool stateHasChanged(void) { return StateHasChanged; }
private:
/// Creates a new state and adds this state to the state vector in which all
/// known states are saved.
///
/// \param SampleHistorySize the (maximum) size of the sample history.
/// \param DABSize the size of a DAB.
/// \param DABHistorySize the (maximum) size of the DAB history.
/// \param FuzzyFunctionSampleMatches the
/// \param FuzzyFunctionSampleMismatches
/// \param FuzzyFunctionNumOfSamplesMatches
/// \param FuzzyFunctionNumOfSamplesMismatches
///
/// \return the new created state or NULL if no state could be created.
StatePtr createNewState(void) {
StatePtr S = new (std::nothrow) State(
SampleHistorySize, DABSize, DABHistorySize, FuzzyFunctionSampleMatches,
FuzzyFunctionSampleMismatches, FuzzyFunctionNumOfSamplesMatches,
FuzzyFunctionNumOfSamplesMismatches);
// TODO: maybe assert which checks if push_back worked (ask benedikt)
DetectedStates.push_back(S);
return S;
}
#ifdef STATEDETECTORDEBUGMODE
public:
#else
private:
#endif // STATEDETECTORDEBUGMODE
/// Detects the state to which the new sample belongs or create a new 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 actual state (state ID and other
/// parameters).
// TODO: return something const.. cannot remember exactly (ask benedikt)
StateInfoPtr detectState__debug(INDATATYPE Sample) {
if (!CurrentState) {
ASSERT(DetectedStates.empty());
StatePtr S = createNewState();
CurrentState = S;
} else {
CONFTYPE ConfidenceSampleMatchesState =
CurrentState->confSampleMatchesState(Sample);
CONFTYPE ConfidenceSampleMismatchesState =
CurrentState->confSampleMismatchesState(Sample);
if (ConfidenceSampleMatchesState > ConfidenceSampleMismatchesState) {
StateHasChanged = false;
} else {
StateHasChanged = true;
if (CurrentState->stateInformation()->StateIsValid) {
CurrentState->leaveState();
} else {
DetectedStates.erase(std::find(DetectedStates.begin(),
DetectedStates.end(), CurrentState));
}
// TODO (future): additionally save averages to enable fast
// iteration through recorded state vector (maybe sort vector based on
// these average values)
CurrentState = nullptr;
for (auto &SavedState : DetectedStates) {
if (SavedState != CurrentState) {
CONFTYPE ConfidenceSampleMatchesState =
SavedState->confSampleMatchesState(Sample);
CONFTYPE ConfidenceSampleMismatchesState =
SavedState->confSampleMismatchesState(Sample);
if (ConfidenceSampleMatchesState >
ConfidenceSampleMismatchesState) {
// TODO (future): maybe it would be better to compare
// ConfidenceSampleMatchesState of all states in the vector in
// order to find the best matching state.
CurrentState = SavedState;
break;
}
}
}
if (!CurrentState) {
StatePtr S = createNewState();
CurrentState = S;
}
}
}
StateInfoPtr StateInfo = CurrentState->insertSample(Sample);
if (StateInfo->StateJustGotValid) {
NextStateID++;
}
return CurrentState->stateInformation();
}
#ifdef STATEDETECTORDEBUGMODE
public:
#else
private:
#endif // STATEDETECTORDEBUGMODE
/// Gives information about the current state.
///
/// \return a struct StateInformation that contains information about the
/// current state or NULL if no current state exists.
StateInfoPtr currentStateInformation__debug(void) {
if (CurrentState) {
return CurrentState->stateInformation();
} else {
return NULL;
}
}
};
} // End namespace agent
} // End namespace rosa
#endif // ROSA_AGENT_STATEDETECTOR_HPP
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Jul 3, 10:49 PM (2 h, 42 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
157403
Default Alt Text
(23 KB)
Attached To
Mode
R20 SoC_Rosa_repo
Attached
Detach File
Event Timeline
Log In to Comment