mirror of
https://gitlab.com/pholy/OSCAR-code.git
synced 2025-04-08 04:00:44 +00:00
Oximetry summary work, Prescription changes best and worst highlighting, Summary percentile calculations and load all nastiness test
This commit is contained in:
parent
e4132512f5
commit
fe73e0ae5f
@ -53,11 +53,13 @@ void gLineOverlayBar::paint(gGraph & w, int left, int topp, int width, int heigh
|
|||||||
QHash<ChannelID,QVector<EventList *> >::iterator cei;
|
QHash<ChannelID,QVector<EventList *> >::iterator cei;
|
||||||
|
|
||||||
m_count=0;
|
m_count=0;
|
||||||
|
m_sum=0;
|
||||||
m_flag_color=schema::channel[m_code].defaultColor();
|
m_flag_color=schema::channel[m_code].defaultColor();
|
||||||
|
|
||||||
if (m_flt==FT_Span) {
|
if (m_flt==FT_Span) {
|
||||||
m_flag_color.setAlpha(128);
|
m_flag_color.setAlpha(128);
|
||||||
}
|
}
|
||||||
|
EventStoreType raw;
|
||||||
for (QVector<Session *>::iterator s=m_day->begin();s!=m_day->end(); s++) {
|
for (QVector<Session *>::iterator s=m_day->begin();s!=m_day->end(); s++) {
|
||||||
cei=(*s)->eventlist.find(m_code);
|
cei=(*s)->eventlist.find(m_code);
|
||||||
if (cei==(*s)->eventlist.end()) continue;
|
if (cei==(*s)->eventlist.end()) continue;
|
||||||
@ -67,8 +69,9 @@ void gLineOverlayBar::paint(gGraph & w, int left, int topp, int width, int heigh
|
|||||||
|
|
||||||
for (quint32 i=0;i<el.count();i++) {
|
for (quint32 i=0;i<el.count();i++) {
|
||||||
X=el.time(i);
|
X=el.time(i);
|
||||||
|
raw=el.data(i);
|
||||||
if (m_flt==FT_Span) {
|
if (m_flt==FT_Span) {
|
||||||
Y=X-(qint64(el.raw(i))*1000.0L); // duration
|
Y=X-(qint64(raw)*1000.0L); // duration
|
||||||
|
|
||||||
if (X < w.min_x) continue;
|
if (X < w.min_x) continue;
|
||||||
if (Y > w.max_x) break;
|
if (Y > w.max_x) break;
|
||||||
@ -80,6 +83,7 @@ void gLineOverlayBar::paint(gGraph & w, int left, int topp, int width, int heigh
|
|||||||
//x1=w.x2p(X);
|
//x1=w.x2p(X);
|
||||||
x1=double(width)/double(xx)*double(X-w.min_x)+left;
|
x1=double(width)/double(xx)*double(X-w.min_x)+left;
|
||||||
m_count++;
|
m_count++;
|
||||||
|
m_sum+=raw;
|
||||||
if (m_flt==FT_Span) {
|
if (m_flt==FT_Span) {
|
||||||
//x2=w.x2p(Y);
|
//x2=w.x2p(Y);
|
||||||
x2=double(width)/double(xx)*double(Y-w.min_x)+left;
|
x2=double(width)/double(xx)*double(Y-w.min_x)+left;
|
||||||
@ -149,8 +153,12 @@ void gLineOverlaySummary::paint(gGraph & w,int left, int top, int width, int hei
|
|||||||
Q_UNUSED(width);
|
Q_UNUSED(width);
|
||||||
Q_UNUSED(height);
|
Q_UNUSED(height);
|
||||||
float cnt=0;
|
float cnt=0;
|
||||||
|
double sum=0;
|
||||||
|
bool isSpan=false;
|
||||||
for (int i=0;i<m_overlays.size();i++) {
|
for (int i=0;i<m_overlays.size();i++) {
|
||||||
cnt+=m_overlays[i]->count();
|
cnt+=m_overlays[i]->count();
|
||||||
|
sum+=m_overlays[i]->sum();
|
||||||
|
if (m_overlays[i]->flagtype()==FT_Span) isSpan=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
double val,first,last;
|
double val,first,last;
|
||||||
@ -187,5 +195,14 @@ void gLineOverlaySummary::paint(gGraph & w,int left, int top, int width, int hei
|
|||||||
|
|
||||||
|
|
||||||
QString a="Event Count="+QString::number(cnt)+" Selection Time="+QString().sprintf("%02i:%02i:%02i",h,m,s)+" "+m_text+"="+QString::number(val,'f',2);
|
QString a="Event Count="+QString::number(cnt)+" Selection Time="+QString().sprintf("%02i:%02i:%02i",h,m,s)+" "+m_text+"="+QString::number(val,'f',2);
|
||||||
|
|
||||||
|
if (isSpan) {
|
||||||
|
float sph;
|
||||||
|
if (!time) sph=0; else {
|
||||||
|
sph=(100.0/float(time))*(sum/3600.0);
|
||||||
|
if (sph>100) sph=100;
|
||||||
|
}
|
||||||
|
a+=QString(" (\%%1 in events)").arg(sph,0,'f',2);
|
||||||
|
}
|
||||||
w.renderText(a,left+m_x,top+m_y);
|
w.renderText(a,left+m_x,top+m_y);
|
||||||
}
|
}
|
||||||
|
@ -31,11 +31,14 @@ class gLineOverlayBar:public Layer
|
|||||||
|
|
||||||
//! \brief returns a count of all flags drawn during render. (for gLineOverlaySummary)
|
//! \brief returns a count of all flags drawn during render. (for gLineOverlaySummary)
|
||||||
int count() { return m_count; }
|
int count() { return m_count; }
|
||||||
|
double sum() { return m_sum; }
|
||||||
|
FlagType flagtype() { return m_flt; }
|
||||||
protected:
|
protected:
|
||||||
QColor m_flag_color;
|
QColor m_flag_color;
|
||||||
QString m_label;
|
QString m_label;
|
||||||
FlagType m_flt;
|
FlagType m_flt;
|
||||||
int m_count;
|
int m_count;
|
||||||
|
double m_sum;
|
||||||
|
|
||||||
GLShortBuffer *points,*quads, *lines;
|
GLShortBuffer *points,*quads, *lines;
|
||||||
};
|
};
|
||||||
|
@ -596,20 +596,28 @@ int calcSPO2Drop(Session *session)
|
|||||||
int cnt=0;
|
int cnt=0;
|
||||||
tmp=0;
|
tmp=0;
|
||||||
|
|
||||||
// Calculate baseline from first 15 minutes of data, hopefully meaning they are still awake..
|
|
||||||
qint64 start=0;
|
qint64 start=0;
|
||||||
|
|
||||||
|
// Calculate median baseline
|
||||||
|
QList<EventDataType> med;
|
||||||
for (int e=0;e<it.value().size();e++) {
|
for (int e=0;e<it.value().size();e++) {
|
||||||
EventList & el=*(it.value()[e]);
|
EventList & el=*(it.value()[e]);
|
||||||
for (unsigned i=0;i<el.count();i++) {
|
for (unsigned i=0;i<el.count();i++) {
|
||||||
val=el.data(i);
|
val=el.data(i);
|
||||||
time=el.time(i);
|
time=el.time(i);
|
||||||
|
if (val>0) med.push_back(val);
|
||||||
if (!start) start=time;
|
if (!start) start=time;
|
||||||
if (time > start+900000) break;// 15 minutes
|
if (time > start+3600000) break; // just look at the first hour
|
||||||
tmp+=val;
|
tmp+=val;
|
||||||
cnt++;
|
cnt++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EventDataType baseline=round(tmp/EventDataType(cnt));
|
qSort(med);
|
||||||
|
int midx=float(med.size())*0.90;
|
||||||
|
if (midx>med.size()-1) midx=med.size()-1;
|
||||||
|
EventDataType baseline=med[midx];
|
||||||
|
session->settings[OXI_SPO2Drop]=baseline;
|
||||||
|
//EventDataType baseline=round(tmp/EventDataType(cnt));
|
||||||
EventDataType current;
|
EventDataType current;
|
||||||
qDebug() << "Calculated baseline" << baseline;
|
qDebug() << "Calculated baseline" << baseline;
|
||||||
|
|
||||||
|
@ -489,6 +489,18 @@ bool Day::settingExists(ChannelID id)
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
bool Day::eventsLoaded()
|
||||||
|
{
|
||||||
|
bool r=false;
|
||||||
|
for (int i=0;i<sessions.size();i++) {
|
||||||
|
if (sessions[i]->eventsLoaded()) {
|
||||||
|
r=true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
bool Day::channelExists(ChannelID id)
|
bool Day::channelExists(ChannelID id)
|
||||||
{
|
{
|
||||||
bool r=false;
|
bool r=false;
|
||||||
@ -522,5 +534,12 @@ void Day::OpenEvents()
|
|||||||
for (s=sessions.begin();s!=sessions.end();s++) {
|
for (s=sessions.begin();s!=sessions.end();s++) {
|
||||||
(*s)->OpenEvents();
|
(*s)->OpenEvents();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
void Day::CloseEvents()
|
||||||
|
{
|
||||||
|
QVector<Session *>::iterator s;
|
||||||
|
|
||||||
|
for (s=sessions.begin();s!=sessions.end();s++) {
|
||||||
|
(*s)->TrashEvents();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -136,12 +136,18 @@ public:
|
|||||||
//! \brief Loads all Events files for this Days Sessions
|
//! \brief Loads all Events files for this Days Sessions
|
||||||
void OpenEvents();
|
void OpenEvents();
|
||||||
|
|
||||||
|
//! \brief Closes all Events files for this Days Sessions
|
||||||
|
void CloseEvents();
|
||||||
|
|
||||||
//! \brief Returns this days sessions list
|
//! \brief Returns this days sessions list
|
||||||
QVector<Session *> & getSessions() { return sessions; }
|
QVector<Session *> & getSessions() { return sessions; }
|
||||||
|
|
||||||
//! \brief Returns true if this Day contains loaded Event Data for this channel.
|
//! \brief Returns true if this Day contains loaded Event Data for this channel.
|
||||||
bool channelExists(ChannelID id);
|
bool channelExists(ChannelID id);
|
||||||
|
|
||||||
|
//! \brief Returns true if session events are loaded
|
||||||
|
bool eventsLoaded();
|
||||||
|
|
||||||
//! \brief Returns true if this Day contains loaded Event Data or a cached count for this channel
|
//! \brief Returns true if this Day contains loaded Event Data or a cached count for this channel
|
||||||
bool channelHasData(ChannelID id);
|
bool channelHasData(ChannelID id);
|
||||||
|
|
||||||
|
@ -263,6 +263,7 @@ bool Machine::Load()
|
|||||||
|
|
||||||
if (sess->LoadSummary(s.value()[0])) {
|
if (sess->LoadSummary(s.value()[0])) {
|
||||||
sess->SetEventFile(s.value()[1]);
|
sess->SetEventFile(s.value()[1]);
|
||||||
|
sess->OpenEvents();
|
||||||
AddSession(sess,profile);
|
AddSession(sess,profile);
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "Error unpacking summary data";
|
qWarning() << "Error unpacking summary data";
|
||||||
|
@ -380,7 +380,8 @@ QList<Machine *> Profile::GetMachines(MachineType t)
|
|||||||
qWarning() << "Profile::GetMachines() i->second == NULL";
|
qWarning() << "Profile::GetMachines() i->second == NULL";
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (i.value()->GetType()==t) {
|
MachineType mt=i.value()->GetType();
|
||||||
|
if ((t==MT_UNKNOWN) || (mt==t)) {
|
||||||
vec.push_back(i.value());
|
vec.push_back(i.value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -472,7 +473,9 @@ Profile *Create(QString name)
|
|||||||
|
|
||||||
Machine *m=new Machine(prof,0);
|
Machine *m=new Machine(prof,0);
|
||||||
m->SetClass("Journal");
|
m->SetClass("Journal");
|
||||||
m->properties[STR_PROP_Brand]="Virtual";
|
m->properties[STR_PROP_Brand]="Journal";
|
||||||
|
m->properties[STR_PROP_Model]="Journal Data Machine Object";
|
||||||
|
m->properties[STR_PROP_Serial]=m->hexid();
|
||||||
m->properties[STR_PROP_Path]="{DataFolder}/"+m->GetClass()+"_"+m->hexid();
|
m->properties[STR_PROP_Path]="{DataFolder}/"+m->GetClass()+"_"+m->hexid();
|
||||||
m->SetType(MT_JOURNAL);
|
m->SetType(MT_JOURNAL);
|
||||||
prof->AddMachine(m);
|
prof->AddMachine(m);
|
||||||
@ -616,6 +619,23 @@ const char * US_STR_RebuildCache="RebuildCache";
|
|||||||
const char * US_STR_ShowDebug="ShowDebug";
|
const char * US_STR_ShowDebug="ShowDebug";
|
||||||
const char * US_STR_LinkGroups="LinkGroups";
|
const char * US_STR_LinkGroups="LinkGroups";
|
||||||
|
|
||||||
|
int Profile::countDays(MachineType mt, QDate start, QDate end)
|
||||||
|
{
|
||||||
|
if (!start.isValid()) start=LastDay(mt);
|
||||||
|
if (!end.isValid()) end=LastDay(mt);
|
||||||
|
QDate date=start;
|
||||||
|
int days=0;
|
||||||
|
do {
|
||||||
|
Day * day=GetDay(date,mt);
|
||||||
|
if (day) {
|
||||||
|
if ((mt==MT_UNKNOWN) || (day->machine->GetType()==mt)) days++;
|
||||||
|
}
|
||||||
|
date=date.addDays(1);
|
||||||
|
} while (date<end);
|
||||||
|
return days;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
EventDataType Profile::calcCount(ChannelID code, MachineType mt, QDate start, QDate end)
|
EventDataType Profile::calcCount(ChannelID code, MachineType mt, QDate start, QDate end)
|
||||||
{
|
{
|
||||||
if (!start.isValid()) start=LastDay(mt);
|
if (!start.isValid()) start=LastDay(mt);
|
||||||
@ -706,6 +726,78 @@ EventDataType Profile::calcWavg(ChannelID code, MachineType mt, QDate start, QDa
|
|||||||
val=val/hours;
|
val=val/hours;
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
EventDataType Profile::calcMin(ChannelID code, MachineType mt, QDate start, QDate end)
|
||||||
|
{
|
||||||
|
if (!start.isValid()) start=LastDay(mt);
|
||||||
|
if (!end.isValid()) end=LastDay(mt);
|
||||||
|
QDate date=start;
|
||||||
|
|
||||||
|
double min=99999999,tmp;
|
||||||
|
do {
|
||||||
|
Day * day=GetDay(date,mt);
|
||||||
|
if (day) {
|
||||||
|
tmp=day->Min(code);
|
||||||
|
if (min>tmp) min=tmp;
|
||||||
|
}
|
||||||
|
date=date.addDays(1);
|
||||||
|
} while (date<end);
|
||||||
|
if (min>=99999999) min=0;
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
EventDataType Profile::calcMax(ChannelID code, MachineType mt, QDate start, QDate end)
|
||||||
|
{
|
||||||
|
if (!start.isValid()) start=LastDay(mt);
|
||||||
|
if (!end.isValid()) end=LastDay(mt);
|
||||||
|
QDate date=start;
|
||||||
|
|
||||||
|
double max=-99999999,tmp;
|
||||||
|
do {
|
||||||
|
Day * day=GetDay(date,mt);
|
||||||
|
if (day) {
|
||||||
|
tmp=day->Max(code);
|
||||||
|
if (max<tmp) max=tmp;
|
||||||
|
}
|
||||||
|
date=date.addDays(1);
|
||||||
|
} while (date<end);
|
||||||
|
if (max<=-99999999) max=0;
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
EventDataType Profile::calcSettingsMin(ChannelID code, MachineType mt, QDate start, QDate end)
|
||||||
|
{
|
||||||
|
if (!start.isValid()) start=LastDay(mt);
|
||||||
|
if (!end.isValid()) end=LastDay(mt);
|
||||||
|
QDate date=start;
|
||||||
|
|
||||||
|
double min=99999999,tmp;
|
||||||
|
do {
|
||||||
|
Day * day=GetDay(date,mt);
|
||||||
|
if (day) {
|
||||||
|
tmp=day->settings_min(code);
|
||||||
|
if (min>tmp) min=tmp;
|
||||||
|
}
|
||||||
|
date=date.addDays(1);
|
||||||
|
} while (date<end);
|
||||||
|
if (min>=99999999) min=0;
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
EventDataType Profile::calcSettingsMax(ChannelID code, MachineType mt, QDate start, QDate end)
|
||||||
|
{
|
||||||
|
if (!start.isValid()) start=LastDay(mt);
|
||||||
|
if (!end.isValid()) end=LastDay(mt);
|
||||||
|
QDate date=start;
|
||||||
|
|
||||||
|
double max=-99999999,tmp;
|
||||||
|
do {
|
||||||
|
Day * day=GetDay(date,mt);
|
||||||
|
if (day) {
|
||||||
|
tmp=day->settings_max(code);
|
||||||
|
if (max<tmp) max=tmp;
|
||||||
|
}
|
||||||
|
date=date.addDays(1);
|
||||||
|
} while (date<end);
|
||||||
|
if (max<=-99999999) max=0;
|
||||||
|
return max;
|
||||||
|
}
|
||||||
EventDataType Profile::calcPercentile(ChannelID code, EventDataType percent, MachineType mt, QDate start, QDate end)
|
EventDataType Profile::calcPercentile(ChannelID code, EventDataType percent, MachineType mt, QDate start, QDate end)
|
||||||
{
|
{
|
||||||
if (!start.isValid()) start=LastDay(mt);
|
if (!start.isValid()) start=LastDay(mt);
|
||||||
@ -713,11 +805,38 @@ EventDataType Profile::calcPercentile(ChannelID code, EventDataType percent, Mac
|
|||||||
|
|
||||||
QDate date=start;
|
QDate date=start;
|
||||||
|
|
||||||
|
// This is one messy function.. It requires all data to be loaded.. :(
|
||||||
|
|
||||||
|
QVector<EventDataType> array;
|
||||||
//double val=0,tmp,hours=0;
|
//double val=0,tmp,hours=0;
|
||||||
do {
|
do {
|
||||||
|
Day * day=GetDay(date,mt);
|
||||||
|
if (day) {
|
||||||
|
bool open=day->eventsLoaded();
|
||||||
|
if (!open)
|
||||||
|
day->OpenEvents();
|
||||||
|
for (int i=0;i<day->size();i++) {
|
||||||
|
for (QVector<Session *>::iterator s=day->begin();s!=day->end();s++) {
|
||||||
|
QHash<ChannelID,QVector<EventList *> >::iterator el=(*s)->eventlist.find(code);
|
||||||
|
if (el==(*s)->eventlist.end()) continue;
|
||||||
|
for (int j=0;j<el.value().size();j++) {
|
||||||
|
EventList & e=*el.value()[j];
|
||||||
|
for (unsigned k=0;k<e.count();k++) {
|
||||||
|
array.push_back(e.data(k));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//if (!open)
|
||||||
|
//day->CloseEvents();
|
||||||
|
}
|
||||||
date=date.addDays(1);
|
date=date.addDays(1);
|
||||||
} while (date<end);
|
} while (date<end);
|
||||||
return 0;
|
qSort(array);
|
||||||
|
int idx=array.size()*percent;
|
||||||
|
if (idx>array.size()-1) idx=array.size()-1;
|
||||||
|
return array[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
QDate Profile::FirstDay(MachineType mt)
|
QDate Profile::FirstDay(MachineType mt)
|
||||||
|
@ -85,7 +85,7 @@ public:
|
|||||||
Day * GetDay(QDate date,MachineType type=MT_UNKNOWN);
|
Day * GetDay(QDate date,MachineType type=MT_UNKNOWN);
|
||||||
|
|
||||||
//! \brief Returns a list of all machines of type t
|
//! \brief Returns a list of all machines of type t
|
||||||
QList<Machine *> GetMachines(MachineType t);
|
QList<Machine *> GetMachines(MachineType t=MT_UNKNOWN);
|
||||||
|
|
||||||
//! \brief Returns the machine of type t used on date, NULL if none..
|
//! \brief Returns the machine of type t used on date, NULL if none..
|
||||||
Machine * GetMachine(MachineType t,QDate date);
|
Machine * GetMachine(MachineType t,QDate date);
|
||||||
@ -96,13 +96,19 @@ public:
|
|||||||
//! \brief Returns true if this profile stores this variable identified by key
|
//! \brief Returns true if this profile stores this variable identified by key
|
||||||
bool contains(QString key) { return p_preferences.contains(key); }
|
bool contains(QString key) { return p_preferences.contains(key); }
|
||||||
|
|
||||||
|
int countDays(MachineType mt=MT_UNKNOWN, QDate start=QDate(), QDate end=QDate());
|
||||||
EventDataType calcCount(ChannelID code, MachineType mt=MT_CPAP, QDate start=QDate(), QDate end=QDate());
|
EventDataType calcCount(ChannelID code, MachineType mt=MT_CPAP, QDate start=QDate(), QDate end=QDate());
|
||||||
double calcSum(ChannelID code, MachineType mt=MT_CPAP, QDate start=QDate(), QDate end=QDate());
|
double calcSum(ChannelID code, MachineType mt=MT_CPAP, QDate start=QDate(), QDate end=QDate());
|
||||||
EventDataType calcHours(MachineType mt=MT_CPAP, QDate start=QDate(), QDate end=QDate());
|
EventDataType calcHours(MachineType mt=MT_CPAP, QDate start=QDate(), QDate end=QDate());
|
||||||
EventDataType calcAvg(ChannelID code, MachineType mt=MT_CPAP, QDate start=QDate(), QDate end=QDate());
|
EventDataType calcAvg(ChannelID code, MachineType mt=MT_CPAP, QDate start=QDate(), QDate end=QDate());
|
||||||
EventDataType calcWavg(ChannelID code, MachineType mt=MT_CPAP, QDate start=QDate(), QDate end=QDate());
|
EventDataType calcWavg(ChannelID code, MachineType mt=MT_CPAP, QDate start=QDate(), QDate end=QDate());
|
||||||
|
EventDataType calcMin(ChannelID code, MachineType mt=MT_CPAP, QDate start=QDate(), QDate end=QDate());
|
||||||
|
EventDataType calcMax(ChannelID code, MachineType mt=MT_CPAP, QDate start=QDate(), QDate end=QDate());
|
||||||
EventDataType calcPercentile(ChannelID code, EventDataType percent, MachineType mt=MT_CPAP, QDate start=QDate(), QDate end=QDate());
|
EventDataType calcPercentile(ChannelID code, EventDataType percent, MachineType mt=MT_CPAP, QDate start=QDate(), QDate end=QDate());
|
||||||
|
|
||||||
|
EventDataType calcSettingsMin(ChannelID code, MachineType mt=MT_CPAP, QDate start=QDate(), QDate end=QDate());
|
||||||
|
EventDataType calcSettingsMax(ChannelID code, MachineType mt=MT_CPAP, QDate start=QDate(), QDate end=QDate());
|
||||||
|
|
||||||
virtual void ExtraLoad(QDomElement & root);
|
virtual void ExtraLoad(QDomElement & root);
|
||||||
virtual QDomElement ExtraSave(QDomDocument & doc);
|
virtual QDomElement ExtraSave(QDomDocument & doc);
|
||||||
|
|
||||||
|
@ -204,6 +204,8 @@ public:
|
|||||||
bool IsLoneSession() { return s_lonesession; }
|
bool IsLoneSession() { return s_lonesession; }
|
||||||
void SetLoneSession(bool b) { s_lonesession=b; }
|
void SetLoneSession(bool b) { s_lonesession=b; }
|
||||||
|
|
||||||
|
bool eventsLoaded() { return s_events_loaded; }
|
||||||
|
|
||||||
//! \brief Sets the event file linked to the summary (during load, for ondemand loading)
|
//! \brief Sets the event file linked to the summary (during load, for ondemand loading)
|
||||||
void SetEventFile(QString & filename) { s_eventfile=filename; }
|
void SetEventFile(QString & filename) { s_eventfile=filename; }
|
||||||
|
|
||||||
|
70
daily.cpp
70
daily.cpp
@ -237,8 +237,12 @@ Daily::Daily(QWidget *parent,gGraphView * shared)
|
|||||||
//INTPULSE->AddLayer(AddCPAP(new gLineChart(OXI_Pulse,Qt::red,square)));
|
//INTPULSE->AddLayer(AddCPAP(new gLineChart(OXI_Pulse,Qt::red,square)));
|
||||||
//INTSPO2->AddLayer(AddCPAP(new gLineChart(OXI_SPO2,Qt::blue,square)));
|
//INTSPO2->AddLayer(AddCPAP(new gLineChart(OXI_SPO2,Qt::blue,square)));
|
||||||
|
|
||||||
PULSE->AddLayer(AddOXI(new gLineOverlayBar(OXI_PulseChange,QColor("light gray"),tr("PD"),FT_Span)));
|
gLineOverlaySummary *los1=new gLineOverlaySummary(tr("Events/hour"),5,-4);
|
||||||
SPO2->AddLayer(AddOXI(new gLineOverlayBar(OXI_SPO2Drop,QColor("light blue"),tr("O2"),FT_Span)));
|
gLineOverlaySummary *los2=new gLineOverlaySummary(tr("Events/hour"),5,-4);
|
||||||
|
PULSE->AddLayer(AddOXI(los1->add(new gLineOverlayBar(OXI_PulseChange,QColor("light gray"),tr("PD"),FT_Span))));
|
||||||
|
PULSE->AddLayer(AddOXI(los1));
|
||||||
|
SPO2->AddLayer(AddOXI(los2->add(new gLineOverlayBar(OXI_SPO2Drop,QColor("light blue"),tr("O2"),FT_Span))));
|
||||||
|
SPO2->AddLayer(AddOXI(los2));
|
||||||
|
|
||||||
PULSE->AddLayer(AddOXI(new gLineChart(OXI_Pulse,Qt::red,square)));
|
PULSE->AddLayer(AddOXI(new gLineChart(OXI_Pulse,Qt::red,square)));
|
||||||
SPO2->AddLayer(AddOXI(new gLineChart(OXI_SPO2,Qt::blue,true)));
|
SPO2->AddLayer(AddOXI(new gLineChart(OXI_SPO2,Qt::blue,true)));
|
||||||
@ -656,10 +660,15 @@ void Daily::Load(QDate date)
|
|||||||
CPAPMode mode=MODE_UNKNOWN;
|
CPAPMode mode=MODE_UNKNOWN;
|
||||||
QString a;
|
QString a;
|
||||||
bool isBrick=false;
|
bool isBrick=false;
|
||||||
if (graphsAvailable==0) {
|
|
||||||
|
if (graphsAvailable>0) {
|
||||||
|
GraphView->setCubeImage(images["sheep"]);
|
||||||
|
GraphView->setEmptyText(tr("Graphs Switched Off"));
|
||||||
|
} else {
|
||||||
|
GraphView->setCubeImage(images["nodata"]);
|
||||||
GraphView->setEmptyText(tr("No Data"));
|
GraphView->setEmptyText(tr("No Data"));
|
||||||
}
|
}
|
||||||
GraphView->setCubeImage(images["nodata"]);
|
|
||||||
if (cpap) {
|
if (cpap) {
|
||||||
if (GraphView->isEmpty()) {
|
if (GraphView->isEmpty()) {
|
||||||
GraphView->setCubeImage(images["brick"]);
|
GraphView->setCubeImage(images["brick"]);
|
||||||
@ -667,9 +676,7 @@ void Daily::Load(QDate date)
|
|||||||
|
|
||||||
isBrick=true;
|
isBrick=true;
|
||||||
} else {
|
} else {
|
||||||
if (graphsAvailable>0) {
|
|
||||||
GraphView->setEmptyText(tr("Graphs Switched Off"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mode=(CPAPMode)(int)cpap->settings_max(CPAP_Mode);
|
mode=(CPAPMode)(int)cpap->settings_max(CPAP_Mode);
|
||||||
@ -783,7 +790,26 @@ void Daily::Load(QDate date)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
html+="</table>";
|
|
||||||
|
} else { // machine is a brick
|
||||||
|
html+="<tr><td colspan='5' align='center'><b><h2>"+tr("BRICK :(")+"</h2></b></td></tr>";
|
||||||
|
html+="<tr><td colspan='5' align='center'><i>"+tr("Sorry, your machine does not record data.")+"</i></td></tr>\n";
|
||||||
|
html+="<tr><td colspan='5' align='center'><i>"+tr("Complain to your Equipment Provider!")+"</i></td></tr>\n";
|
||||||
|
html+="<tr><td colspan='5'> </td></tr>\n";
|
||||||
|
}
|
||||||
|
html+="</table>";
|
||||||
|
|
||||||
|
} // if (!CPAP)
|
||||||
|
if (!cpap && oxi) {
|
||||||
|
html+="<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n";
|
||||||
|
html+="<tr><td colspan=4 align=center><b>"+oxi->machine->properties[STR_PROP_Brand]+"</b> <br>"+oxi->machine->properties[STR_PROP_Model]+"</td></tr>\n";
|
||||||
|
html+="<tr><td colspan=4 align=center> </td></tr>";
|
||||||
|
html+=QString("<tr><td colspan=4 align=center>SpO2 Baseline Used: %1\%</td></tr>").arg(oxi->settings_wavg(OXI_SPO2Drop));
|
||||||
|
html+=QString("<tr><td colspan=4 align=center>SpO2 Desaturations: %1 (%2)\%</td></tr>").arg(oxi->count(OXI_SPO2Drop)).arg((100.0/oxi->hours()) * (oxi->sum(OXI_SPO2Drop)/3600.0));
|
||||||
|
html+=QString("<tr><td colspan=4 align=center>Pulse Change events: %1 (%2)\%</td></tr>").arg(oxi->count(OXI_PulseChange)).arg((100.0/oxi->hours()) * (oxi->sum(OXI_PulseChange)/3600.0));
|
||||||
|
html+="</table>";
|
||||||
|
}
|
||||||
|
if ((cpap && !isBrick) || oxi) {
|
||||||
html+="<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n";
|
html+="<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n";
|
||||||
if (cpap || oxi) {
|
if (cpap || oxi) {
|
||||||
html+="<tr height='2'><td colspan=5 height='2'><hr></td></tr>\n";
|
html+="<tr height='2'><td colspan=5 height='2'><hr></td></tr>\n";
|
||||||
@ -824,12 +850,7 @@ void Daily::Load(QDate date)
|
|||||||
html+="</td><tr>";
|
html+="</td><tr>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
|
||||||
html+="<tr><td colspan='5' align='center'><b><h2>"+tr("BRICK :(")+"</h2></b></td></tr>";
|
|
||||||
html+="<tr><td colspan='5' align='center'><i>"+tr("Sorry, your machine does not record data.")+"</i></td></tr>\n";
|
|
||||||
html+="<tr><td colspan='5' align='center'><i>"+tr("Complain to your Equipment Provider!")+"</i></td></tr>\n";
|
|
||||||
html+="<tr><td colspan='5'> </td></tr>\n";
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
html+="<tr><td colspan=5 align=center><i>"+tr("No data available")+"</i></td></tr>";
|
html+="<tr><td colspan=5 align=center><i>"+tr("No data available")+"</i></td></tr>";
|
||||||
@ -892,15 +913,22 @@ void Daily::Load(QDate date)
|
|||||||
|
|
||||||
}
|
}
|
||||||
html+="</table><hr height=2>";
|
html+="</table><hr height=2>";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
//}
|
//}
|
||||||
html+="<table cellpadding=0 cellspacing=0 border=0 width=100%>";
|
html+="<table cellpadding=0 cellspacing=0 border=0 width=100%>";
|
||||||
QDateTime fd,ld;
|
QDateTime fd,ld;
|
||||||
bool corrupted_waveform=false;
|
bool corrupted_waveform=false;
|
||||||
QString tooltip;
|
QString tooltip;
|
||||||
|
if (cpap || oxi)
|
||||||
|
html+=QString("<tr><td align=left><b>%1</b></td><td align=center><b>%2</b></td><td align=center><b>%3</b></td><td align=center><b>%4</b></td></tr>")
|
||||||
|
.arg(tr("SessionID"))
|
||||||
|
.arg(tr("Date"))
|
||||||
|
.arg(tr("Start"))
|
||||||
|
.arg(tr("End"));
|
||||||
if (cpap) {
|
if (cpap) {
|
||||||
html+="<tr><td align=left><b>"+tr("SessionID")+"</b></td><td align=center><b>"+tr("Date")+"</b></td><td align=center><b>"+tr("Start")+"</b></td><td align=center><b>"+tr("End")+"</b></td></tr>";
|
html+=QString("<tr><td align=left colspan=4><i>%1</i></td></tr>").arg(tr("CPAP Sessions"));
|
||||||
html+="<tr><td align=left colspan=4><i>"+tr("CPAP Sessions")+"</i></td></tr>";
|
|
||||||
for (QVector<Session *>::iterator s=cpap->begin();s!=cpap->end();s++) {
|
for (QVector<Session *>::iterator s=cpap->begin();s!=cpap->end();s++) {
|
||||||
fd=QDateTime::fromTime_t((*s)->first()/1000L);
|
fd=QDateTime::fromTime_t((*s)->first()/1000L);
|
||||||
ld=QDateTime::fromTime_t((*s)->last()/1000L);
|
ld=QDateTime::fromTime_t((*s)->last()/1000L);
|
||||||
@ -919,7 +947,7 @@ void Daily::Load(QDate date)
|
|||||||
//if (oxi) html+="<tr><td colspan=4><hr></td></tr>";
|
//if (oxi) html+="<tr><td colspan=4><hr></td></tr>";
|
||||||
}
|
}
|
||||||
if (oxi) {
|
if (oxi) {
|
||||||
html+="<tr><td align=left colspan=4><i>"+tr("Oximetry Sessions")+"</i></td></tr>";
|
html+=QString("<tr><td align=left colspan=4><i>%1</i></td></tr>").arg(tr("Oximetry Sessions"));
|
||||||
for (QVector<Session *>::iterator s=oxi->begin();s!=oxi->end();s++) {
|
for (QVector<Session *>::iterator s=oxi->begin();s!=oxi->end();s++) {
|
||||||
fd=QDateTime::fromTime_t((*s)->first()/1000L);
|
fd=QDateTime::fromTime_t((*s)->first()/1000L);
|
||||||
ld=QDateTime::fromTime_t((*s)->last()/1000L);
|
ld=QDateTime::fromTime_t((*s)->last()/1000L);
|
||||||
@ -1039,12 +1067,10 @@ void Daily::Load(QDate date)
|
|||||||
ui->bookmarkTable->setItem(i,1,tw);
|
ui->bookmarkTable->setItem(i,1,tw);
|
||||||
tw->setData(Qt::UserRole,st);
|
tw->setData(Qt::UserRole,st);
|
||||||
tw->setData(Qt::UserRole+1,et);
|
tw->setData(Qt::UserRole+1,et);
|
||||||
}
|
} // for (int i
|
||||||
ui->bookmarkTable->blockSignals(false);
|
ui->bookmarkTable->blockSignals(false);
|
||||||
|
} // if (journal->settings.contains(Bookmark_Start))
|
||||||
}
|
} // if (journal)
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Daily::UnitsChanged()
|
void Daily::UnitsChanged()
|
||||||
|
534
mainwindow.cpp
534
mainwindow.cpp
@ -381,7 +381,7 @@ EventDataType calcAHI(QDate start, QDate end)
|
|||||||
|
|
||||||
struct RXChange
|
struct RXChange
|
||||||
{
|
{
|
||||||
RXChange() {}
|
RXChange() { highlight=0; }
|
||||||
RXChange(const RXChange & copy) {
|
RXChange(const RXChange & copy) {
|
||||||
first=copy.first;
|
first=copy.first;
|
||||||
last=copy.last;
|
last=copy.last;
|
||||||
@ -389,8 +389,10 @@ struct RXChange
|
|||||||
ahi=copy.ahi;
|
ahi=copy.ahi;
|
||||||
mode=copy.mode;
|
mode=copy.mode;
|
||||||
min=copy.min;
|
min=copy.min;
|
||||||
max=copy.min;
|
max=copy.max;
|
||||||
p90=copy.p90;
|
p90=copy.p90;
|
||||||
|
highlight=copy.highlight;
|
||||||
|
weighted=copy.weighted;
|
||||||
}
|
}
|
||||||
QDate first;
|
QDate first;
|
||||||
QDate last;
|
QDate last;
|
||||||
@ -400,11 +402,74 @@ struct RXChange
|
|||||||
EventDataType min;
|
EventDataType min;
|
||||||
EventDataType max;
|
EventDataType max;
|
||||||
EventDataType p90;
|
EventDataType p90;
|
||||||
|
EventDataType weighted;
|
||||||
|
short highlight;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum RXSortMode { RX_first, RX_last, RX_days, RX_ahi, RX_mode, RX_min, RX_max, RX_p90, RX_weighted };
|
||||||
|
RXSortMode RXsort=RX_first;
|
||||||
|
bool RXorder=false;
|
||||||
|
|
||||||
bool operator<(const RXChange & comp1, const RXChange & comp2) {
|
bool operator<(const RXChange & comp1, const RXChange & comp2) {
|
||||||
return comp1.ahi < comp2.ahi;
|
if (RXorder) {
|
||||||
|
switch (RXsort) {
|
||||||
|
case RX_ahi: return comp1.ahi < comp2.ahi;
|
||||||
|
case RX_days: return comp1.days < comp2.days;
|
||||||
|
case RX_first: return comp1.first < comp2.first;
|
||||||
|
case RX_last: return comp1.last < comp2.last;
|
||||||
|
case RX_mode: return comp1.mode < comp2.mode;
|
||||||
|
case RX_min: return comp1.min < comp2.min;
|
||||||
|
case RX_max: return comp1.max < comp2.max;
|
||||||
|
case RX_p90: return comp1.p90 < comp2.p90;
|
||||||
|
case RX_weighted: return comp1.weighted < comp2.weighted;
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
switch (RXsort) {
|
||||||
|
case RX_ahi: return comp1.ahi > comp2.ahi;
|
||||||
|
case RX_days: return comp1.days > comp2.days;
|
||||||
|
case RX_first: return comp1.first > comp2.first;
|
||||||
|
case RX_last: return comp1.last > comp2.last;
|
||||||
|
case RX_mode: return comp1.mode > comp2.mode;
|
||||||
|
case RX_min: return comp1.min > comp2.min;
|
||||||
|
case RX_max: return comp1.max > comp2.max;
|
||||||
|
case RX_p90: return comp1.p90 > comp2.p90;
|
||||||
|
case RX_weighted: return comp1.weighted > comp2.weighted;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
bool RXSort(const RXChange * comp1, const RXChange * comp2) {
|
||||||
|
if (RXorder) {
|
||||||
|
switch (RXsort) {
|
||||||
|
case RX_ahi: return comp1->ahi < comp2->ahi;
|
||||||
|
case RX_days: return comp1->days < comp2->days;
|
||||||
|
case RX_first: return comp1->first < comp2->first;
|
||||||
|
case RX_last: return comp1->last < comp2->last;
|
||||||
|
case RX_mode: return comp1->mode < comp2->mode;
|
||||||
|
case RX_min: return comp1->min < comp2->min;
|
||||||
|
case RX_max: return comp1->max < comp2->max;
|
||||||
|
case RX_p90: return comp1->p90 < comp2->p90;
|
||||||
|
case RX_weighted: return comp1->weighted < comp2->weighted;
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
switch (RXsort) {
|
||||||
|
case RX_ahi: return comp1->ahi > comp2->ahi;
|
||||||
|
case RX_days: return comp1->days > comp2->days;
|
||||||
|
case RX_first: return comp1->first > comp2->first;
|
||||||
|
case RX_last: return comp1->last > comp2->last;
|
||||||
|
case RX_mode: return comp1->mode > comp2->mode;
|
||||||
|
case RX_min: return comp1->min > comp2->min;
|
||||||
|
case RX_max: return comp1->max > comp2->max;
|
||||||
|
case RX_p90: return comp1->p90 > comp2->p90;
|
||||||
|
case RX_weighted: return comp1->weighted > comp2->weighted;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//bool operator<(const RXChange * & comp1, const RXChange * & comp2) {
|
||||||
|
|
||||||
|
//}
|
||||||
|
|
||||||
void MainWindow::on_homeButton_clicked()
|
void MainWindow::on_homeButton_clicked()
|
||||||
{
|
{
|
||||||
@ -425,60 +490,159 @@ void MainWindow::on_homeButton_clicked()
|
|||||||
int cpapmonthdays=cpapmonth.daysTo(lastcpap);
|
int cpapmonthdays=cpapmonth.daysTo(lastcpap);
|
||||||
int cpapyeardays=cpapyear.daysTo(lastcpap);
|
int cpapyeardays=cpapyear.daysTo(lastcpap);
|
||||||
int cpap6monthdays=cpap6month.daysTo(lastcpap);
|
int cpap6monthdays=cpap6month.daysTo(lastcpap);
|
||||||
QList<Machine *> mach=PROFILE.GetMachines(MT_CPAP);
|
QList<Machine *> cpap_machines=PROFILE.GetMachines(MT_CPAP);
|
||||||
|
QList<Machine *> oximeters=PROFILE.GetMachines(MT_OXIMETER);
|
||||||
|
QList<Machine *> mach;
|
||||||
|
mach.append(cpap_machines);
|
||||||
|
mach.append(oximeters);
|
||||||
|
|
||||||
int days=firstcpap.daysTo(lastcpap);
|
int cpapdays=PROFILE.countDays(MT_CPAP,firstcpap,lastcpap);
|
||||||
if (days==0) {
|
if (mach.size()==0) {
|
||||||
html+="<p>No Machine Data Imported</p>";
|
html+="<p>No Machine Data Imported</p>";
|
||||||
} else {
|
} else {
|
||||||
html+=QString("<p>%1 day%2 of CPAP Data</p>").arg(days).arg(days>1 ? "s" : "");
|
|
||||||
|
|
||||||
html+=QString("<b>Summary Information as of %1</b>").arg(lastcpap.toString(Qt::SystemLocaleLongDate));
|
|
||||||
html+=QString("<table cellpadding=2 cellspacing=0 border=1 width=100%>"
|
|
||||||
"<tr><td><b>%1</b></td><td><b>%2</b></td><td><b>%3</b></td><td><b>%4</b></td><td><b>%5</b></td><td><b>%6</td></tr>")
|
|
||||||
.arg(tr("Details")).arg(tr("Most Recent")).arg(tr("Last 7 Days")).arg(tr("Last 30 Days")).arg(tr("Last 6 months")).arg(tr("Last Year"));
|
|
||||||
|
|
||||||
html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
|
|
||||||
.arg(tr("AHI"))
|
|
||||||
.arg(calcAHI(lastcpap,lastcpap),0,'f',2)
|
|
||||||
.arg(calcAHI(cpapweek,lastcpap),0,'f',2)
|
|
||||||
.arg(calcAHI(cpapmonth,lastcpap),0,'f',2)
|
|
||||||
.arg(calcAHI(cpap6month,lastcpap),0,'f',2)
|
|
||||||
.arg(calcAHI(cpapyear,lastcpap),0,'f',2);
|
|
||||||
html+="<tr><td colspan=6>Note, these are different to overview calcs.. Overview shows a simple average AHI, this shows combined counts divide by combined hours</td></tr>";
|
|
||||||
|
|
||||||
html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
|
|
||||||
.arg(tr("Usage (Average)"))
|
|
||||||
.arg(p_profile->calcHours(MT_CPAP),0,'f',2)
|
|
||||||
.arg(p_profile->calcHours(MT_CPAP,cpapweek,lastcpap)/float(cpapweekdays),0,'f',2)
|
|
||||||
.arg(p_profile->calcHours(MT_CPAP,cpapmonth,lastcpap)/float(cpapmonthdays),0,'f',2)
|
|
||||||
.arg(p_profile->calcHours(MT_CPAP,cpap6month,lastcpap)/float(cpap6monthdays),0,'f',2)
|
|
||||||
.arg(p_profile->calcHours(MT_CPAP,cpapyear,lastcpap)/float(cpapyeardays),0,'f',2);
|
|
||||||
|
|
||||||
html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
|
|
||||||
.arg(tr("Average Pressure"))
|
|
||||||
.arg(p_profile->calcWavg(CPAP_Pressure,MT_CPAP))
|
|
||||||
.arg(p_profile->calcWavg(CPAP_Pressure,MT_CPAP,cpapweek,lastcpap),0,'f',3)
|
|
||||||
.arg(p_profile->calcWavg(CPAP_Pressure,MT_CPAP,cpapmonth,lastcpap),0,'f',3)
|
|
||||||
.arg(p_profile->calcWavg(CPAP_Pressure,MT_CPAP,cpap6month,lastcpap),0,'f',3)
|
|
||||||
.arg(p_profile->calcWavg(CPAP_Pressure,MT_CPAP,cpapyear,lastcpap),0,'f',3);
|
|
||||||
html+="<tr><td colspan=6>TODO: 90% pressure.. Any point showing if this is all CPAP?</td></tr>";
|
|
||||||
|
|
||||||
|
|
||||||
html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
|
html+=QString("<p><b>Summary Information as of %1</b></p>").arg(lastcpap.toString(Qt::SystemLocaleLongDate));
|
||||||
.arg(tr("Average Leaks"))
|
html+=QString("<table cellpadding=2 cellspacing=0 border=1 width=100%>");
|
||||||
.arg(p_profile->calcWavg(CPAP_Leak,MT_CPAP))
|
|
||||||
.arg(p_profile->calcWavg(CPAP_Leak,MT_CPAP,cpapweek,lastcpap),0,'f',3)
|
|
||||||
.arg(p_profile->calcWavg(CPAP_Leak,MT_CPAP,cpapmonth,lastcpap),0,'f',3)
|
|
||||||
.arg(p_profile->calcWavg(CPAP_Leak,MT_CPAP,cpap6month,lastcpap),0,'f',3)
|
|
||||||
.arg(p_profile->calcWavg(CPAP_Leak,MT_CPAP,cpapyear,lastcpap),0,'f',3);
|
|
||||||
html+="<tr><td colspan=6>What about median leak values? 90% Leaks?</td></tr>";
|
|
||||||
|
|
||||||
|
if (cpap_machines.size()>0) {
|
||||||
|
html+=QString("<tr><td colspan=6><b>%1</b></td></tr>").arg(tr("CPAP Summary"));
|
||||||
|
|
||||||
|
if (!cpapdays) {
|
||||||
|
html+=QString("<tr><td colspan=6><b>%1</b></td></tr>").arg(tr("No CPAP data available."));
|
||||||
|
} else if (cpapdays==1) {
|
||||||
|
html+=QString("<tr><td colspan=6>%1</td></tr>").arg(QString(tr("%1 day of CPAP Data, on %2.")).arg(cpapdays).arg(firstcpap.toString(Qt::SystemLocaleShortDate)));
|
||||||
|
} else {
|
||||||
|
html+=QString("<tr><td colspan=6>%1</td></tr>").arg(QString(tr("%1 days of CPAP Data, between %2 and %3")).arg(cpapdays).arg(firstcpap.toString(Qt::SystemLocaleShortDate)).arg(lastcpap.toString(Qt::SystemLocaleShortDate)));
|
||||||
|
}
|
||||||
|
|
||||||
|
html+=QString("<tr><td><b>%1</b></td><td><b>%2</b></td><td><b>%3</b></td><td><b>%4</b></td><td><b>%5</b></td><td><b>%6</td></tr>")
|
||||||
|
.arg(tr("Details")).arg(tr("Most Recent")).arg(tr("Last 7 Days")).arg(tr("Last 30 Days")).arg(tr("Last 6 months")).arg(tr("Last Year"));
|
||||||
|
html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
|
||||||
|
.arg(tr("AHI"))
|
||||||
|
.arg(calcAHI(lastcpap,lastcpap),0,'f',3)
|
||||||
|
.arg(calcAHI(cpapweek,lastcpap),0,'f',3)
|
||||||
|
.arg(calcAHI(cpapmonth,lastcpap),0,'f',3)
|
||||||
|
.arg(calcAHI(cpap6month,lastcpap),0,'f',3)
|
||||||
|
.arg(calcAHI(cpapyear,lastcpap),0,'f',3);
|
||||||
|
html+="<tr><td colspan=6>Note, these are different to overview calcs.. Overview shows a simple average AHI, this shows combined counts divide by combined hours</td></tr>";
|
||||||
|
|
||||||
|
html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
|
||||||
|
.arg(tr("Usage (Average)"))
|
||||||
|
.arg(p_profile->calcHours(MT_CPAP),0,'f',3)
|
||||||
|
.arg(p_profile->calcHours(MT_CPAP,cpapweek,lastcpap)/float(cpapweekdays),0,'f',3)
|
||||||
|
.arg(p_profile->calcHours(MT_CPAP,cpapmonth,lastcpap)/float(cpapmonthdays),0,'f',3)
|
||||||
|
.arg(p_profile->calcHours(MT_CPAP,cpap6month,lastcpap)/float(cpap6monthdays),0,'f',3)
|
||||||
|
.arg(p_profile->calcHours(MT_CPAP,cpapyear,lastcpap)/float(cpapyeardays),0,'f',3);
|
||||||
|
|
||||||
|
html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
|
||||||
|
.arg(tr("Average Pressure"))
|
||||||
|
.arg(p_profile->calcWavg(CPAP_Pressure,MT_CPAP),0,'f',3)
|
||||||
|
.arg(p_profile->calcWavg(CPAP_Pressure,MT_CPAP,cpapweek,lastcpap),0,'f',3)
|
||||||
|
.arg(p_profile->calcWavg(CPAP_Pressure,MT_CPAP,cpapmonth,lastcpap),0,'f',3)
|
||||||
|
.arg(p_profile->calcWavg(CPAP_Pressure,MT_CPAP,cpap6month,lastcpap),0,'f',3)
|
||||||
|
.arg(p_profile->calcWavg(CPAP_Pressure,MT_CPAP,cpapyear,lastcpap),0,'f',3);
|
||||||
|
|
||||||
|
if (p_profile->calcSettingsMax(CPAP_Mode,MT_CPAP,firstcpap,lastcpap)>MODE_CPAP) {
|
||||||
|
html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
|
||||||
|
.arg(tr("90% Pressure"))
|
||||||
|
.arg(p_profile->calcPercentile(CPAP_Pressure,0.9,MT_CPAP),0,'f',3)
|
||||||
|
.arg(p_profile->calcPercentile(CPAP_Pressure,0.9,MT_CPAP,cpapweek,lastcpap),0,'f',3)
|
||||||
|
.arg(p_profile->calcPercentile(CPAP_Pressure,0.9,MT_CPAP,cpapmonth,lastcpap),0,'f',3)
|
||||||
|
.arg(p_profile->calcPercentile(CPAP_Pressure,0.9,MT_CPAP,cpap6month,lastcpap),0,'f',3)
|
||||||
|
.arg(p_profile->calcPercentile(CPAP_Pressure,0.9,MT_CPAP,cpapyear,lastcpap),0,'f',3);
|
||||||
|
}
|
||||||
|
//html+="<tr><td colspan=6>TODO: 90% pressure.. Any point showing if this is all CPAP?</td></tr>";
|
||||||
|
|
||||||
|
|
||||||
|
html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
|
||||||
|
.arg(tr("Average Leaks"))
|
||||||
|
.arg(p_profile->calcWavg(CPAP_Leak,MT_CPAP),0,'f',3)
|
||||||
|
.arg(p_profile->calcWavg(CPAP_Leak,MT_CPAP,cpapweek,lastcpap),0,'f',3)
|
||||||
|
.arg(p_profile->calcWavg(CPAP_Leak,MT_CPAP,cpapmonth,lastcpap),0,'f',3)
|
||||||
|
.arg(p_profile->calcWavg(CPAP_Leak,MT_CPAP,cpap6month,lastcpap),0,'f',3)
|
||||||
|
.arg(p_profile->calcWavg(CPAP_Leak,MT_CPAP,cpapyear,lastcpap),0,'f',3);
|
||||||
|
html+="<tr><td colspan=6>What about median leak values? 90% Leaks?</td></tr>";
|
||||||
|
}
|
||||||
|
if (oximeters.size()>0) {
|
||||||
|
QDate lastoxi=p_profile->LastDay(MT_OXIMETER);
|
||||||
|
QDate firstoxi=p_profile->FirstDay(MT_OXIMETER);
|
||||||
|
html+=QString("<tr><td colspan=6><b>%1</b></td></tr>").arg(tr("Oximetry Summary"));
|
||||||
|
int days=PROFILE.countDays(MT_OXIMETER,firstcpap,lastcpap);
|
||||||
|
if (!days) {
|
||||||
|
html+=QString("<tr><td colspan=6><b>%1</b></td></tr>").arg(tr("No Oximetry data available."));
|
||||||
|
} else if (days==1) {
|
||||||
|
html+=QString("<tr><td colspan=6>%1</td></tr>").arg(QString(tr("%1 day of Oximetry Data, on %2.")).arg(days).arg(firstoxi.toString(Qt::SystemLocaleShortDate)));
|
||||||
|
} else {
|
||||||
|
html+=QString("<tr><td colspan=6>%1</td></tr>").arg(QString(tr("%1 days of Oximetry Data, between %2 and %3")).arg(days).arg(firstoxi.toString(Qt::SystemLocaleShortDate)).arg(lastoxi.toString(Qt::SystemLocaleShortDate)));
|
||||||
|
}
|
||||||
|
|
||||||
|
html+=QString("<tr><td><b>%1</b></td><td><b>%2</b></td><td><b>%3</b></td><td><b>%4</b></td><td><b>%5</b></td><td><b>%6</td></tr>")
|
||||||
|
.arg(tr("Details")).arg(tr("Most Recent")).arg(tr("Last 7 Days")).arg(tr("Last 30 Days")).arg(tr("Last 6 months")).arg(tr("Last Year"));
|
||||||
|
QDate oxiweek=lastcpap.addDays(-7);
|
||||||
|
QDate oximonth=lastcpap.addDays(-30);
|
||||||
|
QDate oxi6month=lastcpap.addMonths(-6);
|
||||||
|
QDate oxiyear=lastcpap.addYears(-12);
|
||||||
|
if (oxiweek<firstoxi) oxiweek=firstoxi;
|
||||||
|
if (oximonth<firstoxi) oximonth=firstoxi;
|
||||||
|
if (oxi6month<firstoxi) oxi6month=firstoxi;
|
||||||
|
if (oxiyear<firstoxi) oxiyear=firstoxi;
|
||||||
|
html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
|
||||||
|
.arg(tr("Average SpO2"))
|
||||||
|
.arg(p_profile->calcWavg(OXI_SPO2,MT_OXIMETER),0,'f',3)
|
||||||
|
.arg(p_profile->calcWavg(OXI_SPO2,MT_OXIMETER,oxiweek,lastoxi),0,'f',3)
|
||||||
|
.arg(p_profile->calcWavg(OXI_SPO2,MT_OXIMETER,oximonth,lastoxi),0,'f',3)
|
||||||
|
.arg(p_profile->calcWavg(OXI_SPO2,MT_OXIMETER,oxi6month,lastoxi),0,'f',3)
|
||||||
|
.arg(p_profile->calcWavg(OXI_SPO2,MT_OXIMETER,oxiyear,lastoxi),0,'f',3);
|
||||||
|
html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
|
||||||
|
.arg(tr("Minimum SpO2"))
|
||||||
|
.arg(p_profile->calcMin(OXI_SPO2,MT_OXIMETER),0,'f',3)
|
||||||
|
.arg(p_profile->calcMin(OXI_SPO2,MT_OXIMETER,oxiweek,lastoxi),0,'f',3)
|
||||||
|
.arg(p_profile->calcMin(OXI_SPO2,MT_OXIMETER,oximonth,lastoxi),0,'f',3)
|
||||||
|
.arg(p_profile->calcMin(OXI_SPO2,MT_OXIMETER,oxi6month,lastoxi),0,'f',3)
|
||||||
|
.arg(p_profile->calcMin(OXI_SPO2,MT_OXIMETER,oxiyear,lastoxi),0,'f',3);
|
||||||
|
html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
|
||||||
|
.arg(tr("SpO2 Events / Hour"))
|
||||||
|
.arg(p_profile->calcCount(OXI_SPO2Drop,MT_OXIMETER)/p_profile->calcHours(MT_OXIMETER),0,'f',3)
|
||||||
|
.arg(p_profile->calcCount(OXI_SPO2Drop,MT_OXIMETER,oxiweek,lastoxi)/p_profile->calcHours(MT_OXIMETER,oxiweek,lastoxi),0,'f',3)
|
||||||
|
.arg(p_profile->calcCount(OXI_SPO2Drop,MT_OXIMETER,oximonth,lastoxi)/p_profile->calcHours(MT_OXIMETER,oximonth,lastoxi),0,'f',3)
|
||||||
|
.arg(p_profile->calcCount(OXI_SPO2Drop,MT_OXIMETER,oxi6month,lastoxi)/p_profile->calcHours(MT_OXIMETER,oxi6month,lastoxi),0,'f',3)
|
||||||
|
.arg(p_profile->calcCount(OXI_SPO2Drop,MT_OXIMETER,oxiyear,lastoxi)/p_profile->calcHours(MT_OXIMETER,oxiyear,lastoxi),0,'f',3);
|
||||||
|
html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
|
||||||
|
.arg(tr("SpO2 Events / Hour"))
|
||||||
|
.arg(p_profile->calcCount(OXI_SPO2Drop,MT_OXIMETER)/p_profile->calcHours(MT_OXIMETER),0,'f',3)
|
||||||
|
.arg(p_profile->calcCount(OXI_SPO2Drop,MT_OXIMETER,oxiweek,lastoxi)/p_profile->calcHours(MT_OXIMETER,oxiweek,lastoxi),0,'f',3)
|
||||||
|
.arg(p_profile->calcCount(OXI_SPO2Drop,MT_OXIMETER,oximonth,lastoxi)/p_profile->calcHours(MT_OXIMETER,oximonth,lastoxi),0,'f',3)
|
||||||
|
.arg(p_profile->calcCount(OXI_SPO2Drop,MT_OXIMETER,oxi6month,lastoxi)/p_profile->calcHours(MT_OXIMETER,oxi6month,lastoxi),0,'f',3)
|
||||||
|
.arg(p_profile->calcCount(OXI_SPO2Drop,MT_OXIMETER,oxiyear,lastoxi)/p_profile->calcHours(MT_OXIMETER,oxiyear,lastoxi),0,'f',3);
|
||||||
|
html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
|
||||||
|
.arg(tr("Average Pulse Rate"))
|
||||||
|
.arg(p_profile->calcWavg(OXI_Pulse,MT_OXIMETER),0,'f',3)
|
||||||
|
.arg(p_profile->calcWavg(OXI_Pulse,MT_OXIMETER,oxiweek,lastoxi),0,'f',3)
|
||||||
|
.arg(p_profile->calcWavg(OXI_Pulse,MT_OXIMETER,oximonth,lastoxi),0,'f',3)
|
||||||
|
.arg(p_profile->calcWavg(OXI_Pulse,MT_OXIMETER,oxi6month,lastoxi),0,'f',3)
|
||||||
|
.arg(p_profile->calcWavg(OXI_Pulse,MT_OXIMETER,oxiyear,lastoxi),0,'f',3);
|
||||||
|
html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
|
||||||
|
.arg(tr("Minimum Pulse Rate"))
|
||||||
|
.arg(p_profile->calcMin(OXI_Pulse,MT_OXIMETER),0,'f',3)
|
||||||
|
.arg(p_profile->calcMin(OXI_Pulse,MT_OXIMETER,oxiweek,lastoxi),0,'f',3)
|
||||||
|
.arg(p_profile->calcMin(OXI_Pulse,MT_OXIMETER,oximonth,lastoxi),0,'f',3)
|
||||||
|
.arg(p_profile->calcMin(OXI_Pulse,MT_OXIMETER,oxi6month,lastoxi),0,'f',3)
|
||||||
|
.arg(p_profile->calcMin(OXI_Pulse,MT_OXIMETER,oxiyear,lastoxi),0,'f',3);
|
||||||
|
html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td></tr>")
|
||||||
|
.arg(tr("Maximum Pulse Rate"))
|
||||||
|
.arg(p_profile->calcMax(OXI_Pulse,MT_OXIMETER),0,'f',3)
|
||||||
|
.arg(p_profile->calcMax(OXI_Pulse,MT_OXIMETER,oxiweek,lastoxi),0,'f',3)
|
||||||
|
.arg(p_profile->calcMax(OXI_Pulse,MT_OXIMETER,oximonth,lastoxi),0,'f',3)
|
||||||
|
.arg(p_profile->calcMax(OXI_Pulse,MT_OXIMETER,oxi6month,lastoxi),0,'f',3)
|
||||||
|
.arg(p_profile->calcMax(OXI_Pulse,MT_OXIMETER,oxiyear,lastoxi),0,'f',3);
|
||||||
|
}
|
||||||
|
|
||||||
html+="</table>";
|
html+="</table>";
|
||||||
html+=QString("<br/><b>Changes to Prescription Settings</b>");
|
if (cpap_machines.size()>0) {
|
||||||
html+=QString("<table cellpadding=2 cellspacing=0 border=1 width=100%>");
|
html+=QString("<br/><b>Changes to Prescription Settings</b>");
|
||||||
html+=QString("<tr><td><b>%1</b></td><td><b>%2</b></td><td><b>%3</b></td><td><b>%4</b></td><td><b>%5</b></td><td><b>%6</b></td><td><b>%7</b></td><td><b>%8</b></td></tr>")
|
html+=QString("<table cellpadding=2 cellspacing=0 border=1 width=100%>");
|
||||||
|
html+=QString("<tr><td><b>%1</b></td><td><b>%2</b></td><td><b>%3</b></td><td><b>%4</b></td><td><b>%5</b></td><td><b>%6</b></td><td><b>%7</b></td><td><b>%8</b></td></tr>")
|
||||||
.arg(tr("First"))
|
.arg(tr("First"))
|
||||||
.arg(tr("Last"))
|
.arg(tr("Last"))
|
||||||
.arg(tr("Days"))
|
.arg(tr("Days"))
|
||||||
@ -488,78 +652,110 @@ void MainWindow::on_homeButton_clicked()
|
|||||||
.arg(tr("Max Pressure"))
|
.arg(tr("Max Pressure"))
|
||||||
.arg(tr("90% Pressure"));
|
.arg(tr("90% Pressure"));
|
||||||
|
|
||||||
QDate first,last=lastcpap;
|
QDate first,last=lastcpap;
|
||||||
CPAPMode mode,cmode=MODE_UNKNOWN;
|
CPAPMode mode,cmode=MODE_UNKNOWN;
|
||||||
EventDataType cmin=0,cmax=0,min,max;
|
EventDataType cmin=0,cmax=0,min,max;
|
||||||
QDate date=lastcpap;
|
QDate date=lastcpap;
|
||||||
Day * day;
|
Day * day;
|
||||||
bool lastchanged;
|
bool lastchanged;
|
||||||
int cnt=0;
|
int cnt=0;
|
||||||
QList<RXChange> rxchange;
|
QVector<RXChange> rxchange;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
day=PROFILE.GetDay(date,MT_CPAP);
|
day=PROFILE.GetDay(date,MT_CPAP);
|
||||||
lastchanged=false;
|
lastchanged=false;
|
||||||
if (day) {
|
if (day) {
|
||||||
mode=(CPAPMode)round(day->settings_wavg(CPAP_Mode));
|
mode=(CPAPMode)round(day->settings_wavg(CPAP_Mode));
|
||||||
min=day->settings_min(CPAP_PressureMin);
|
min=day->settings_min(CPAP_PressureMin);
|
||||||
if (mode==MODE_CPAP) {
|
if (mode==MODE_CPAP) {
|
||||||
max=day->settings_max(CPAP_PressureMin);
|
max=day->settings_max(CPAP_PressureMin);
|
||||||
} else max=day->settings_max(CPAP_PressureMax);
|
} else max=day->settings_max(CPAP_PressureMax);
|
||||||
|
|
||||||
if ((mode!=cmode) || (min!=cmin) || (max!=cmax)) {
|
if ((mode!=cmode) || (min!=cmin) || (max!=cmax)) {
|
||||||
if (cmode!=MODE_UNKNOWN) {
|
if (cmode!=MODE_UNKNOWN) {
|
||||||
first=date.addDays(1);
|
first=date.addDays(1);
|
||||||
RXChange rx;
|
int days=PROFILE.countDays(MT_CPAP,first,last);
|
||||||
rx.first=first;
|
RXChange rx;
|
||||||
rx.last=last;
|
rx.first=first;
|
||||||
rx.days=first.daysTo(last)+1;
|
rx.last=last;
|
||||||
rx.ahi=calcAHI(first,last);
|
rx.days=days;
|
||||||
rx.mode=cmode;
|
rx.ahi=calcAHI(first,last);
|
||||||
rx.min=cmin;
|
rx.mode=cmode;
|
||||||
rx.max=cmax;
|
rx.min=cmin;
|
||||||
rx.p90=0;
|
rx.max=cmax;
|
||||||
rxchange.push_back(rx);
|
rx.p90=p_profile->calcPercentile(CPAP_Pressure,0.9,MT_CPAP,first,last);
|
||||||
|
rx.weighted=float(rx.days)/float(cpapdays)*rx.ahi;
|
||||||
|
rxchange.push_back(rx);
|
||||||
|
}
|
||||||
|
cmode=mode;
|
||||||
|
cmin=min;
|
||||||
|
cmax=max;
|
||||||
|
last=date;
|
||||||
|
lastchanged=true;
|
||||||
}
|
}
|
||||||
cmode=mode;
|
|
||||||
cmin=min;
|
|
||||||
cmax=max;
|
|
||||||
last=date;
|
|
||||||
lastchanged=true;
|
|
||||||
}
|
}
|
||||||
|
date=date.addDays(-1);
|
||||||
|
} while (date>=firstcpap);
|
||||||
|
if (!lastchanged) {
|
||||||
|
last=date.addDays(1);
|
||||||
|
first=firstcpap;
|
||||||
|
int days=PROFILE.countDays(MT_CPAP,first,last);
|
||||||
|
RXChange rx;
|
||||||
|
rx.first=first;
|
||||||
|
rx.last=last;
|
||||||
|
rx.days=days;
|
||||||
|
rx.ahi=calcAHI(first,last);
|
||||||
|
rx.mode=mode;
|
||||||
|
rx.min=min;
|
||||||
|
rx.max=max;
|
||||||
|
rx.p90=p_profile->calcPercentile(CPAP_Pressure,0.9,MT_CPAP,first,last);
|
||||||
|
rx.weighted=float(rx.days)/float(cpapdays);
|
||||||
|
//rx.weighted=float(days)*rx.ahi;
|
||||||
|
rxchange.push_back(rx);
|
||||||
}
|
}
|
||||||
date=date.addDays(-1);
|
QVector<RXChange *> tmpRX;
|
||||||
} while (date>=firstcpap);
|
for (int i=0;i<rxchange.size();i++) {
|
||||||
if (!lastchanged) {
|
RXChange & rx=rxchange[i];
|
||||||
last=date.addDays(1);
|
if (rx.days>1)
|
||||||
first=firstcpap;
|
tmpRX.push_back(&rx);
|
||||||
RXChange rx;
|
}
|
||||||
rx.first=first;
|
RXsort=RX_ahi;
|
||||||
rx.last=last;
|
qSort(tmpRX.begin(),tmpRX.end(),RXSort);
|
||||||
rx.days=first.daysTo(last)+1;
|
tmpRX[0]->highlight=4; // worst
|
||||||
rx.ahi=calcAHI(first,last);
|
tmpRX[tmpRX.size()-1]->highlight=1; //best
|
||||||
rx.mode=mode;
|
|
||||||
rx.min=min;
|
|
||||||
rx.max=max;
|
|
||||||
rx.p90=0;
|
|
||||||
rxchange.push_back(rx);
|
|
||||||
}
|
|
||||||
qSort(rxchange);
|
|
||||||
for (int i=0;i<rxchange.size();i++) {
|
|
||||||
RXChange rx=rxchange.at(i);
|
|
||||||
html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td><td>%7</td><td>%8</td></tr>")
|
|
||||||
.arg(rx.first.toString(Qt::SystemLocaleShortDate))
|
|
||||||
.arg(rx.last.toString(Qt::SystemLocaleShortDate))
|
|
||||||
.arg(rx.days)
|
|
||||||
.arg(rx.ahi,0,'f',2)
|
|
||||||
.arg(schema::channel[CPAP_Mode].option(int(rx.mode)-1))
|
|
||||||
.arg(rx.min)
|
|
||||||
.arg(rx.max)
|
|
||||||
.arg(rx.p90);
|
|
||||||
}
|
|
||||||
|
|
||||||
html+="</table>";
|
if (tmpRX.size()>4) {
|
||||||
|
tmpRX[1]->highlight=3; // worst
|
||||||
|
tmpRX[tmpRX.size()-2]->highlight=2; //best
|
||||||
|
}
|
||||||
|
//RXsort=RX_first;
|
||||||
|
//qSort(rxchange);
|
||||||
|
|
||||||
|
for (int i=0;i<rxchange.size();i++) {
|
||||||
|
RXChange rx=rxchange.at(i);
|
||||||
|
QString color;
|
||||||
|
if (rx.highlight==1) {
|
||||||
|
color=" bgcolor='#80ff80'";
|
||||||
|
} else if (rx.highlight==2) {
|
||||||
|
color=" bgcolor='#d0ffd0'";
|
||||||
|
} else if (rx.highlight==3) {
|
||||||
|
color=" bgcolor='#ffd0d0'";
|
||||||
|
} else if (rx.highlight==4) {
|
||||||
|
color=" bgcolor='#ff8080'";
|
||||||
|
} else color="";
|
||||||
|
html+=QString("<tr"+color+"><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td><td>%6</td><td>%7</td><td>%8</td></tr>")
|
||||||
|
.arg(rx.first.toString(Qt::SystemLocaleShortDate))
|
||||||
|
.arg(rx.last.toString(Qt::SystemLocaleShortDate))
|
||||||
|
.arg(rx.days)
|
||||||
|
.arg(rx.ahi,0,'f',2)
|
||||||
|
.arg(schema::channel[CPAP_Mode].option(int(rx.mode)-1))
|
||||||
|
.arg(rx.min)
|
||||||
|
.arg(rx.max)
|
||||||
|
.arg(rx.p90);
|
||||||
|
}
|
||||||
|
html+="</table>";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (mach.size()>0) {
|
if (mach.size()>0) {
|
||||||
@ -575,6 +771,7 @@ void MainWindow::on_homeButton_clicked()
|
|||||||
Machine *m;
|
Machine *m;
|
||||||
for (int i=0;i<mach.size();i++) {
|
for (int i=0;i<mach.size();i++) {
|
||||||
m=mach.at(i);
|
m=mach.at(i);
|
||||||
|
if (m->GetType()==MT_JOURNAL) continue;
|
||||||
QString mn=m->properties[STR_PROP_ModelNumber];
|
QString mn=m->properties[STR_PROP_ModelNumber];
|
||||||
//if (mn.isEmpty())
|
//if (mn.isEmpty())
|
||||||
html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td></tr>")
|
html+=QString("<tr><td>%1</td><td>%2</td><td>%3</td><td>%4</td><td>%5</td></tr>")
|
||||||
@ -842,33 +1039,6 @@ void MainWindow::on_action_Frequently_Asked_Questions_triggered()
|
|||||||
ui->tabWidget->setCurrentIndex(0);
|
ui->tabWidget->setCurrentIndex(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
EventList *packEventList(EventList *ev)
|
|
||||||
{
|
|
||||||
EventList *nev=new EventList(EVL_Event);
|
|
||||||
|
|
||||||
EventDataType val,lastval=0;
|
|
||||||
qint64 time,lasttime=0;//,lasttime2=0;
|
|
||||||
|
|
||||||
lastval=ev->data(0);
|
|
||||||
lasttime=ev->time(0);
|
|
||||||
nev->AddEvent(lasttime,lastval);
|
|
||||||
|
|
||||||
for (unsigned i=1;i<ev->count();i++) {
|
|
||||||
val=ev->data(i);
|
|
||||||
time=ev->time(i);
|
|
||||||
if (val!=lastval) {
|
|
||||||
nev->AddEvent(time,val);
|
|
||||||
//lasttime2=time;
|
|
||||||
}
|
|
||||||
lastval=val;
|
|
||||||
lasttime=time;
|
|
||||||
}
|
|
||||||
if (val==lastval) {
|
|
||||||
nev->AddEvent(lasttime,val);
|
|
||||||
}
|
|
||||||
return nev;
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::PrintReport(gGraphView *gv,QString name, QDate date)
|
void MainWindow::PrintReport(gGraphView *gv,QString name, QDate date)
|
||||||
{
|
{
|
||||||
if (!gv) return;
|
if (!gv) return;
|
||||||
@ -1118,7 +1288,7 @@ void MainWindow::PrintReport(gGraphView *gv,QString name, QDate date)
|
|||||||
gGraph *g=(*gv)[i];
|
gGraph *g=(*gv)[i];
|
||||||
if (g->isEmpty()) continue;
|
if (g->isEmpty()) continue;
|
||||||
if (!g->visible()) continue;
|
if (!g->visible()) continue;
|
||||||
if (print_bookmarks && (g->title()==tr("Flow Rate"))) {
|
if (print_bookmarks) {
|
||||||
normal=false;
|
normal=false;
|
||||||
start.push_back(st);
|
start.push_back(st);
|
||||||
end.push_back(et);
|
end.push_back(et);
|
||||||
@ -1130,10 +1300,12 @@ void MainWindow::PrintReport(gGraphView *gv,QString name, QDate date)
|
|||||||
QVariantList et1=journal->settings[Bookmark_End].toList();
|
QVariantList et1=journal->settings[Bookmark_End].toList();
|
||||||
QStringList notes=journal->settings[Bookmark_Notes].toStringList();
|
QStringList notes=journal->settings[Bookmark_Notes].toStringList();
|
||||||
for (int i=0;i<notes.size();i++) {
|
for (int i=0;i<notes.size();i++) {
|
||||||
labels.push_back(notes.at(i));
|
if ((g->title()==tr("Flow Rate")) || (g->title()==tr("SpO2")) || (g->title()==tr("Pulse"))) {
|
||||||
start.push_back(st1.at(i).toLongLong());
|
labels.push_back(notes.at(i));
|
||||||
end.push_back(et1.at(i).toLongLong());
|
start.push_back(st1.at(i).toLongLong());
|
||||||
graphs.push_back(g);
|
end.push_back(et1.at(i).toLongLong());
|
||||||
|
graphs.push_back(g);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1223,6 +1395,59 @@ void MainWindow::PrintReport(gGraphView *gv,QString name, QDate date)
|
|||||||
Notify("SleepyHead has finished sending the job to the printer.");
|
Notify("SleepyHead has finished sending the job to the printer.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void packEventList(EventList *el, EventDataType minval=0)
|
||||||
|
{
|
||||||
|
if (el->count()<2) return;
|
||||||
|
EventList nel(EVL_Waveform);
|
||||||
|
EventDataType t,lastt=0; //el->data(0);
|
||||||
|
qint64 ti;//=el->time(0);
|
||||||
|
//nel.AddEvent(ti,lastt);
|
||||||
|
bool f;
|
||||||
|
qint64 lasttime=0;
|
||||||
|
EventDataType min=999,max=0;
|
||||||
|
for (quint32 i=0;i<el->count();i++) {
|
||||||
|
t=el->data(i);
|
||||||
|
ti=el->time(i);
|
||||||
|
f=false;
|
||||||
|
if (t>minval) {
|
||||||
|
if (t!=lastt) {
|
||||||
|
if (!lasttime) {
|
||||||
|
nel.setFirst(ti);
|
||||||
|
}
|
||||||
|
nel.AddEvent(ti,t);
|
||||||
|
if (t < min) min=t;
|
||||||
|
if (t > max) max=t;
|
||||||
|
lasttime=ti;
|
||||||
|
f=true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (lastt>minval) {
|
||||||
|
nel.AddEvent(ti,lastt);
|
||||||
|
lasttime=ti;
|
||||||
|
f=true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastt=t;
|
||||||
|
}
|
||||||
|
if (!f) {
|
||||||
|
if (t>minval) {
|
||||||
|
nel.AddEvent(ti,t);
|
||||||
|
lasttime=ti;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
el->setFirst(nel.first());
|
||||||
|
el->setLast(nel.last());
|
||||||
|
el->setMin(min);
|
||||||
|
el->setMax(max);
|
||||||
|
|
||||||
|
el->getData().clear();
|
||||||
|
el->getTime().clear();
|
||||||
|
el->setCount(nel.count());
|
||||||
|
|
||||||
|
el->getData()=nel.getData();
|
||||||
|
el->getTime()=nel.getTime();
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::on_action_Rebuild_Oximetry_Index_triggered()
|
void MainWindow::on_action_Rebuild_Oximetry_Index_triggered()
|
||||||
{
|
{
|
||||||
QVector<ChannelID> valid;
|
QVector<ChannelID> valid;
|
||||||
@ -1236,6 +1461,8 @@ void MainWindow::on_action_Rebuild_Oximetry_Index_triggered()
|
|||||||
|
|
||||||
QList<Machine *> machines=PROFILE.GetMachines(MT_OXIMETER);
|
QList<Machine *> machines=PROFILE.GetMachines(MT_OXIMETER);
|
||||||
|
|
||||||
|
qint64 f=0,l=0;
|
||||||
|
|
||||||
int discard_threshold=PROFILE.oxi->oxiDiscardThreshold();
|
int discard_threshold=PROFILE.oxi->oxiDiscardThreshold();
|
||||||
Machine *m;
|
Machine *m;
|
||||||
for (int z=0;z<machines.size();z++) {
|
for (int z=0;z<machines.size();z++) {
|
||||||
@ -1263,20 +1490,27 @@ void MainWindow::on_action_Rebuild_Oximetry_Index_triggered()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i=0;i<newlist.size();i++) {
|
for (int i=0;i<newlist.size();i++) {
|
||||||
EventList *nev=packEventList(newlist[i]);
|
packEventList(newlist[i],8);
|
||||||
|
|
||||||
|
/*EventList *nev=packEventList(newlist[i]);
|
||||||
if (nev->count()!=e.value()[i]->count() ) {
|
if (nev->count()!=e.value()[i]->count() ) {
|
||||||
delete newlist[i];
|
delete newlist[i];
|
||||||
newlist[i]=nev;
|
newlist[i]=nev;
|
||||||
} else {
|
} else {
|
||||||
delete nev;
|
delete nev;
|
||||||
}
|
}*/
|
||||||
|
EventList * el=newlist[i];
|
||||||
|
if (!f || f > el->first()) f=el->first();
|
||||||
|
if (!l || l < el->last()) l=el->last();
|
||||||
}
|
}
|
||||||
e.value()=newlist;
|
e.value()=newlist;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i=0;i<invalid.size();i++) {
|
for (int i=0;i<invalid.size();i++) {
|
||||||
sess->eventlist.erase(sess->eventlist.find(invalid[i]));
|
sess->eventlist.erase(sess->eventlist.find(invalid[i]));
|
||||||
}
|
}
|
||||||
|
if (f) sess->really_set_first(f);
|
||||||
|
if (l) sess->really_set_last(l);
|
||||||
sess->m_cnt.clear();
|
sess->m_cnt.clear();
|
||||||
sess->m_sum.clear();
|
sess->m_sum.clear();
|
||||||
sess->m_min.clear();
|
sess->m_min.clear();
|
||||||
|
17
oximetry.cpp
17
oximetry.cpp
@ -600,6 +600,7 @@ void CMS50Serial::ReadyRead()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
lastbytesize=size;
|
lastbytesize=size;
|
||||||
|
bool fixtime=false;
|
||||||
|
|
||||||
while (i<bytes.size()) {
|
while (i<bytes.size()) {
|
||||||
if (import_mode) {
|
if (import_mode) {
|
||||||
@ -620,16 +621,16 @@ void CMS50Serial::ReadyRead()
|
|||||||
// otherwise pick the first session of the last days data..
|
// otherwise pick the first session of the last days data..
|
||||||
Day *day=PROFILE.GetDay(PROFILE.LastDay(),MT_CPAP);
|
Day *day=PROFILE.GetDay(PROFILE.LastDay(),MT_CPAP);
|
||||||
QDateTime d;
|
QDateTime d;
|
||||||
|
fixtime=true;
|
||||||
if (day) {
|
if (day) {
|
||||||
int ti=day->first()/1000L;
|
int ti=day->first()/1000L;
|
||||||
|
|
||||||
d=QDateTime::fromTime_t(ti);
|
d=QDateTime::fromTime_t(ti);
|
||||||
qDebug() << "Guessing session starting from CPAP data" << d;
|
qDebug() << "Guessing session starting from CPAP data" << d;
|
||||||
} else {
|
} else {
|
||||||
qDebug() << "Can't guess start time, defaulting to 6pm yesterday" << d;
|
qDebug() << "Can't guess start time, defaulting to ending at 7:30am this morning" << d;
|
||||||
d=QDateTime::currentDateTime();
|
d=QDateTime::currentDateTime();
|
||||||
d.setTime(QTime(18,0,0));
|
d.setTime(QTime(7,30,0));
|
||||||
//d.addDays(-1);
|
//d.addDays(-1);
|
||||||
}
|
}
|
||||||
f2time.push_back(d);
|
f2time.push_back(d);
|
||||||
@ -647,6 +648,16 @@ void CMS50Serial::ReadyRead()
|
|||||||
datasize=(((unsigned char)bytes.at(i) & 0x3f) << 14) | (((unsigned char)bytes.at(i+1)&0x7f) << 7) | ((unsigned char)bytes.at(i+2) & 0x7f);
|
datasize=(((unsigned char)bytes.at(i) & 0x3f) << 14) | (((unsigned char)bytes.at(i+1)&0x7f) << 7) | ((unsigned char)bytes.at(i+2) & 0x7f);
|
||||||
received_bytes=0;
|
received_bytes=0;
|
||||||
qDebug() << "Data Size=" << datasize << "??";
|
qDebug() << "Data Size=" << datasize << "??";
|
||||||
|
if (fixtime) {
|
||||||
|
QDateTime time;
|
||||||
|
for (int i=0;i<f2time.size();i++) {
|
||||||
|
time=f2time.at(i);
|
||||||
|
time.addSecs(-(datasize/3));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
f2time.clear();
|
||||||
|
f2time.push_back(time);
|
||||||
|
}
|
||||||
done_import=false;
|
done_import=false;
|
||||||
|
|
||||||
i+=3;
|
i+=3;
|
||||||
|
@ -88,7 +88,7 @@ public:
|
|||||||
void compactToWaveform(EventList *el);
|
void compactToWaveform(EventList *el);
|
||||||
|
|
||||||
//! \brief Packs EventList to time delta format, also pruning zeros.
|
//! \brief Packs EventList to time delta format, also pruning zeros.
|
||||||
void compactToEvent(EventList *el);
|
static void compactToEvent(EventList *el);
|
||||||
|
|
||||||
//! \brief Packs SPO2 & Pulse to Events, and Plethy to Waveform EventList types.
|
//! \brief Packs SPO2 & Pulse to Events, and Plethy to Waveform EventList types.
|
||||||
void compactAll();
|
void compactAll();
|
||||||
|
Loading…
Reference in New Issue
Block a user