Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F376164
sa-ews1.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Size
23 KB
Referenced Files
None
Subscribers
None
sa-ews1.cpp
View Options
//===-- apps/sa-ews1/sa-ews1.cpp --------------------------------*- C++ -*-===//
//
// The RoSA Framework -- Application SA-EWS1
//
// Distributed under the terms and conditions of the Boost Software License 1.0.
// See accompanying file LICENSE.
//
// If you did not receive a copy of the license file, see
// http://www.boost.org/LICENSE_1_0.txt.
//
//===----------------------------------------------------------------------===//
///
/// \file apps/sa-ews1/sa-ews1.cpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
/// Maximilian Goetzinger (maxgot@utu.fi)
///
/// \date 2017-2020
///
/// \brief The application SA-EWS1 implements the case study from the paper:
/// M. Götzinger, A. Anzanpour, I. Azimi, N. TaheriNejad, and A. M. Rahmani:
/// Enhancing the Self-Aware Early Warning Score System Through Fuzzified Data
/// Reliability Assessment. DOI: 10.1007/978-3-319-98551-0_1
//===----------------------------------------------------------------------===//
#include
"rosa/agent/Abstraction.hpp"
#include
"rosa/agent/CrossCombinator.h"
#include
"rosa/agent/ReliabilityConfidenceCombination.h"
#include
"rosa/config/version.h"
#include
"rosa/app/Application.hpp"
#include
"rosa/support/csv/CSVReader.hpp"
#include
"rosa/support/csv/CSVWriter.hpp"
#include
"rosa/support/iterator/split_tuple_iterator.hpp"
#include
"cxxopts/cxxopts.hpp"
#include
<fstream>
using
namespace
rosa
;
using
namespace
rosa
::
agent
;
using
namespace
rosa
::
app
;
using
namespace
rosa
::
terminal
;
using
namespace
rosa
::
csv
;
using
namespace
rosa
::
iterator
;
const
std
::
string
AppName
=
"SA-EWS1"
;
/// Representation type of warning levels.
/// \note Make sure it suits all defined enumeration values.
using
WarningScoreType
=
uint8_t
;
/// Warning levels for abstraction.
enum
WarningScore
:
WarningScoreType
{
No
=
0
,
Low
=
1
,
High
=
2
,
Emergency
=
3
};
/// Vector with all possible warning levels.
std
::
vector
<
WarningScore
>
warningScores
=
{
No
,
Low
,
High
,
Emergency
};
/// Type used to represent reliability values.
using
ReliabilityType
=
double
;
/// The result type of low-level functions.
using
WarningValue
=
AppTuple
<
WarningScoreType
,
ReliabilityType
>
;
/// Helper function creating an application sensor and setting its execution
/// policy for decimation.
///
/// \note The sensors are created without defining a normal generator function,
/// which is suitable for simulation only.
///
/// \tparam T type of values for the sensor to generate
///
/// \param App the application to create the sensor in
/// \param Name name of the new sensor
/// \param Decimation the decimation parameter
///
/// \return handle for the new sensor
template
<
typename
T
>
AgentHandle
createSensor
(
std
::
unique_ptr
<
Application
>
&
App
,
const
std
::
string
&
Name
,
const
size_t
Decimation
)
{
AgentHandle
Sensor
=
App
->
createSensor
<
T
>
(
Name
);
App
->
setExecutionPolicy
(
Sensor
,
AppExecutionPolicy
::
decimation
(
Decimation
));
return
Sensor
;
}
/// Helper function creating an application agent for pre-processing sensory
/// values and setting its execution policy for decimation.
///
/// Received values are assessed for reliability and abstracted into a \c
/// WarningScore. The result of the processing function is a pair of assessed
/// reliability and abstracted values.
///
/// \note The result, \c WarningScore, is returned as \c WarningScoreType
/// because enumeration types are not integrated into built-in types. Hence, a
/// master to these agents receives its input as \c WarningScoreType values, and
/// may cast them to \c WarningScore explicitly.
///
/// \tparam T type of values to receive from the sensor
///
/// \param App the application to create the agent in
/// \param Name name of the new agent
/// \param Decimation the decimation parameter
/// \param A abstraction to use
/// \param R reliability/confidence combination to use
///
/// \return handle for the new agent
template
<
typename
T
>
AgentHandle
createLowLevelAgent
(
std
::
unique_ptr
<
Application
>
&
App
,
const
std
::
string
&
Name
,
const
size_t
Decimation
,
const
Abstraction
<
T
,
WarningScore
>
&
A
,
ReliabilityAndConfidenceCombination
<
T
,
WarningScore
,
ReliabilityType
>
&
R
)
{
using
result
=
Optional
<
WarningValue
>
;
using
input
=
AppTuple
<
T
>
;
using
handler
=
std
::
function
<
result
(
std
::
pair
<
input
,
bool
>
)
>
;
AgentHandle
Agent
=
App
->
createAgent
(
Name
,
handler
([
&
,
Name
](
std
::
pair
<
input
,
bool
>
I
)
->
result
{
LOG_INFO_STREAM
<<
"
\n
******
\n
"
<<
Name
<<
" "
<<
(
I
.
second
?
"<New>"
:
"<Old>"
)
<<
" value: "
<<
PRINTABLE
(
std
::
get
<
0
>
(
I
.
first
))
<<
"
\n
******
\n
"
;
const
auto
SensorValue
=
std
::
get
<
0
>
(
I
.
first
);
const
WarningScoreType
Score
=
A
(
SensorValue
);
const
ReliabilityType
InputReliability
=
R
.
getInputReliability
(
SensorValue
);
return
{
WarningValue
(
Score
,
InputReliability
)};
}));
App
->
setExecutionPolicy
(
Agent
,
AppExecutionPolicy
::
decimation
(
Decimation
));
return
Agent
;
}
/// Helper function to print an error message in red color to the terminal and
/// exit from the application.
///
/// \note The function never returns as it calles `exit()`.
///
/// \param Error error message
/// \param ExitCode exit code to return from the application
void
logErrorAndExit
(
const
std
::
string
&
Error
,
const
int
ExitCode
)
{
LOG_ERROR_STREAM
<<
Color
::
Red
<<
Error
<<
Color
::
Default
<<
std
::
endl
;
exit
(
ExitCode
);
}
int
main
(
int
argc
,
char
*
argv
[])
{
LOG_INFO_STREAM
<<
'\n'
<<
library_string
()
<<
" -- "
<<
Color
::
Red
<<
AppName
<<
" app"
<<
Color
::
Default
<<
'\n'
;
/// Paths for the CSV files for simulation.
///
///@{
std
::
string
DataCSVPath
;
std
::
string
ScoreCSVPath
;
///@}
/// Whether CSV files have header row at the beginning.
bool
CSVHeader
=
false
;
/// Delimiter character in CSV files.
char
CSVDelimiter
=
','
;
/// Decimation of sensors and agents.
size_t
Decimation
=
1
;
/// How many cycles of simulation to perform.
size_t
NumberOfSimulationCycles
=
16
;
// Handle command-line arguments.
try
{
cxxopts
::
Options
Options
(
argv
[
0
],
library_string
()
+
" -- "
+
AppName
);
Options
.
add_options
()(
"i,input"
,
"Path for the CSV file providing input data"
,
cxxopts
::
value
(
DataCSVPath
),
"file"
)
(
"o,output"
,
"Path for the CSV file to write output scores"
,
cxxopts
::
value
(
ScoreCSVPath
),
"file"
)
(
"header"
,
"CSV files have header row"
,
cxxopts
::
value
(
CSVHeader
)
->
default_value
(
"false"
))
(
"delimiter"
,
"CSV delimiter character"
,
cxxopts
::
value
(
CSVDelimiter
)
->
default_value
(
","
),
"char"
)
(
"d,decimation"
,
"Decimation of sensors and agents"
,
cxxopts
::
value
(
Decimation
)
->
default_value
(
"1"
),
"int"
)
(
"c,cycles"
,
"Number of simulation cycles to perform"
,
cxxopts
::
value
(
NumberOfSimulationCycles
)
->
default_value
(
"16"
),
"int"
)
(
"h,help"
,
"Print usage"
);
auto
Args
=
Options
.
parse
(
argc
,
argv
);
if
(
Args
.
count
(
"help"
))
{
LOG_INFO_STREAM
<<
'\n'
<<
Options
.
help
()
<<
std
::
endl
;
exit
(
0
);
}
if
(
Args
.
count
(
"input"
)
==
0
)
{
throw
std
::
invalid_argument
(
"Argument --input must be defined."
);
}
if
(
Args
.
count
(
"output"
)
==
0
)
{
throw
std
::
invalid_argument
(
"Argument --output must be defined."
);
}
}
catch
(
const
cxxopts
::
OptionException
&
e
)
{
logErrorAndExit
(
e
.
what
(),
1
);
}
catch
(
const
std
::
invalid_argument
&
e
)
{
logErrorAndExit
(
e
.
what
(),
1
);
}
std
::
unique_ptr
<
Application
>
App
=
Application
::
create
(
AppName
);
//
// Relevant types and definitions.
//
using
HRType
=
int32_t
;
using
HRParFun
=
PartialFunction
<
HRType
,
ReliabilityType
>
;
using
HRLinFun
=
LinearFunction
<
HRType
,
ReliabilityType
>
;
using
BRType
=
int32_t
;
using
BRParFun
=
PartialFunction
<
BRType
,
ReliabilityType
>
;
using
BRLinFun
=
LinearFunction
<
BRType
,
ReliabilityType
>
;
using
SpO2Type
=
int32_t
;
using
SpO2ParFun
=
PartialFunction
<
SpO2Type
,
ReliabilityType
>
;
using
SpO2LinFun
=
LinearFunction
<
SpO2Type
,
ReliabilityType
>
;
using
BPSysType
=
int32_t
;
using
BPSysParFun
=
PartialFunction
<
BPSysType
,
ReliabilityType
>
;
using
BPSysLinFun
=
LinearFunction
<
BPSysType
,
ReliabilityType
>
;
using
BodyTempType
=
float
;
using
BodyTempParFun
=
PartialFunction
<
BodyTempType
,
ReliabilityType
>
;
using
BodyTempLinFun
=
LinearFunction
<
BodyTempType
,
ReliabilityType
>
;
//
// Create application sensors.
//
LOG_INFO
(
"Creating sensors."
);
// All sensors are created without defining a normal generator function, but
// with the default value of the second argument. That, however, requires the
// data type to be explicitly defined. This is good for simulation only.
AgentHandle
HRSensor
=
createSensor
<
HRType
>
(
App
,
"HR Sensor"
,
Decimation
);
AgentHandle
BRSensor
=
createSensor
<
BRType
>
(
App
,
"BR Sensor"
,
Decimation
);
AgentHandle
SpO2Sensor
=
createSensor
<
SpO2Type
>
(
App
,
"SpO2 Sensor"
,
Decimation
);
AgentHandle
BPSysSensor
=
createSensor
<
BPSysType
>
(
App
,
"BPSys Sensor"
,
Decimation
);
AgentHandle
BodyTempSensor
=
createSensor
<
BodyTempType
>
(
App
,
"BodyTemp Sensor"
,
Decimation
);
//
// Create functionalities.
//
LOG_INFO
(
"Creating Functionalities for Agents."
);
//
// Define abstractions.
//
RangeAbstraction
<
HRType
,
WarningScore
>
HRAbstraction
(
{{{
0
,
40
},
Emergency
},
{{
40
,
51
},
High
},
{{
51
,
60
},
Low
},
{{
60
,
100
},
No
},
{{
100
,
110
},
Low
},
{{
110
,
129
},
High
},
{{
129
,
200
},
Emergency
}},
Emergency
);
RangeAbstraction
<
BRType
,
WarningScore
>
BRAbstraction
({{{
0
,
9
},
High
},
{{
9
,
14
},
No
},
{{
14
,
20
},
Low
},
{{
20
,
29
},
High
},
{{
29
,
50
},
Emergency
}},
Emergency
);
RangeAbstraction
<
SpO2Type
,
WarningScore
>
SpO2Abstraction
(
{{{
1
,
85
},
Emergency
},
{{
85
,
90
},
High
},
{{
90
,
95
},
Low
},
{{
95
,
100
},
No
}},
Emergency
);
RangeAbstraction
<
BPSysType
,
WarningScore
>
BPSysAbstraction
(
{{{
0
,
70
},
Emergency
},
{{
70
,
81
},
High
},
{{
81
,
101
},
Low
},
{{
101
,
149
},
No
},
{{
149
,
169
},
Low
},
{{
169
,
179
},
High
},
{{
179
,
200
},
Emergency
}},
Emergency
);
RangeAbstraction
<
BodyTempType
,
WarningScore
>
BodyTempAbstraction
(
{{{
0.f
,
28.f
},
Emergency
},
{{
28.f
,
32.f
},
High
},
{{
32.f
,
35.f
},
Low
},
{{
35.f
,
38.f
},
No
},
{{
38.f
,
39.5f
},
High
},
{{
39.5f
,
100.f
},
Emergency
}},
Emergency
);
//
// Define reliabilities.
//
ReliabilityAndConfidenceCombination
<
HRType
,
WarningScore
,
ReliabilityType
>
HRReliability
;
HRReliability
.
setTimeStep
(
1
);
std
::
shared_ptr
<
Abstraction
<
HRType
,
ReliabilityType
>>
HRAbsRel
(
new
HRParFun
({{{
0
,
200
},
std
::
make_shared
<
HRLinFun
>
(
1
,
0
)},
{{
200
,
300
},
std
::
make_shared
<
HRLinFun
>
(
200
,
1
,
300
,
0
)}},
0
));
HRReliability
.
setAbsoluteReliabilityFunction
(
HRAbsRel
);
std
::
shared_ptr
<
Abstraction
<
HRType
,
ReliabilityType
>>
HRRelSlope
(
new
HRParFun
(
{{{
-200
,
-100
},
std
::
make_shared
<
HRLinFun
>
(
-200
,
0
,
-100
,
1
)},
{{
-100
,
100
},
std
::
make_shared
<
HRLinFun
>
(
1
,
0
)},
{{
100
,
200
},
std
::
make_shared
<
HRLinFun
>
(
100
,
1
,
200
,
0
)}},
0
));
HRReliability
.
setReliabilitySlopeFunction
(
HRRelSlope
);
ReliabilityAndConfidenceCombination
<
BRType
,
WarningScore
,
ReliabilityType
>
BRReliability
;
BRReliability
.
setTimeStep
(
1
);
std
::
shared_ptr
<
Abstraction
<
BRType
,
ReliabilityType
>>
BRAbsRel
(
new
BRParFun
({{{
0
,
40
},
std
::
make_shared
<
BRLinFun
>
(
1
,
0
)},
{{
40
,
60
},
std
::
make_shared
<
BRLinFun
>
(
40
,
1
,
60
,
0
)}},
0
));
BRReliability
.
setAbsoluteReliabilityFunction
(
BRAbsRel
);
std
::
shared_ptr
<
Abstraction
<
BRType
,
ReliabilityType
>>
BRRelSlope
(
new
BRParFun
({{{
-30
,
-20
},
std
::
make_shared
<
BRLinFun
>
(
-30
,
0
,
-20
,
1
)},
{{
-20
,
20
},
std
::
make_shared
<
BRLinFun
>
(
1
,
0
)},
{{
20
,
30
},
std
::
make_shared
<
BRLinFun
>
(
20
,
1
,
30
,
0
)}},
0
));
BRReliability
.
setReliabilitySlopeFunction
(
BRRelSlope
);
ReliabilityAndConfidenceCombination
<
SpO2Type
,
WarningScore
,
ReliabilityType
>
SpO2Reliability
;
SpO2Reliability
.
setTimeStep
(
1
);
std
::
shared_ptr
<
Abstraction
<
SpO2Type
,
ReliabilityType
>>
SpO2AbsRel
(
new
SpO2ParFun
(
{
{{
0
,
100
},
std
::
make_shared
<
SpO2LinFun
>
(
1
,
0
)},
},
0
));
SpO2Reliability
.
setAbsoluteReliabilityFunction
(
SpO2AbsRel
);
std
::
shared_ptr
<
Abstraction
<
SpO2Type
,
ReliabilityType
>>
SpO2RelSlope
(
new
SpO2ParFun
({{{
-8
,
-5
},
std
::
make_shared
<
SpO2LinFun
>
(
-8
,
0
,
-5
,
1
)},
{{
-5
,
5
},
std
::
make_shared
<
SpO2LinFun
>
(
1
,
0
)},
{{
5
,
8
},
std
::
make_shared
<
SpO2LinFun
>
(
5
,
1
,
8
,
0
)}},
0
));
SpO2Reliability
.
setReliabilitySlopeFunction
(
SpO2RelSlope
);
ReliabilityAndConfidenceCombination
<
BPSysType
,
WarningScore
,
ReliabilityType
>
BPSysReliability
;
BPSysReliability
.
setTimeStep
(
1
);
std
::
shared_ptr
<
Abstraction
<
BPSysType
,
ReliabilityType
>>
BPSysAbsRel
(
new
BPSysParFun
(
{{{
0
,
260
},
std
::
make_shared
<
BPSysLinFun
>
(
1
,
0
)},
{{
260
,
400
},
std
::
make_shared
<
BPSysLinFun
>
(
260
,
1
,
400
,
0
)}},
0
));
BPSysReliability
.
setAbsoluteReliabilityFunction
(
BPSysAbsRel
);
std
::
shared_ptr
<
Abstraction
<
BPSysType
,
ReliabilityType
>>
BPSysRelSlope
(
new
BPSysParFun
(
{{{
-100
,
-50
},
std
::
make_shared
<
BPSysLinFun
>
(
-100
,
0
,
-50
,
1
)},
{{
-50
,
50
},
std
::
make_shared
<
BPSysLinFun
>
(
1
,
0
)},
{{
50
,
100
},
std
::
make_shared
<
BPSysLinFun
>
(
50
,
1
,
100
,
0
)}},
0
));
BPSysReliability
.
setReliabilitySlopeFunction
(
BPSysRelSlope
);
ReliabilityAndConfidenceCombination
<
BodyTempType
,
WarningScore
,
ReliabilityType
>
BodyTempReliability
;
BodyTempReliability
.
setTimeStep
(
1
);
std
::
shared_ptr
<
Abstraction
<
BodyTempType
,
ReliabilityType
>>
BodyTempAbsRel
(
new
BodyTempParFun
(
{{{
-70.f
,
-50.f
},
std
::
make_shared
<
BodyTempLinFun
>
(
-70.f
,
0
,
-50.f
,
1
)},
{{
-50.f
,
40.f
},
std
::
make_shared
<
BodyTempLinFun
>
(
1
,
0
)},
{{
40.f
,
60.f
},
std
::
make_shared
<
BodyTempLinFun
>
(
40.f
,
1
,
60.f
,
0
)}},
0
));
BodyTempReliability
.
setAbsoluteReliabilityFunction
(
BodyTempAbsRel
);
std
::
shared_ptr
<
Abstraction
<
BodyTempType
,
ReliabilityType
>>
BodyTempRelSlope
(
new
BodyTempParFun
(
{{{
-0.1f
,
-0.05f
},
std
::
make_shared
<
BodyTempLinFun
>
(
-0.1f
,
0
,
-0.05f
,
1
)},
{{
-0.05f
,
0.05f
},
std
::
make_shared
<
BodyTempLinFun
>
(
1
,
0
)},
{{
0.05f
,
0.1f
},
std
::
make_shared
<
BodyTempLinFun
>
(
0.05f
,
1
,
0.1f
,
0
)}},
0
));
BodyTempReliability
.
setReliabilitySlopeFunction
(
BodyTempRelSlope
);
//
// Create low-level application agents with \c createLowLevelAgent.
//
LOG_INFO
(
"Creating low-level agents."
);
AgentHandle
HRAgent
=
createLowLevelAgent
(
App
,
"HR Agent"
,
Decimation
,
HRAbstraction
,
HRReliability
);
AgentHandle
BRAgent
=
createLowLevelAgent
(
App
,
"BR Agent"
,
Decimation
,
BRAbstraction
,
BRReliability
);
AgentHandle
SpO2Agent
=
createLowLevelAgent
(
App
,
"SpO2 Agent"
,
Decimation
,
SpO2Abstraction
,
SpO2Reliability
);
AgentHandle
BPSysAgent
=
createLowLevelAgent
(
App
,
"BPSys Agent"
,
Decimation
,
BPSysAbstraction
,
BPSysReliability
);
AgentHandle
BodyTempAgent
=
createLowLevelAgent
(
App
,
"BodyTemp Agent"
,
Decimation
,
BodyTempAbstraction
,
BodyTempReliability
);
//
// Connect sensors to low-level agents.
//
LOG_INFO
(
"Connect sensors to their corresponding low-level agents."
);
App
->
connectSensor
(
HRAgent
,
0
,
HRSensor
,
"HR Sensor Channel"
);
App
->
connectSensor
(
BRAgent
,
0
,
BRSensor
,
"BR Sensor Channel"
);
App
->
connectSensor
(
SpO2Agent
,
0
,
SpO2Sensor
,
"SpO2 Sensor Channel"
);
App
->
connectSensor
(
BPSysAgent
,
0
,
BPSysSensor
,
"BPSys Sensor Channel"
);
App
->
connectSensor
(
BodyTempAgent
,
0
,
BodyTempSensor
,
"BodyTemp Sensor Channel"
);
//
// Create a high-level application agent.
//
LOG_INFO
(
"Create high-level agent."
);
// Slave positions on BodyAgent.
enum
SlaveIndex
:
rosa
::
id_t
{
HRIdx
=
0
,
BRIdx
=
1
,
SpO2Idx
=
2
,
BPSysIdx
=
3
,
BodyTempIdx
=
4
};
CrossCombinator
<
WarningScoreType
,
ReliabilityType
>
BodyCrossCombinator
;
BodyCrossCombinator
.
setCrossLikelinessParameter
(
1.5
);
using
WarningLikelinessFun
=
LikelinessFunction
<
WarningScoreType
,
ReliabilityType
>
;
std
::
shared_ptr
<
WarningLikelinessFun
>
BRCrossLikelinessFun
(
new
WarningLikelinessFun
(
0.6
));
BodyCrossCombinator
.
addCrossLikelinessProfile
(
HRIdx
,
BRIdx
,
BRCrossLikelinessFun
);
BodyCrossCombinator
.
addCrossLikelinessProfile
(
BRIdx
,
HRIdx
,
BRCrossLikelinessFun
);
BodyCrossCombinator
.
addCrossLikelinessProfile
(
BRIdx
,
SpO2Idx
,
BRCrossLikelinessFun
);
BodyCrossCombinator
.
addCrossLikelinessProfile
(
BRIdx
,
BPSysIdx
,
BRCrossLikelinessFun
);
BodyCrossCombinator
.
addCrossLikelinessProfile
(
BRIdx
,
BodyTempIdx
,
BRCrossLikelinessFun
);
BodyCrossCombinator
.
addCrossLikelinessProfile
(
SpO2Idx
,
BRIdx
,
BRCrossLikelinessFun
);
BodyCrossCombinator
.
addCrossLikelinessProfile
(
BPSysIdx
,
BRIdx
,
BRCrossLikelinessFun
);
BodyCrossCombinator
.
addCrossLikelinessProfile
(
BodyTempIdx
,
BRIdx
,
BRCrossLikelinessFun
);
std
::
shared_ptr
<
WarningLikelinessFun
>
HRBPCrossLikelinessFun
(
new
WarningLikelinessFun
(
2.5
));
BodyCrossCombinator
.
addCrossLikelinessProfile
(
HRIdx
,
BPSysIdx
,
HRBPCrossLikelinessFun
);
BodyCrossCombinator
.
addCrossLikelinessProfile
(
BPSysIdx
,
HRIdx
,
HRBPCrossLikelinessFun
);
// The new agent logs its input values and results in a pair of the sum of
// received warning scores and their cross-reliability.
AgentHandle
BodyAgent
=
App
->
createAgent
(
"Body Agent"
,
std
::
function
<
Optional
<
WarningValue
>
(
std
::
pair
<
WarningValue
,
bool
>
,
std
::
pair
<
WarningValue
,
bool
>
,
std
::
pair
<
WarningValue
,
bool
>
,
std
::
pair
<
WarningValue
,
bool
>
,
std
::
pair
<
WarningValue
,
bool
>
)
>
(
[
&
](
std
::
pair
<
WarningValue
,
bool
>
HR
,
std
::
pair
<
WarningValue
,
bool
>
BR
,
std
::
pair
<
WarningValue
,
bool
>
SpO2
,
std
::
pair
<
WarningValue
,
bool
>
BPSys
,
std
::
pair
<
WarningValue
,
bool
>
BodyTemp
)
->
Optional
<
WarningValue
>
{
LOG_INFO_STREAM
<<
"
\n
*******
\n
Body Agent trigged with values:
\n
"
<<
(
HR
.
second
?
"<New>"
:
"<Old>"
)
<<
" HR result: "
<<
PRINTABLE
(
HR
.
first
)
<<
"
\n
"
<<
(
BR
.
second
?
"<New>"
:
"<Old>"
)
<<
" BR result: "
<<
PRINTABLE
(
BR
.
first
)
<<
"
\n
"
<<
(
SpO2
.
second
?
"<New>"
:
"<Old>"
)
<<
" SpO2 result: "
<<
PRINTABLE
(
SpO2
.
first
)
<<
"
\n
"
<<
(
BPSys
.
second
?
"<New>"
:
"<Old>"
)
<<
" BPSys result: "
<<
PRINTABLE
(
BPSys
.
first
)
<<
"
\n
"
<<
(
BodyTemp
.
second
?
"<New>"
:
"<Old>"
)
<<
" BodyTemp result: "
<<
PRINTABLE
(
BodyTemp
.
first
)
<<
"
\n
******
\n
"
;
using
ValueType
=
std
::
tuple
<
rosa
::
id_t
,
WarningScoreType
,
ReliabilityType
>
;
const
std
::
vector
<
ValueType
>
SlaveValues
{
{
HRIdx
,
std
::
get
<
0
>
(
HR
.
first
),
std
::
get
<
1
>
(
HR
.
first
)},
{
BRIdx
,
std
::
get
<
0
>
(
BR
.
first
),
std
::
get
<
1
>
(
BR
.
first
)},
{
SpO2Idx
,
std
::
get
<
0
>
(
SpO2
.
first
),
std
::
get
<
1
>
(
SpO2
.
first
)},
{
BPSysIdx
,
std
::
get
<
0
>
(
BPSys
.
first
),
std
::
get
<
1
>
(
BPSys
.
first
)},
{
BodyTempIdx
,
std
::
get
<
0
>
(
BodyTemp
.
first
),
std
::
get
<
1
>
(
BodyTemp
.
first
)}};
const
ReliabilityType
crossReliability
=
BodyCrossCombinator
.
getOutputLikeliness
(
SlaveValues
);
struct
ScoreSum
{
void
operator
()(
const
ValueType
&
V
)
{
ews
+=
std
::
get
<
1
>
(
V
);
}
WarningScoreType
ews
{
0
};
};
const
ScoreSum
scoreSum
=
std
::
for_each
(
SlaveValues
.
cbegin
(),
SlaveValues
.
cend
(),
ScoreSum
());
return
{
WarningValue
(
scoreSum
.
ews
,
crossReliability
)};
}));
App
->
setExecutionPolicy
(
BodyAgent
,
AppExecutionPolicy
::
decimation
(
Decimation
));
//
// Connect low-level agents to the high-level agent.
//
LOG_INFO
(
"Connect low-level agents to the high-level agent."
);
App
->
connectAgents
(
BodyAgent
,
HRIdx
,
HRAgent
,
"HR Agent Channel"
);
App
->
connectAgents
(
BodyAgent
,
BRIdx
,
BRAgent
,
"BR Agent Channel"
);
App
->
connectAgents
(
BodyAgent
,
SpO2Idx
,
SpO2Agent
,
"SpO2 Agent Channel"
);
App
->
connectAgents
(
BodyAgent
,
BPSysIdx
,
BPSysAgent
,
"BPSys Agent Channel"
);
App
->
connectAgents
(
BodyAgent
,
BodyTempIdx
,
BodyTempAgent
,
"BodyTemp Agent Channel"
);
//
// For simulation output, create a logger agent writing the output of the
// high-level agent into a CSV file.
//
LOG_INFO
(
"Create a logger agent."
);
// Create CSV writer.
std
::
ofstream
ScoreCSV
(
ScoreCSVPath
);
csv
::
CSVTupleWriter
<
WarningScoreType
,
ReliabilityType
>
ScoreWriter
(
ScoreCSV
,
CSVDelimiter
);
if
(
CSVHeader
)
{
ScoreWriter
.
writeHeader
({
"EWS"
,
"Reliability"
});
}
// The agent writes each new input value into a CSV file and produces nothing.
// \note The execution of the logger is not subject to decimation.
using
logger_result
=
AppTuple
<
unit_t
>
;
AgentHandle
LoggerAgent
=
App
->
createAgent
(
"Logger Agent"
,
std
::
function
<
Optional
<
logger_result
>
(
std
::
pair
<
WarningValue
,
bool
>
)
>
(
[
&
ScoreWriter
](
std
::
pair
<
WarningValue
,
bool
>
Score
)
->
Optional
<
logger_result
>
{
// The state of \p ScoreWriter is not checked, expecting good.
ScoreWriter
<<
Score
.
first
;
return
{};
}));
//
// Connect the high-level agent to the logger agent.
//
LOG_INFO
(
"Connect the high-level agent to the logger agent."
);
App
->
connectAgents
(
LoggerAgent
,
0
,
BodyAgent
,
"Body Agent Channel"
);
//
// Do simulation.
//
LOG_INFO
(
"Setting up and performing simulation."
);
//
// Initialize application for simulation.
//
App
->
initializeSimulation
();
//
// Open CSV files and register them for their corresponding sensors.
//
// Type aliases for iterators.
using
CSVDataIterator
=
CSVIterator
<
HRType
,
BRType
,
SpO2Type
,
BPSysType
,
BodyTempType
>
;
const
auto
CSVHeaderInfo
=
CSVHeader
?
HeaderInformation
::
HasHeader
:
HeaderInformation
::
HasNoHeader
;
std
::
ifstream
DataCSV
(
DataCSVPath
);
auto
[
HRRange
,
BRRange
,
SpO2Range
,
BPSysRange
,
BodyTempRange
]
=
splitTupleIterator
(
CSVDataIterator
(
DataCSV
,
0
,
CSVHeaderInfo
,
CSVDelimiter
),
CSVDataIterator
());
App
->
registerSensorValues
(
HRSensor
,
std
::
move
(
begin
(
HRRange
)),
end
(
HRRange
));
App
->
registerSensorValues
(
BRSensor
,
std
::
move
(
begin
(
BRRange
)),
end
(
BRRange
));
App
->
registerSensorValues
(
SpO2Sensor
,
std
::
move
(
begin
(
SpO2Range
)),
end
(
SpO2Range
));
App
->
registerSensorValues
(
BPSysSensor
,
std
::
move
(
begin
(
BPSysRange
)),
end
(
BPSysRange
));
App
->
registerSensorValues
(
BodyTempSensor
,
std
::
move
(
begin
(
BodyTempRange
)),
end
(
BodyTempRange
));
//
// Simulate.
//
App
->
simulate
(
NumberOfSimulationCycles
);
return
0
;
}
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Sun, Jun 8, 8:11 PM (1 d, 7 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
150246
Default Alt Text
sa-ews1.cpp (23 KB)
Attached To
Mode
R20 SoC_Rosa_repo
Attached
Detach File
Event Timeline
Log In to Comment