Commit 7f693f54 authored by fmg005's avatar fmg005

Added realtime capability v2.0

parent 617b5c11
...@@ -8,34 +8,47 @@ my_serial, CLA::LOGGER* logger):m_serial(my_serial), m_logger(logger) { ...@@ -8,34 +8,47 @@ my_serial, CLA::LOGGER* logger):m_serial(my_serial), m_logger(logger) {
HardwareSimulator::HardwareSimulator(serial::Serial* HardwareSimulator::HardwareSimulator(serial::Serial*
my_serial, CLA::LOGGER* logger, CLA::Environment* env):m_serial(my_serial), m_logger(logger), m_env(env) { my_serial, CLA::LOGGER* logger, CLA::Environment* env):m_serial(my_serial), m_logger(logger), m_env(env) {
nextUpdateTime = 0;
respondToData = &HardwareSimulator::SetInitialIBP;
}
void HardwareSimulator::update(std::unique_ptr<PhysiologyEngine>& engine) {
((this)->*respondToData)(engine);
} }
void HardwareSimulator::SetInitialIBP(std::unique_ptr<PhysiologyEngine>& engine) { void HardwareSimulator::update(std::unique_ptr<PhysiologyEngine>& engine) {
/*
synchronize simulation time to real clock
i.e., 1s of Simulation = 1s of real-time
*/
m_start = system_clock::now();
engine->AdvanceModelTime(advance_time, TimeUnit::s);
m_end = system_clock::now();
m_command_start = system_clock::now();
systolic_pressure = engine->GetCardiovascularSystem()->GetSystolicArterialPressure(PressureUnit::mmHg); systolic_pressure = engine->GetCardiovascularSystem()->GetSystolicArterialPressure(PressureUnit::mmHg);
diastolic_pressure = engine->GetCardiovascularSystem()->GetDiastolicArterialPressure(PressureUnit::mmHg); diastolic_pressure = engine->GetCardiovascularSystem()->GetDiastolicArterialPressure(PressureUnit::mmHg);
double hr = engine->GetCardiovascularSystem()->GetHeartRate(FrequencyUnit::Per_min);
SetIBP(1, systolic_pressure, diastolic_pressure); SetIBP(1, systolic_pressure, diastolic_pressure);
nextUpdateTime = m_env->time_index + DELAY_5_SECONDS; SetHeartRate(hr);
//cout<< engine->GetSimulationTime(TimeUnit::s)<<endl; m_command_end = system_clock::now();
respondToData = &HardwareSimulator::updateIBP;
} /* start time for the next execution */
duration<double> m_next_start(real_time); // seconds
void HardwareSimulator::updateIBP(std::unique_ptr<PhysiologyEngine>& engine) { m_real_time = system_clock::to_time_t(m_start) + m_next_start.count();
if(m_env->time_index == nextUpdateTime) {
systolic_pressure = engine->GetCardiovascularSystem()->GetSystolicArterialPressure(PressureUnit::mmHg); m_advance_duration_ms = duration_cast<milliseconds>(m_end - m_start).count();
diastolic_pressure = engine->GetCardiovascularSystem()->GetDiastolicArterialPressure(PressureUnit::mmHg); m_command_duration_ms = duration_cast<milliseconds>(m_command_end - m_command_start).count();
m_real_time_duration_ms = duration_cast<milliseconds>(m_next_start).count();
SetIBP(1, systolic_pressure, diastolic_pressure);
nextUpdateTime = m_env->time_index + DELAY_5_SECONDS; /* checking if simulation will take longer than allotted 'time' */
//cout<< engine->GetSimulationTime(TimeUnit::s)<<endl; if (m_advance_duration_ms + m_command_duration_ms > m_real_time_duration_ms)
respondToData = &HardwareSimulator::updateIBP; m_logger->error("Simulation too slow");
/* wait until start time of next execution is reached i.e., time:s of real-time */
while(true) {
m_delta = m_real_time - system_clock::to_time_t(system_clock::now());
if (m_delta <= 0)
break;
std::this_thread::sleep_for(milliseconds(m_delta));
} }
/* track data */
engine->GetEngineTracker()->TrackData(engine->GetSimulationTime(TimeUnit::s));
} }
void HardwareSimulator::LoadConfig(const char* file_path) { void HardwareSimulator::LoadConfig(const char* file_path) {
...@@ -48,9 +61,8 @@ void HardwareSimulator::LoadConfig(const char* file_path) { ...@@ -48,9 +61,8 @@ void HardwareSimulator::LoadConfig(const char* file_path) {
catch(const ParseException &pex) { catch(const ParseException &pex) {
m_logger->error("Error parsing configuration file"); m_logger->error("Error parsing configuration file");
} }
advance_time = cfg.lookup("pulse.advance_time");
DELAY_5_SECONDS = cfg.lookup("prosim.delay_5_sec"); real_time = cfg.lookup("prosim.real_time");
DELAY_5_SECONDS = DELAY_5_SECONDS/m_env->engine_timestep; // 5 seconds delay
} }
bool HardwareSimulator::isOpen() { bool HardwareSimulator::isOpen() {
...@@ -59,12 +71,17 @@ bool HardwareSimulator::isOpen() { ...@@ -59,12 +71,17 @@ bool HardwareSimulator::isOpen() {
/* HR range: 10-360 */ /* HR range: 10-360 */
void HardwareSimulator::SetHeartRate(double rate) { void HardwareSimulator::SetHeartRate(double rate) {
if (rate >= 10 && rate <= 360) { int heart_rate = static_cast<int>(rate);
SendCommand("NSRA=0"+std::to_string(rate)); if (rate >= 10 && rate < 100) {
m_logger->info("Heart rate set to "+to_string(rate)+" bpm"); SendCommand("NSRA=0"+to_string(heart_rate));
m_logger->info("Heart rate set to "+to_string(heart_rate)+" bpm");
}
else if (rate > 100 ) {
SendCommand("NSRA="+to_string(heart_rate));
m_logger->info("Heart rate set to "+to_string(heart_rate)+" bpm");
} }
else { else {
m_logger->warning("Heart rate value: "+to_string(rate)+" not within acceptable range 10-360"); m_logger->warning("Heart rate value: "+to_string(heart_rate)+" not within acceptable range 10-360");
} }
} }
...@@ -164,7 +181,7 @@ string HardwareSimulator::GetCurrentMode() { ...@@ -164,7 +181,7 @@ string HardwareSimulator::GetCurrentMode() {
size_t HardwareSimulator::SendCommand(string command) { size_t HardwareSimulator::SendCommand(string command) {
size_t bytes_sent = m_serial->write(command+"\r\n"); size_t bytes_sent = m_serial->write(command+"\r\n");
usleep(100); // sleep for 100ms std::this_thread::sleep_for(milliseconds(100));
return bytes_sent; return bytes_sent;
} }
......
#include "Realtime.h"
using namespace CLA;
Realtime::Realtime(std::unique_ptr<PhysiologyEngine>& engine, CLA::LOGGER*
logger): m_engine(engine), m_logger(logger) {
}
void Realtime::AdvanceModelTime(double time) {
/*
synchronize simulation time to real clock
i.e., 1s of Simulation = 1s of real-time
*/
m_start = clock();
m_engine->AdvanceModelTime(1.0, TimeUnit::s);
m_end = clock();
/* start time for the next execution */
m_next_start = CLOCKS_PER_SEC * time;
m_real_time = m_start + m_next_start;
/* checking if simulation will take longer than allotted 'time' */
if ((m_end - m_start) > m_next_start)
m_logger->error("Simulation too slow");
/* wait until start time of next execution is reached i.e., 1s of real-time */
while(true) {
m_delta = m_real_time - clock();
if (m_delta <= 0)
break;
m_delta_secs = long(((double)m_delta)/CLOCKS_PER_SEC);
std::this_thread::sleep_for(std::chrono::seconds(m_delta_secs));
}
/* track data */
m_engine->GetEngineTracker()->TrackData(m_engine->GetSimulationTime(TimeUnit::s));
}
Realtime::~Realtime() {
}
...@@ -4,13 +4,12 @@ ...@@ -4,13 +4,12 @@
#include <vector> #include <vector>
#include <map> #include <map>
#include <libconfig.h++> #include <libconfig.h++>
#include <time.h> /* clock_t, clock, CLOCKS_PER_SEC */
#include "serial/serial.h" #include "serial/serial.h"
#include "HardwareSimulator.h" #include "HardwareSimulator.h"
#include "CLA_Logger.h" #include "CLA_Logger.h"
#include "SimulationEngine.h" #include "SimulationEngine.h"
#include "Realtime.h" #include "Timer.h"
// Include the various types you will be using in your code // Include the various types you will be using in your code
#include "scenario/SEDataRequestManager.h" #include "scenario/SEDataRequestManager.h"
...@@ -36,13 +35,13 @@ ...@@ -36,13 +35,13 @@
using namespace libconfig; using namespace libconfig;
int main() {
int main(){ CLA::Timer timer;
auto cf = std::make_shared<Config>(); auto cf = std::make_shared<Config>();
string f_path = prosim_config_dir+"scenario.cfg"; string f_path = prosim_config_dir+"scenario.cfg";
const char* filepath = f_path.c_str(); const char* filepath = f_path.c_str();
Simulation("Hassan", cf, filepath); Simulation("Cynthia", cf, filepath);
} }
void Simulation(const string patient_name, const std::shared_ptr<Config>& cfg, const char* filepath ) void Simulation(const string patient_name, const std::shared_ptr<Config>& cfg, const char* filepath )
...@@ -62,7 +61,7 @@ void Simulation(const string patient_name, const std::shared_ptr<Config>& cfg, c ...@@ -62,7 +61,7 @@ void Simulation(const string patient_name, const std::shared_ptr<Config>& cfg, c
pe->GetEngineTracker()->GetDataRequestManager().SetResultsFilename(prosim_results_dir+"PulseSimEngine_"+patient_name+".txt"); pe->GetEngineTracker()->GetDataRequestManager().SetResultsFilename(prosim_results_dir+"PulseSimEngine_"+patient_name+".txt");
SEHemorrhage hemorrhageLeg; SEHemorrhage hemorrhageLeg;
double initialMAP = 76.0; double initialMAP = 70.0;
double currentMAP; double currentMAP;
CLA::Environment sim_env; CLA::Environment sim_env;
Global_LoadConfig(pe, cfg, filepath, &sim_env); Global_LoadConfig(pe, cfg, filepath, &sim_env);
...@@ -85,18 +84,17 @@ void Simulation(const string patient_name, const std::shared_ptr<Config>& cfg, c ...@@ -85,18 +84,17 @@ void Simulation(const string patient_name, const std::shared_ptr<Config>& cfg, c
bool STOP = false; // Execute stop hemmorrhage only once; without this it be executed for each timestep bool STOP = false; // Execute stop hemmorrhage only once; without this it be executed for each timestep
bool DEVICES_START = false; bool DEVICES_START = false;
CLA::Realtime rt(pe, &logger);
prosim.SetRemoteMode(); prosim.SetRemoteMode();
// stop when the set time is reached // stop when the set time is reached
while (sim_env.time_index <= sim_env.simulation_timesteps) { while (sim_env.time_index <= sim_env.simulation_timesteps) {
// event_hemorrage_start // event_hemorrage_start
if(sim_env.time_index == sim_env.simulation_injury_start_timestep) { if(sim_env.time_index == sim_env.simulation_injury_start_timestep) {
cout<< "The time_index "<<sim_env.time_index;
// Hemorrhage Starts - instantiate a hemorrhage action and have the engine process it // Hemorrhage Starts - instantiate a hemorrhage action and have the engine process it
cout<<"\nHemorrhage Started at: "<<pe->GetSimulationTime(TimeUnit::s)<<endl; cout<<"\nHemorrhage Started at: "<<pe->GetSimulationTime(TimeUnit::s)<<endl;
hemorrhageLeg.SetCompartment(pulse::VascularCompartment::RightLeg); hemorrhageLeg.SetCompartment(pulse::VascularCompartment::RightLeg);
//the rate of hemorrhage //the rate of hemorrhage
hemorrhageLeg.GetRate().SetValue(150,VolumePerTimeUnit::mL_Per_min); hemorrhageLeg.GetRate().SetValue(350,VolumePerTimeUnit::mL_Per_min);
pe->ProcessAction(hemorrhageLeg); pe->ProcessAction(hemorrhageLeg);
STOP = true; STOP = true;
} }
...@@ -109,18 +107,9 @@ void Simulation(const string patient_name, const std::shared_ptr<Config>& cfg, c ...@@ -109,18 +107,9 @@ void Simulation(const string patient_name, const std::shared_ptr<Config>& cfg, c
hemorrhageLeg.GetRate().SetValue(0,VolumePerTimeUnit::mL_Per_min); hemorrhageLeg.GetRate().SetValue(0,VolumePerTimeUnit::mL_Per_min);
pe->ProcessAction(hemorrhageLeg); pe->ProcessAction(hemorrhageLeg);
STOP = false; STOP = false;
DEVICES_START = true; // instruct devices to start
cout << "START DEVICES" << endl;
} }
/* We both track data and advance engine inside the update method */
if(DEVICES_START) { prosim.update(pe);
prosim.update(pe);
}
// track patient data
//pe->GetEngineTracker()->TrackData(pe->GetSimulationTime(TimeUnit::s));
//pe->AdvanceModelTime();
rt.AdvanceModelTime(1.0);//Advance Engine at 1s in real time
sim_env.time_index++; sim_env.time_index++;
}// End while looop }// End while looop
}// End Simulation function }// End Simulation function
...@@ -140,9 +129,8 @@ void Global_LoadConfig(std::unique_ptr<PhysiologyEngine>& engine, const std::sha ...@@ -140,9 +129,8 @@ void Global_LoadConfig(std::unique_ptr<PhysiologyEngine>& engine, const std::sha
env->simulation_injury_start = cf->lookup("simulation.time.injury_start"); env->simulation_injury_start = cf->lookup("simulation.time.injury_start");
env->simulation_injury_stop = cf->lookup("simulation.time.injury_stop"); env->simulation_injury_stop = cf->lookup("simulation.time.injury_stop");
env->time_index = 0; // initialize the time index env->time_index = 0; // initialize the time index
//env->engine_timestep = engine->GetTimeStep(TimeUnit::s); env->engine_timestep = cf->lookup("pulse.advance_time");
env->engine_timestep = 1.0; env->simulation_timesteps = env->simulation_time/env->engine_timestep;
env->simulation_timesteps = env->simulation_time / env->engine_timestep;
env->simulation_injury_start_timestep = env->simulation_injury_start/env->engine_timestep; env->simulation_injury_start_timestep = env->simulation_injury_start/env->engine_timestep;
env->simulation_injury_stop_timestep = env->simulation_injury_stop/env->engine_timestep; env->simulation_injury_stop_timestep = env->simulation_injury_stop/env->engine_timestep;
}// End Global_LoadConfig }// End Global_LoadConfig
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#include <iostream> #include <iostream>
#include <cstdio> #include <cstdio>
#include <unistd.h> #include <unistd.h>
#include <chrono>
#include <thread>
#include <libconfig.h++> #include <libconfig.h++>
#include "serial/serial.h" #include "serial/serial.h"
#include "CLA_Logger.h" #include "CLA_Logger.h"
...@@ -14,10 +16,13 @@ ...@@ -14,10 +16,13 @@
#include "PulsePhysiologyEngine.h" #include "PulsePhysiologyEngine.h"
#include "properties/SEScalarTime.h" #include "properties/SEScalarTime.h"
#include "properties/SEScalarPressure.h" #include "properties/SEScalarPressure.h"
#include "properties/SEScalarFrequency.h"
#include "engine/SEEngineTracker.h"
#include "system/physiology/SECardiovascularSystem.h" #include "system/physiology/SECardiovascularSystem.h"
using namespace std; using namespace std;
using namespace libconfig; using namespace libconfig;
using namespace std::chrono;
class HardwareSimulator { class HardwareSimulator {
...@@ -30,10 +35,20 @@ private: ...@@ -30,10 +35,20 @@ private:
string GetResponse(); string GetResponse();
double systolic_pressure; double systolic_pressure;
double diastolic_pressure; double diastolic_pressure;
double nextUpdateTime; double advance_time;
double DELAY_5_SECONDS; double real_time;
Config cfg; // API for accessing configuration files Config cfg; // API for accessing configuration files
string mode; string mode;
/* chrono */
system_clock::time_point m_start;
system_clock::time_point m_end;
system_clock::time_point m_command_start;
system_clock::time_point m_command_end;
time_t m_delta;
time_t m_real_time;
time_t m_advance_duration_ms;
time_t m_command_duration_ms;
time_t m_real_time_duration_ms;
public: public:
HardwareSimulator(serial::Serial*, CLA::LOGGER*, CLA::Environment*); HardwareSimulator(serial::Serial*, CLA::LOGGER*, CLA::Environment*);
...@@ -47,9 +62,6 @@ public: ...@@ -47,9 +62,6 @@ public:
void SetRemoteMode(); void SetRemoteMode();
void SetLocalMode(); void SetLocalMode();
string GetCurrentMode(); string GetCurrentMode();
void updateIBP(std::unique_ptr<PhysiologyEngine>&);
void SetInitialIBP(std::unique_ptr<PhysiologyEngine>&);
void (HardwareSimulator::*respondToData)(std::unique_ptr<PhysiologyEngine>&);
void update(std::unique_ptr<PhysiologyEngine>&); void update(std::unique_ptr<PhysiologyEngine>&);
void LoadConfig(const char*); void LoadConfig(const char*);
}; };
......
#ifndef REALTIME2_H
#define REALTIME2_H
#include <time.h>
#include <string>
#include <chrono>
#include <thread>
#include <libconfig.h++>
#include "CLA_Logger.h"
#include "PulsePhysiologyEngine.h"
#include "engine/SEEngineTracker.h"
#include "scenario/SEDataRequest.h"
#include "properties/SEScalarTime.h"
using namespace libconfig;
using namespace std;
namespace CLA {
class Realtime {
private:
std::unique_ptr<PhysiologyEngine>& m_engine;
CLA::LOGGER* m_logger;
Config m_cfg;
clock_t m_real_time, real_start, m_delta, m_start, m_end;
clock_t m_next_start;
long m_delta_secs;
public:
Realtime(std::unique_ptr<PhysiologyEngine>&, CLA::LOGGER*);
~Realtime();
void AdvanceModelTime(double);
};
}
#endif
...@@ -61,7 +61,7 @@ set( my_srcs ...@@ -61,7 +61,7 @@ set( my_srcs
CLA_Logger.cpp CLA_Logger.cpp
#example.cpp #example.cpp
SimulationEngine.cpp SimulationEngine.cpp
Realtime.cpp Timer.cpp
) )
add_executable(prosim ${my_srcs}) add_executable(prosim ${my_srcs})
......
# Configuration file # Configuration file
pulse = { pulse = {
advance_time = 1.0; # Simulation engine advance time -> seconds advance_time = 1.0; # Simulation engine advance time -> seconds
} }
prosim = { prosim = {
real_time = 5.0; # Real time -> seconds real_time = 1.0; # Real time -> seconds
} }
simulation = { simulation = {
time = { time = {
run = 60.0; # Time -> Seconds How long should simulation run run = 180.0; # Time -> Seconds How long should simulation run
injury_start = 5.0; # When should injury be introduced to patient injury_start = 60.0; # When should injury be introduced to patient
injury_stop = 700.0; # When should injury be stopped injury_stop = 700.0; # When should injury be stopped
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment