home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.hitl.washington.edu
/
ftp.hitl.washington.edu.tar
/
ftp.hitl.washington.edu
/
pub
/
people
/
peter
/
ER
/
BP_trend_driver.cxx
< prev
next >
Wrap
C/C++ Source or Header
|
1998-07-07
|
10KB
|
376 lines
/*
BP_trend_driver.cc
*/
#include "BP_trend_driver.h"
#include <iostream.h>
#include <vector.h>
#include <stdlib.h>
#include <math.h>
#include "v3dSystem.h"
#include "v3dUniverse.h"
//#define TIMESTAMP // Time-stamp data changes.
#ifdef TIMESTAMP
#include "timestamp.h"
#endif
///////////////////////////
// BPTrendDriver //
/////////////////////////
//const double BPTrendDriver::ms_Interval = 25.0; // 25 ms per interval
const double BPTrendDriver::ms_Interval = 40.0; // 40 ms per interval
//static vector <vector <BP_TREND_DATA_TYPE> > test_BP_values;
static vector <BP_TREND_DATA_TYPE> BP_trend_values;
template<class T>
vector<T> to_vec (int num_values, T *data_ary)
{
vector<T> new_vec;
for (int i = 0; i < num_values; ++i)
new_vec.push_back (data_ary[i]);
return new_vec;
}
#include <stdio.h>
void
BPTrendDriver::InitializeBaseFunctionValues(
float domain_low, float domain_high,
float range_low, unsigned int set_size)
{
float low = range_low + M_PI_2,
domain = domain_high - domain_low,
step = domain / (float)set_size,
cur_x = domain_low;
//cerr << "BP trend step size: " << step << endl;
for (int i = 0; i < set_size; ++i) {
//cerr << "Element " << i << ": atan (" << cur_x << ") = " << atanf(cur_x) + low << endl;
BP_trend_values.push_back(atanf(cur_x) + low);
cur_x += step;
}
//cerr << "Finished!" << endl;
data_range_.high_threshold_value
= 0.75 * BP_trend_values[BP_trend_values.size() - 1];
data_range_.low_threshold_value = -1 * data_range_.high_threshold_value;
cerr << "Thresholds: High: " << data_range_.high_threshold_value <<
" Low: " << data_range_.low_threshold_value << endl;
// The range of random offset is 1/10th the range of the
// base function's data.
random_range_ = 0.1 * (data_range_.high_threshold_value -
data_range_.low_threshold_value);
cerr << "Random range: " << random_range_ << endl;;
}
void
BPTrendDriver::SeedTrend(long seed_val)
{
srand48(seed_val);
}
BPTrendDriver::BPTrendDriver()
{
InitializeBaseFunctionValues(-10, 10, 0, 500);
data_list = 0;
SeedTrend(1);
Reset();
// Register the driver with the current universe.
// Later, the universe should be passed as a parameter.
v3dSystem::GetCurrentUniverse()->RegisterEventSender(this);
// Register an event to tell receivers that new data has arrived.
RegisterEvent(new BPTrendDataUpdateEvent);
Unpause();
}
BPTrendDriver::~BPTrendDriver()
{
delete data_list;
}
void
BPTrendDriver::TestEvents()
{
// Update the BP trend driver index.
if (!IsPaused()) {
update_current_index();
// Test the events registered with this sender first.
EventMap::iterator event_iter = events_.begin();
for (; event_iter != events_.end(); ++event_iter)
if ((*event_iter).second->IsActive())
(*event_iter).second->Test();
}
// Next, tell all event senders registered with this object to
// test their events.
EventSenderVector::iterator event_sender_iter = event_senders_.begin();
for (; event_sender_iter != event_senders_.end(); ++event_sender_iter)
(*event_sender_iter)->TestEvents ();
}
// BPTrendDriver::Reset
// Resets the BP trend.
void
BPTrendDriver::Reset()
{
// Create a new set of data.
CreateData ((int)(100 * drand48()), drand48() > .5 ? true : false, 100 + (int)(100 * drand48()));
}
BP_TREND_DATA_RANGE
BPTrendDriver::switch_data (int set_no, int new_set_size)
{
#if 0
if (set_no < 0)
++current_set_;
else
current_set_ = set_no;
// Choose set 0 if the specified set is out of range.
if (current_set_ >= BP_trend_values.size())
current_set_ = 0;
#endif
}
BP_TREND_DATA_RANGE
BPTrendDriver::CreateData(unsigned int zero_set_size, bool trend_up,
unsigned int trend_set_size)
{
// If the new set size is 0, then use the base function's set size.
int set_size = BP_trend_values.size();
if (trend_set_size == 0)
trend_set_size = set_size;
max_index_ = trend_set_size + zero_set_size;
cerr << "BP set size: " << trend_set_size << " Max index: " << max_index_ << endl;
// Allocate a new array to hold the data values.
delete [] data_list;
data_list = new BP_TREND_DATA_TYPE [max_index_];
// Create the pre-trend zero line with random offset.
for (int i = 0; i < zero_set_size; ++i)
data_list[i] = (0.5 - drand48()) * random_range_;
// Copy the function values from the base function value vector,
// and add a random offset.
float step_size = set_size / (1.0 * trend_set_size),
real_index = 0.5;
int cur_index = 0;
threshold_cross_index_ = 0;
cerr << "Step size: " << step_size << endl;
if (trend_up) {
for (int i = zero_set_size; i < max_index_; ++i) {
data_list[i] = BP_trend_values[cur_index];
data_list[i] += (0.5 - drand48()) * random_range_;
if (!threshold_cross_index_ &&
(data_list[i] >= data_range_.high_threshold_value))
threshold_cross_index_ = i;
real_index += step_size;
cur_index = (int)ftrunc(real_index);
}
} else {
for (int i = zero_set_size; i < max_index_; ++i) {
data_list[i] = -BP_trend_values[cur_index];
data_list[i] += (0.5 - drand48()) * random_range_;
if (!threshold_cross_index_ &&
(data_list[i] <= data_range_.low_threshold_value))
threshold_cross_index_ = i;
real_index += step_size;
cur_index = (int)ftrunc(real_index);
}
}
cerr << "Theshold cross index: " << threshold_cross_index_ << endl;;
// Set the index to the start of the data.
reset_current_index();
// Get the ranges of the data.
data_range_.maximum_value = data_list[0];
data_range_.minimum_value = data_list[0];
for (int i = 1; i < max_index_; ++i) {
if (data_list[i] > data_range_.maximum_value)
data_range_.maximum_value = data_list[i];
if (data_list[i] < data_range_.minimum_value)
data_range_.minimum_value = data_list[i];
}
return data_range_;
}
void
BPTrendDriver::CreatePostThresholdData (bool high_threshold)
{
BP_TREND_DATA_TYPE base_number;
if (high_threshold)
base_number = BP_trend_values[BP_trend_values.size() - 1];
else
base_number = -BP_trend_values[BP_trend_values.size() - 1];
// Create the post-trend zero-slope line with random offset.
for (int i = 0; i < max_index_; ++i)
data_list[i] = base_number + (0.5 - drand48()) * random_range_;
}
void
BPTrendDriver::BP_update_callback(const v3dEventMessage *message)
{
((BPTrendDriver *)message->GetEventReceiver())->update_current_index();
}
// usec_diff
// Calculate the difference in microseconds between the two times
// passed in.
inline float
usec_diff (const timeval& current_time, const timeval& past_time)
{
return (current_time.tv_sec - past_time.tv_sec) * 1000000 +
current_time.tv_usec - past_time.tv_usec;
}
// BPTrendDriver::update_current_index
// Changes the current index to the BP data depending on how much
// time has elapsed since the last update.
// Each value in the array represents a piece of BP data read at
// 40ms intervals.
int
BPTrendDriver::update_current_index ()
{
#ifdef TIMESTAMP
static TrackedEvent low_threshold_crossed_event(TrackedEvent::SystemEvent,
24, "Blood pressure low threshold crossed");
static TrackedEvent high_threshold_crossed_event(TrackedEvent::SystemEvent,
23, "Blood pressure high threshold crossed");
#endif // TIMESTAMP
if (IsPaused()) return current_index_;
timeval current_time;
//cerr << "clock / sec: " << CLOCKS_PER_SEC;
gettimeofday (¤t_time);
//cerr << " elapsed clock: " << current_time.tv_usec - last_time_.tv_usec;
//cerr << " elapsed int: " << ((current_time.tv_sec - last_time_.tv_sec) *
// 1000000 + current_time.tv_usec - last_time_.tv_usec)
// / (1000 * ms_Interval);
//cerr << endl;
// true_index_ += ((current_time.tv_sec - last_time_.tv_sec) * 1000000 +
// current_time.tv_usec - last_time_.tv_usec) /
// (1000 * ms_Interval);
true_index_ += usec_diff (current_time, last_time_) /
(1000 * ms_Interval);
if (true_index_ >= max_index_) {
CreatePostThresholdData(data_list[max_index_ - 1] > data_range_.high_threshold_value);
while (true_index_ >= max_index_)
true_index_ -= max_index_;
}
current_index_ = (int) ffloor (true_index_);
if (threshold_cross_index_ && (threshold_cross_index_ < current_index_))
{
cerr << "Threshold crossed." << endl;
#ifdef TIMESTAMP
// Timestamp the threshold crossing event.
if (data_list[current_index_] >= data_range_.high_threshold_value)
TimestampedEvent::AddEvent(&high_threshold_crossed_event);
else
TimestampedEvent::AddEvent(&low_threshold_crossed_event);
#endif // TIMESTAMP
threshold_cross_index_ = 0;
}
last_time_ = current_time;
//cerr << " true index: " << true_index_;
//cerr << " current index: " << current_index_ << endl;
return current_index_;
}
int
BPTrendDriver::reset_current_index ()
{
// last_time_ = clock();
gettimeofday(&last_time_);
true_index_ = 0;
return current_index_ = 0;
}
bool
BPTrendDriver::CorrectDown()
{
#ifdef TIMESTAMP
static TrackedEvent bp_corrected_down_event (TrackedEvent::SystemEvent, 25,
"High blood pressure corrected");
#endif // TIMESTAMP
if (threshold_cross_index_) { // Threshold not crossed yet.
// ADD: timestamp false correction.
return false;
} else if (data_list[current_index_] < data_range_.high_threshold_value) {
// ADD: timestamp correcting in wrong direction.
return false;
}
#ifdef TIMESTAMP
// Timestamp the correction in the system
TimestampedEvent::AddEvent(&bp_corrected_down_event);
#endif // TIMESTAMP
// Reset the BP trend.
Reset();
return true;
}
bool
BPTrendDriver::CorrectUp()
{
#ifdef TIMESTAMP
static TrackedEvent bp_corrected_up_event (TrackedEvent::SystemEvent, 25,
"Low blood pressure corrected");
#endif // TIMESTAMP
if (threshold_cross_index_) { // Threshold not crossed yet.
// ADD: timestamp false correction.
return false;
} else if (data_list[current_index_] > data_range_.low_threshold_value) {
// ADD: timestamp correcting in wrong direction.
return false;
}
#ifdef TIMESTAMP
// Timestamp the correction in the system
TimestampedEvent::AddEvent(&bp_corrected_up_event);
#endif // TIMESTAMP
// Reset the BP trend.
Reset();
return true;
}
/////////////////////////////////////////////////////////////////////////////
// Events
void BPTrendDataUpdateEvent::Test()
{
InvokeHandlers(0);
}