Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F1493531
sa-ews2.cpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Size
35 KB
Referenced Files
None
Subscribers
None
sa-ews2.cpp
View Options
//===-- apps/sa-ews2/sa-ews2.cpp --------------------------------*- C++ -*-===//
//
// The RoSA Framework -- Application SA-EWS2
//
// 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-ews2/sa-ews2.cpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
/// Maximilian Goetzinger (maxgot@utu.fi)
///
/// \date 2020
///
/// \brief The application SA-EWS2 implements the case study from the paper:
/// M. Götzinger, A. Anzanpour, I. Azimi, N. TaheriNejad, A. Jantsch,
/// A. M. Rahmani, and P. Liljeberg: Confidence-Enhanced Early Warning Score
/// Based on Fuzzy Logic. DOI: 10.1007/s11036-019-01324-5
//===----------------------------------------------------------------------===//
#include
"rosa/agent/RangeConfidence.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-EWS2"
;
/// Representation type of warning levels.
/// \note Make sure it suits all defined enumeration values.
using
WarningScoreType
=
uint8_t
;
/// Warning levels for abstraction.
///
/// \note Conversion functions \c feedbackFromSymbol(), \c feedbackToSymbol(),
/// and the master input handler generated by \c createLowLevelAgent() expect
/// enumeration values to constitute a consecutive range of non-negative
/// integers starting from \c 0.
enum
WarningScore
:
WarningScoreType
{
No
=
0
,
Low
=
1
,
High
=
2
,
Emergency
=
3
};
/// Vector with all possible warning levels.
std
::
vector
<
WarningScoreType
>
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
>
;
/// The helper struct used by the Likeliness Combinator to provide feedback.
using
EWSSymbol
=
Symbol
<
WarningScoreType
,
ReliabilityType
>
;
/// All feedback calculated by Likelienss Combinator for one slave.
using
EWSFeedback
=
std
::
vector
<
EWSSymbol
>
;
/// The feedback provided by master to a slave agent.
/// The tuple contains the reliability feedback for each warning level in order.
using
FeedbackTuple
=
AppTuple
<
ReliabilityType
,
ReliabilityType
,
ReliabilityType
,
ReliabilityType
>
;
/// Converts feedback calculated by Likeliness Combinator into a tuple that can
/// be sent between agents.
///
/// \param F calculated standard feedback
///
/// \return feedback tuple
FeedbackTuple
feedbackFromSymbol
(
const
EWSFeedback
&
F
)
{
// Fill a map with feedback for warning levels.
std
::
map
<
WarningScoreType
,
ReliabilityType
>
M
;
std
::
for_each
(
F
.
cbegin
(),
F
.
cend
(),
[
&
M
](
const
EWSSymbol
&
S
)
{
M
.
insert
({
S
.
Identifier
,
S
.
Likeliness
});
});
// Expect feedback for all warning levels.
ASSERT
(
M
.
size
()
==
warningScores
.
size
());
return
{
M
[
No
],
M
[
Low
],
M
[
High
],
M
[
Emergency
]};
}
/// Converts feedback tuple to standard format used by the Likeliness Combinator.
///
/// \param F feedback tuple
///
/// \return feedback in standard format
EWSFeedback
feedbackToSymbol
(
const
FeedbackTuple
&
F
)
{
return
{{
No
,
std
::
get
<
No
>
(
F
)},
{
Low
,
std
::
get
<
Low
>
(
F
)},
{
High
,
std
::
get
<
High
>
(
F
)},
{
Emergency
,
std
::
get
<
Emergency
>
(
F
)}};
}
/// 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.
///
/// The agent also accepts feedback from its master, which is taken into account
/// for the pre-processing of later sensory 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 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
,
ReliabilityAndConfidenceCombination
<
T
,
WarningScoreType
,
ReliabilityType
>
&
R
)
{
using
masterhandler
=
std
::
function
<
void
(
std
::
pair
<
FeedbackTuple
,
bool
>
)
>
;
using
result
=
Optional
<
WarningValue
>
;
using
input
=
AppTuple
<
T
>
;
using
handler
=
std
::
function
<
result
(
std
::
pair
<
input
,
bool
>
)
>
;
AgentHandle
Agent
=
App
->
createAgent
(
Name
,
masterhandler
([
&
,
Name
](
std
::
pair
<
FeedbackTuple
,
bool
>
I
)
{
LOG_INFO_STREAM
<<
"
\n
******
\n
"
<<
Name
<<
" "
<<
(
I
.
second
?
"<New>"
:
"<Old>"
)
<<
" master feedback: ["
<<
PRINTABLE
(
std
::
get
<
No
>
(
I
.
first
))
<<
", "
<<
PRINTABLE
(
std
::
get
<
Low
>
(
I
.
first
))
<<
", "
<<
PRINTABLE
(
std
::
get
<
High
>
(
I
.
first
))
<<
", "
<<
PRINTABLE
(
std
::
get
<
Emergency
>
(
I
.
first
))
<<
"]
\n
******
\n
"
;
const
auto
Feedback
=
feedbackToSymbol
(
I
.
first
);
R
.
feedback
(
Feedback
);
}),
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
auto
AbstractedValue
=
R
.
bestSymbol
(
SensorValue
);
return
{
WarningValue
(
AbstractedValue
.
Identifier
,
AbstractedValue
.
Likeliness
)};
}));
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
=
128
;
// 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
=
float
;
using
HRConfidence
=
RangeConfidence
<
HRType
,
WarningScoreType
,
ReliabilityType
>
;
using
HRParFun
=
PartialFunction
<
HRType
,
ReliabilityType
>
;
using
HRLinFun
=
LinearFunction
<
HRType
,
ReliabilityType
>
;
using
BRType
=
float
;
using
BRConfidence
=
RangeConfidence
<
BRType
,
WarningScoreType
,
ReliabilityType
>
;
using
BRParFun
=
PartialFunction
<
BRType
,
ReliabilityType
>
;
using
BRLinFun
=
LinearFunction
<
BRType
,
ReliabilityType
>
;
using
SpO2Type
=
int32_t
;
using
SpO2Confidence
=
RangeConfidence
<
SpO2Type
,
WarningScoreType
,
ReliabilityType
>
;
using
SpO2ParFun
=
PartialFunction
<
SpO2Type
,
ReliabilityType
>
;
using
SpO2LinFun
=
LinearFunction
<
SpO2Type
,
ReliabilityType
>
;
using
BPSysType
=
float
;
using
BPSysConfidence
=
RangeConfidence
<
BPSysType
,
WarningScoreType
,
ReliabilityType
>
;
using
BPSysParFun
=
PartialFunction
<
BPSysType
,
ReliabilityType
>
;
using
BPSysLinFun
=
LinearFunction
<
BPSysType
,
ReliabilityType
>
;
using
BodyTempType
=
float
;
using
BodyTempConfidence
=
RangeConfidence
<
BodyTempType
,
WarningScoreType
,
ReliabilityType
>
;
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 reliabilities and confindences.
//
const
size_t
TimeStep
=
1
;
const
size_t
HistoryLength
=
32
;
using
TimeParFun
=
PartialFunction
<
size_t
,
ReliabilityType
>
;
using
TimeLinFun
=
LinearFunction
<
size_t
,
ReliabilityType
>
;
std
::
shared_ptr
<
Abstraction
<
size_t
,
ReliabilityType
>>
TimeConfidence
(
new
TimeParFun
({{{
std
::
numeric_limits
<
size_t
>::
lowest
(),
0
},
std
::
make_shared
<
TimeLinFun
>
(
1
,
0
)},
{{
0
,
HistoryLength
},
std
::
make_shared
<
TimeLinFun
>
(
0
,
1
,
HistoryLength
,
0
)}},
0
));
ReliabilityAndConfidenceCombination
<
HRType
,
WarningScoreType
,
ReliabilityType
>
HRReliability
;
HRReliability
.
setIdentifiers
(
warningScores
);
HRReliability
.
setHistoryLength
(
HistoryLength
);
HRReliability
.
setTimeStep
(
TimeStep
);
HRReliability
.
setTimeFunctionForLikelinessFunction
(
TimeConfidence
);
std
::
shared_ptr
<
HRConfidence
>
HRConf
(
new
HRConfidence
(
{{
No
,
HRParFun
({{{
56.5f
,
62.5f
},
std
::
make_shared
<
HRLinFun
>
(
56.5f
,
0
,
62.5f
,
1
)},
{{
62.5f
,
97.5f
},
std
::
make_shared
<
HRLinFun
>
(
1
,
0
)},
{{
97.5f
,
103.5f
},
std
::
make_shared
<
HRLinFun
>
(
97.5f
,
1
,
103.5f
,
0
)}},
0
)},
{
Low
,
HRParFun
(
{{{
47.5f
,
53.5f
},
std
::
make_shared
<
HRLinFun
>
(
47.5f
,
0
,
53.5f
,
1
)},
{{
53.5f
,
56.5f
},
std
::
make_shared
<
HRLinFun
>
(
1
,
0
)},
{{
56.5f
,
62.5f
},
std
::
make_shared
<
HRLinFun
>
(
56.5f
,
1
,
62.5f
,
0
)},
{{
97.5f
,
103.5f
},
std
::
make_shared
<
HRLinFun
>
(
97.5f
,
0
,
103.5f
,
1
)},
{{
103.5f
,
107.5f
},
std
::
make_shared
<
HRLinFun
>
(
1
,
0
)},
{{
107.5f
,
113.5f
},
std
::
make_shared
<
HRLinFun
>
(
107.5f
,
1
,
113.5f
,
0
)}},
0
)},
{
High
,
HRParFun
(
{{{
36.5f
,
42.5f
},
std
::
make_shared
<
HRLinFun
>
(
36.5f
,
0
,
42.5f
,
1
)},
{{
42.5f
,
47.5f
},
std
::
make_shared
<
HRLinFun
>
(
1
,
0
)},
{{
47.5f
,
53.5f
},
std
::
make_shared
<
HRLinFun
>
(
47.5f
,
1
,
53.5f
,
0
)},
{{
107.5f
,
113.5f
},
std
::
make_shared
<
HRLinFun
>
(
107.5f
,
0
,
113.5f
,
1
)},
{{
113.5f
,
126.5f
},
std
::
make_shared
<
HRLinFun
>
(
1
,
0
)},
{{
126.5f
,
132.5f
},
std
::
make_shared
<
HRLinFun
>
(
126.5f
,
1
,
132.5f
,
0
)}},
0
)},
{
Emergency
,
HRParFun
(
{{{
36.5f
,
42.5f
},
std
::
make_shared
<
HRLinFun
>
(
36.5f
,
1
,
42.5f
,
0
)},
{{
42.5f
,
126.5f
},
std
::
make_shared
<
HRLinFun
>
(
0
,
0
)},
{{
126.5f
,
132.5f
},
std
::
make_shared
<
HRLinFun
>
(
126.5f
,
0
,
132.5f
,
1
)}},
1
)}}));
HRReliability
.
setConfidenceFunction
(
HRConf
);
std
::
shared_ptr
<
Abstraction
<
HRType
,
ReliabilityType
>>
HRAbsRel
(
new
HRParFun
({{{
0.f
,
200.f
},
std
::
make_shared
<
HRLinFun
>
(
1
,
0
)},
{{
200.f
,
300.f
},
std
::
make_shared
<
HRLinFun
>
(
200.f
,
1
,
300.f
,
0
)}},
0
));
HRReliability
.
setAbsoluteReliabilityFunction
(
HRAbsRel
);
std
::
shared_ptr
<
Abstraction
<
HRType
,
ReliabilityType
>>
HRRelSlope
(
new
HRParFun
(
{{{
-200.f
,
-100.f
},
std
::
make_shared
<
HRLinFun
>
(
-200.f
,
0
,
-100.f
,
1
)},
{{
-100.f
,
100.f
},
std
::
make_shared
<
HRLinFun
>
(
1
,
0
)},
{{
100.f
,
200.f
},
std
::
make_shared
<
HRLinFun
>
(
100.f
,
1
,
200.f
,
0
)}},
0
));
HRReliability
.
setReliabilitySlopeFunction
(
HRRelSlope
);
ReliabilityAndConfidenceCombination
<
BRType
,
WarningScoreType
,
ReliabilityType
>
BRReliability
;
BRReliability
.
setIdentifiers
(
warningScores
);
BRReliability
.
setHistoryLength
(
HistoryLength
);
BRReliability
.
setTimeStep
(
TimeStep
);
BRReliability
.
setTimeFunctionForLikelinessFunction
(
TimeConfidence
);
std
::
shared_ptr
<
BRConfidence
>
BRConf
(
new
BRConfidence
(
{{
No
,
BRParFun
(
{{{
7.5f
,
9.5f
},
std
::
make_shared
<
BRLinFun
>
(
7.5f
,
0
,
9.5f
,
1
)},
{{
9.5f
,
13.5f
},
std
::
make_shared
<
BRLinFun
>
(
1
,
0
)},
{{
13.5f
,
15.5f
},
std
::
make_shared
<
BRLinFun
>
(
12.5f
,
1
,
15.5f
,
0
)}},
0
)},
{
Low
,
BRParFun
(
{{{
13.5f
,
15.5f
},
std
::
make_shared
<
BRLinFun
>
(
13.5f
,
0
,
15.5f
,
1
)},
{{
15.5f
,
19.5f
},
std
::
make_shared
<
BRLinFun
>
(
1
,
0
)},
{{
19.5f
,
21.5f
},
std
::
make_shared
<
BRLinFun
>
(
19.5f
,
1
,
21.5f
,
0
)}},
0
)},
{
High
,
BRParFun
(
{{{
std
::
numeric_limits
<
BRType
>::
lowest
(),
7.5f
},
std
::
make_shared
<
BRLinFun
>
(
1
,
0
)},
{{
7.5f
,
9.5f
},
std
::
make_shared
<
BRLinFun
>
(
7.5f
,
1
,
9.5f
,
0
)},
{{
19.5f
,
21.5f
},
std
::
make_shared
<
BRLinFun
>
(
19.5f
,
0
,
21.5f
,
1
)},
{{
21.5f
,
28.5f
},
std
::
make_shared
<
BRLinFun
>
(
1
,
0
)},
{{
28.5f
,
30.5f
},
std
::
make_shared
<
BRLinFun
>
(
28.5f
,
1
,
30.5f
,
0
)}},
0
)},
{
Emergency
,
BRParFun
({{{
std
::
numeric_limits
<
BRType
>::
lowest
(),
28.5f
},
std
::
make_shared
<
BRLinFun
>
(
0
,
0
)},
{{
28.5f
,
30.5f
},
std
::
make_shared
<
BRLinFun
>
(
28.5f
,
0
,
30.5f
,
1
)}},
1
)}}));
BRReliability
.
setConfidenceFunction
(
BRConf
);
std
::
shared_ptr
<
Abstraction
<
BRType
,
ReliabilityType
>>
BRAbsRel
(
new
BRParFun
({{{
0.f
,
40.f
},
std
::
make_shared
<
BRLinFun
>
(
1
,
0
)},
{{
40.f
,
60.f
},
std
::
make_shared
<
BRLinFun
>
(
40.f
,
1
,
60.f
,
0
)}},
0
));
BRReliability
.
setAbsoluteReliabilityFunction
(
BRAbsRel
);
std
::
shared_ptr
<
Abstraction
<
BRType
,
ReliabilityType
>>
BRRelSlope
(
new
BRParFun
({{{
-30.f
,
-20.f
},
std
::
make_shared
<
BRLinFun
>
(
-30.f
,
0
,
-20.f
,
1
)},
{{
-20.f
,
20.f
},
std
::
make_shared
<
BRLinFun
>
(
1
,
0
)},
{{
20.f
,
30.f
},
std
::
make_shared
<
BRLinFun
>
(
20.f
,
1
,
30.f
,
0
)}},
0
));
BRReliability
.
setReliabilitySlopeFunction
(
BRRelSlope
);
ReliabilityAndConfidenceCombination
<
SpO2Type
,
WarningScoreType
,
ReliabilityType
>
SpO2Reliability
;
SpO2Reliability
.
setIdentifiers
(
warningScores
);
SpO2Reliability
.
setHistoryLength
(
HistoryLength
);
SpO2Reliability
.
setTimeStep
(
TimeStep
);
SpO2Reliability
.
setTimeFunctionForLikelinessFunction
(
TimeConfidence
);
std
::
shared_ptr
<
SpO2Confidence
>
SpO2Conf
(
new
SpO2Confidence
(
{{
No
,
SpO2ParFun
({{{
93
,
96
},
std
::
make_shared
<
SpO2LinFun
>
(
93
,
0
,
96
,
1
)},
{{
96
,
std
::
numeric_limits
<
SpO2Type
>::
max
()},
std
::
make_shared
<
SpO2LinFun
>
(
1
,
0
)}},
0
)},
{
Low
,
SpO2ParFun
({{{
88
,
91
},
std
::
make_shared
<
SpO2LinFun
>
(
88
,
0
,
91
,
1
)},
{{
91
,
93
},
std
::
make_shared
<
SpO2LinFun
>
(
1
,
0
)},
{{
93
,
96
},
std
::
make_shared
<
SpO2LinFun
>
(
93
,
1
,
96
,
0
)}},
0
)},
{
High
,
SpO2ParFun
({{{
83
,
86
},
std
::
make_shared
<
SpO2LinFun
>
(
83
,
0
,
86
,
1
)},
{{
86
,
88
},
std
::
make_shared
<
SpO2LinFun
>
(
1
,
0
)},
{{
88
,
91
},
std
::
make_shared
<
SpO2LinFun
>
(
88
,
1
,
91
,
0
)}},
0
)},
{
Emergency
,
SpO2ParFun
({{{
83
,
86
},
std
::
make_shared
<
SpO2LinFun
>
(
83
,
1
,
86
,
0
)},
{{
86
,
std
::
numeric_limits
<
SpO2Type
>::
max
()},
std
::
make_shared
<
SpO2LinFun
>
(
0
,
0
)}},
1
)}}));
SpO2Reliability
.
setConfidenceFunction
(
SpO2Conf
);
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
,
WarningScoreType
,
ReliabilityType
>
BPSysReliability
;
BPSysReliability
.
setIdentifiers
(
warningScores
);
BPSysReliability
.
setHistoryLength
(
HistoryLength
);
BPSysReliability
.
setTimeStep
(
TimeStep
);
BPSysReliability
.
setTimeFunctionForLikelinessFunction
(
TimeConfidence
);
std
::
shared_ptr
<
BPSysConfidence
>
BPSysConf
(
new
BPSysConfidence
(
{{
No
,
BPSysParFun
({{{
97.5f
,
103.5f
},
std
::
make_shared
<
BPSysLinFun
>
(
97.5f
,
0
,
103.5f
,
1
)},
{{
103.5f
,
146.5f
},
std
::
make_shared
<
BPSysLinFun
>
(
1
,
0
)},
{{
146.5f
,
152.5f
},
std
::
make_shared
<
BPSysLinFun
>
(
146.5f
,
1
,
152.5f
,
0
)}},
0
)},
{
Low
,
BPSysParFun
({{{
77.5f
,
83.5f
},
std
::
make_shared
<
BPSysLinFun
>
(
77.5f
,
0
,
83.5f
,
1
)},
{{
83.5f
,
97.5f
},
std
::
make_shared
<
BPSysLinFun
>
(
1
,
0
)},
{{
97.5f
,
103.5f
},
std
::
make_shared
<
BPSysLinFun
>
(
97.5f
,
1
,
103.5f
,
0
)},
{{
146.5f
,
152.5f
},
std
::
make_shared
<
BPSysLinFun
>
(
146.5f
,
0
,
152.5f
,
1
)},
{{
152.5f
,
166.5f
},
std
::
make_shared
<
BPSysLinFun
>
(
1
,
0
)},
{{
166.5f
,
172.5f
},
std
::
make_shared
<
BPSysLinFun
>
(
166.5f
,
1
,
172.5f
,
0
)}},
0
)},
{
High
,
BPSysParFun
({{{
66.5f
,
72.5f
},
std
::
make_shared
<
BPSysLinFun
>
(
66.5f
,
0
,
72.5f
,
1
)},
{{
72.5f
,
77.5f
},
std
::
make_shared
<
BPSysLinFun
>
(
1
,
0
)},
{{
77.5f
,
83.5f
},
std
::
make_shared
<
BPSysLinFun
>
(
77.5f
,
1
,
83.5f
,
0
)},
{{
166.5f
,
172.5f
},
std
::
make_shared
<
BPSysLinFun
>
(
166.5f
,
0
,
172.5f
,
1
)},
{{
172.5f
,
176.5f
},
std
::
make_shared
<
BPSysLinFun
>
(
1
,
0
)},
{{
176.5f
,
182.5f
},
std
::
make_shared
<
BPSysLinFun
>
(
176.5f
,
1
,
182.5f
,
0
)}},
0
)},
{
Emergency
,
BPSysParFun
({{{
66.5f
,
72.5f
},
std
::
make_shared
<
BPSysLinFun
>
(
66.5f
,
1
,
72.5f
,
0
)},
{{
72.5f
,
176.5f
},
std
::
make_shared
<
BPSysLinFun
>
(
0
,
0
)},
{{
176.5f
,
182.5f
},
std
::
make_shared
<
BPSysLinFun
>
(
176.5f
,
0
,
182.5f
,
1
)}},
1
)}}));
BPSysReliability
.
setConfidenceFunction
(
BPSysConf
);
std
::
shared_ptr
<
Abstraction
<
BPSysType
,
ReliabilityType
>>
BPSysAbsRel
(
new
BPSysParFun
(
{{{
0.f
,
260.f
},
std
::
make_shared
<
BPSysLinFun
>
(
1
,
0
)},
{{
260.f
,
400.f
},
std
::
make_shared
<
BPSysLinFun
>
(
260.f
,
1
,
400.f
,
0
)}},
0
));
BPSysReliability
.
setAbsoluteReliabilityFunction
(
BPSysAbsRel
);
std
::
shared_ptr
<
Abstraction
<
BPSysType
,
ReliabilityType
>>
BPSysRelSlope
(
new
BPSysParFun
(
{{{
-100.f
,
-50.f
},
std
::
make_shared
<
BPSysLinFun
>
(
-100.f
,
0
,
-50.f
,
1
)},
{{
-50.f
,
50.f
},
std
::
make_shared
<
BPSysLinFun
>
(
1
,
0
)},
{{
50.f
,
100.f
},
std
::
make_shared
<
BPSysLinFun
>
(
50.f
,
1
,
100.f
,
0
)}},
0
));
BPSysReliability
.
setReliabilitySlopeFunction
(
BPSysRelSlope
);
ReliabilityAndConfidenceCombination
<
BodyTempType
,
WarningScoreType
,
ReliabilityType
>
BodyTempReliability
;
BodyTempReliability
.
setIdentifiers
(
warningScores
);
BodyTempReliability
.
setHistoryLength
(
HistoryLength
);
BodyTempReliability
.
setTimeStep
(
TimeStep
);
BodyTempReliability
.
setTimeFunctionForLikelinessFunction
(
TimeConfidence
);
std
::
shared_ptr
<
BodyTempConfidence
>
BodyTempConf
(
new
BodyTempConfidence
(
{{
No
,
BodyTempParFun
(
{{{
34.55f
,
35.55f
},
std
::
make_shared
<
BodyTempLinFun
>
(
34.55f
,
0
,
35.55f
,
1
)},
{{
35.55f
,
37.55f
},
std
::
make_shared
<
BodyTempLinFun
>
(
1
,
0
)},
{{
37.55f
,
38.55f
},
std
::
make_shared
<
BodyTempLinFun
>
(
37.55f
,
1
,
38.55f
,
0
)}},
0
)},
{
Low
,
BodyTempParFun
({},
0
)},
{
High
,
BodyTempParFun
(
{{{
std
::
numeric_limits
<
BodyTempType
>::
lowest
(),
34.55f
},
std
::
make_shared
<
BodyTempLinFun
>
(
1
,
0
)},
{{
34.55f
,
35.55f
},
std
::
make_shared
<
BodyTempLinFun
>
(
34.55f
,
1
,
35.55f
,
0
)},
{{
37.55f
,
38.55f
},
std
::
make_shared
<
BodyTempLinFun
>
(
37.55f
,
0
,
38.55f
,
1
)},
{{
38.55f
,
39.05f
},
std
::
make_shared
<
BodyTempLinFun
>
(
1
,
0
)},
{{
39.05f
,
40.05f
},
std
::
make_shared
<
BodyTempLinFun
>
(
39.05f
,
1
,
40.05f
,
0
)}},
0
)},
{
Emergency
,
BodyTempParFun
(
{{{
std
::
numeric_limits
<
BodyTempType
>::
lowest
(),
39.05f
},
std
::
make_shared
<
BodyTempLinFun
>
(
0
,
0
)},
{{
39.05f
,
40.05f
},
std
::
make_shared
<
BodyTempLinFun
>
(
39.05f
,
0
,
40.05f
,
1
)}},
1
)}}));
BodyTempReliability
.
setConfidenceFunction
(
BodyTempConf
);
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
,
HRReliability
);
AgentHandle
BRAgent
=
createLowLevelAgent
(
App
,
"BR Agent"
,
Decimation
,
BRReliability
);
AgentHandle
SpO2Agent
=
createLowLevelAgent
(
App
,
"SpO2 Agent"
,
Decimation
,
SpO2Reliability
);
AgentHandle
BPSysAgent
=
createLowLevelAgent
(
App
,
"BPSys Agent"
,
Decimation
,
BPSysReliability
);
AgentHandle
BodyTempAgent
=
createLowLevelAgent
(
App
,
"BodyTemp Agent"
,
Decimation
,
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
};
const
ReliabilityType
CrossLikelinessParameter
=
1.5
;
CrossCombinator
<
WarningScoreType
,
ReliabilityType
>
BodyCrossCombinator
;
BodyCrossCombinator
.
setCrossLikelinessParameter
(
CrossLikelinessParameter
);
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, results in a pair of the sum of
// received warning scores and their cross-reliability as well as calculated
// cross-likeliness feedback for each of its slaves.
using
BodyAgentInput
=
std
::
pair
<
WarningValue
,
bool
>
;
using
BodyAgentOutput
=
Optional
<
WarningValue
>
;
using
BodyAgentFeedback
=
Optional
<
FeedbackTuple
>
;
using
BodyAgentResult
=
std
::
tuple
<
BodyAgentOutput
,
BodyAgentFeedback
,
BodyAgentFeedback
,
BodyAgentFeedback
,
BodyAgentFeedback
,
BodyAgentFeedback
>
;
using
BodyAgentHandler
=
std
::
function
<
BodyAgentResult
(
BodyAgentInput
,
BodyAgentInput
,
BodyAgentInput
,
BodyAgentInput
,
BodyAgentInput
)
>
;
AgentHandle
BodyAgent
=
App
->
createAgent
(
"Body Agent"
,
BodyAgentHandler
([
&
](
BodyAgentInput
HR
,
BodyAgentInput
BR
,
BodyAgentInput
SpO2
,
BodyAgentInput
BPSys
,
BodyAgentInput
BodyTemp
)
->
BodyAgentResult
{
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
auto
[
crossReliability
,
feedbackValues
]
=
BodyCrossCombinator
(
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
)},
{
feedbackFromSymbol
(
feedbackValues
.
at
(
HRIdx
))},
{
feedbackFromSymbol
(
feedbackValues
.
at
(
BRIdx
))},
{
feedbackFromSymbol
(
feedbackValues
.
at
(
SpO2Idx
))},
{
feedbackFromSymbol
(
feedbackValues
.
at
(
BPSysIdx
))},
{
feedbackFromSymbol
(
feedbackValues
.
at
(
BodyTempIdx
))}};
}));
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, Mar 1, 5:19 PM (7 h, 58 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
287428
Default Alt Text
sa-ews2.cpp (35 KB)
Attached To
Mode
R20 SoC_Rosa_repo
Attached
Detach File
Event Timeline
Log In to Comment