Weighted Average & TAP Graph fixes

This commit is contained in:
Mark Watkins 2011-08-07 21:37:56 +10:00
parent 67bfda3280
commit f045b49df5
10 changed files with 168 additions and 143 deletions

View File

@ -41,6 +41,9 @@ void gLineChart::Plot(gGraphWindow & w,float scrx,float scry)
EventDataType miny,maxy;
double minx,maxx;
miny=w.min_y, maxy=w.max_y, maxx=w.max_x, minx=w.min_x;
if (miny<0) {
miny=-MAX(fabs(miny),fabs(maxy));
}
int m;
if (maxy>500) {

View File

@ -217,63 +217,67 @@ void gTAPGraph::SetDay(Day *d)
gLayer::SetDay(d);
m_total=0;
if (!m_day) return;
QVector<qint64> tap;
const int max_value=2600;
tap.resize(max_value);
QMap<EventStoreType,qint64> tap;
EventStoreType data=0,lastval=0;
qint64 time=0,lasttime=0,lastlasttime=0;
qint64 time=0,lasttime=0,firsttime=0;
bool first=true;
bool rfirst=true;
bool changed;
EventDataType gain=1,offset=0;
for (QVector<Session *>::iterator s=m_day->begin();s!=m_day->end();s++) {
if ((*s)->eventlist.find(m_code)==(*s)->eventlist.end()) continue;
for (int q=0;q<(*s)->eventlist[m_code].size();q++) {
EventList &el=*(*s)->eventlist[m_code][q];
lasttime=el.time(0);
first=true;
for (int i=0;i<el.count();i++) {
data=el.raw(i);
if (data>max_value) {
qWarning() << "max_value is too small in gTAPGraph::SetDay()";
break;
}
time=el.time(i);
if (rfirst) {
gain=el.gain();
offset=el.offset();
rfirst=false;
}
if (first) {
first=false;
} else {
if (lastval!=data) {
int v=(time-lasttime)/1000;
tap[lastval]+=v;
}
}
lastlasttime=lasttime;
lasttime=time;
lastval=data;
firsttime=lasttime=el.time(0);
lastval=el.raw(0);
if (rfirst) {
gain=el.gain();
offset=el.offset();
rfirst=false;
}
if (lastval!=data){
first=true;
changed=false;
EventStoreType lastlastval;
for (int i=1;i<el.count();i++) {
data=el.raw(i);
time=el.time(i);
if (lastval!=data) {
qint64 v=(time-lasttime);
if (tap.find(lastval)!=tap.end()) {
tap[lastval]+=v;
} else {
tap[lastval]=v;
}
changed=true;
lasttime=time;
lastval=data;
}
}
if (time!=lasttime) {
qint64 v=(time-lasttime);
if (tap.find(lastval)!=tap.end()) {
tap[data]+=v;
} else {
tap[data]=v;
}
}
/*if (lastval!=data){
int v=(time-lastlasttime)/1000L;
tap[data]+=v;
}
} */
}
}
m_values.clear();
m_names.clear();
m_total=0;
EventDataType val;
for (int i=0;i<max_value;i++) {
if (tap[i]>0) {
val=float(i)*gain+offset;
m_values.push_back(tap[i]);
m_total+=tap[i];
m_names.push_back(QString::number(val,'f',2));
}
for (QMap<EventStoreType,qint64>::iterator i=tap.begin();i!=tap.end();i++) {
val=float(i.key())*gain+offset;
m_values.push_back(i.value()/1000L);
m_total+=i.value()/1000L;
m_names.push_back(QString::number(val,'f',2));
}
}

View File

@ -31,6 +31,9 @@ void gYAxis::Plot(gGraphWindow &w,float scrx,float scry)
double miny=w.min_y;
double maxy=w.max_y;
if (miny<0) {
miny=-MAX(fabs(miny),fabs(maxy));
}
double dy=maxy-miny;
if (dy<=0) {
//miny=miny;
@ -38,6 +41,7 @@ void gYAxis::Plot(gGraphWindow &w,float scrx,float scry)
dy=1;
}
int m;
if (maxy>500) {
m=ceil(maxy/100.0);
@ -91,9 +95,14 @@ void gYAxis::Plot(gGraphWindow &w,float scrx,float scry)
double mxy=MAX(fabs(maxy),fabs(miny));
double mny=MIN(fabs(maxy),fabs(miny));
if (miny<0) mny=-mny;
if (maxy<0) mxy=-mxy;
double mny=miny;
if (miny<0) {
mny=-mxy;
} else {
}
//double mny=MIN(fabs(maxy),fabs(miny));
//if (miny<0) mny=-mny;
//if (maxy<0) mxy=-mxy;
//mny=miny;
//mxy=maxy;
@ -170,7 +179,7 @@ void gYAxis::Plot(gGraphWindow &w,float scrx,float scry)
vertarray[vertcnt++]=h;
if (m_show_major_lines && (i > miny)) {
majorvertarray[majorvertcnt++]=start_px+1;
majorvertarray[majorvertcnt++]=start_px;
majorvertarray[majorvertcnt++]=h;
majorvertarray[majorvertcnt++]=start_px+width;
majorvertarray[majorvertcnt++]=h;

View File

@ -183,15 +183,21 @@ EventDataType Day::sum(ChannelID code)
EventDataType Day::wavg(ChannelID code)
{
double s0=0,s1=0,s2=0;
qint64 d;
for (QVector<Session *>::iterator s=sessions.begin();s!=sessions.end();s++) {
Session & sess=*(*s);
if (sess.eventlist.find(code)!=sess.eventlist.end()) {
s0=sess.hours();
s1+=sess.wavg(code)*s0;
s2+=s0;
if (sess.eventlist.contains(code)) {
d=sess.last(code)-sess.first(code);
s0=double(d)/1000.0;
if (s0>0) {
s1+=sess.wavg(code)*s0;
s2+=s0;
}
}
}
if (s2==0) return 0;
if (s2==0)
return 0;
return (s1/s2);
}
// Total session time in milliseconds
@ -297,6 +303,15 @@ int Day::count(ChannelID code)
}
return sum;
}
bool Day::channelExists(ChannelID id)
{
for (int i=0;i<sessions.size();i++) {
if (sessions[i]->channelExists(id))
return true;
}
return false;
}
void Day::OpenEvents()
{
QVector<Session *>::iterator s;

View File

@ -65,7 +65,7 @@ public:
void OpenEvents();
QVector<Session *> & getSessions() { return sessions; }
bool channelExists(ChannelID id);
protected:
QVector<Session *> sessions;
qint64 d_first,d_last;

View File

@ -360,10 +360,10 @@ int PRS1Loader::OpenMachine(Machine *m,QString path,Profile *profile)
sess->setAvg(CPAP_Pressure,(sess->avg(CPAP_EPAP)+sess->avg(CPAP_IPAP))/2.0);
sess->setWavg(CPAP_Pressure,(sess->wavg(CPAP_EPAP)+sess->wavg(CPAP_IPAP))/2.0);
sess->setMin(CPAP_Pressure,sess->min(CPAP_EPAP));
sess->setMax(CPAP_Pressure,sess->min(CPAP_IPAP));
sess->set90p(CPAP_Pressure,sess->min(CPAP_IPAP));
sess->setMax(CPAP_Pressure,sess->max(CPAP_IPAP));
sess->set90p(CPAP_Pressure,sess->p90(CPAP_IPAP));
sess->p90(CPAP_EPAP);
sess->p90(CPAP_IPAP);
//sess->p90(CPAP_IPAP);
} else {
sess->avg(CPAP_Pressure);
sess->wavg(CPAP_Pressure);

View File

@ -563,6 +563,7 @@ bool ResmedLoader::LoadBRP(Session *sess,EDFParser &edf)
long recs=edf.edfsignals[s]->nr*edf.GetNumDataRecords();
ChannelID code;
if (edf.edfsignals[s]->label=="Flow") {
es.gain*=60;
code=CPAP_FlowRate;
} else if (edf.edfsignals[s]->label=="Mask Pres") {
code=CPAP_MaskPressure;
@ -583,8 +584,8 @@ bool ResmedLoader::LoadBRP(Session *sess,EDFParser &edf)
v=floor(a->min()/1);
a->setMin(v*1); */
} else if (code==CPAP_FlowRate) {
a->setMax(1);
a->setMin(-1);
//a->setMax(1);
//a->setMin(-1);
}
sess->setMin(code,a->min());
sess->setMax(code,a->max());

View File

@ -692,7 +692,6 @@ EventDataType Session::wavg(ChannelID id)
return 0;
QVector<EventList *> & evec=jj.value();
bool first=true;
qint64 lasttime=0,time,td;
EventStoreType val,lastval=0;
@ -701,26 +700,20 @@ EventDataType Session::wavg(ChannelID id)
EventDataType gain=evec[0]->gain();
for (int i=0;i<evec.size();i++) {
for (int j=0;j<evec[i]->count();j++) {
lastval=evec[i]->raw(0);
lasttime=evec[i]->time(0);
for (int j=1;j<evec[i]->count();j++) {
val=evec[i]->raw(j);
time=evec[i]->time(j);
if (first) {
first=false;
} else {
td=(time-lasttime);
if (vtime.contains(lastval)) {
vtime[lastval]+=td;
} else vtime[lastval]=td;
}
td=(time-lasttime);
if (vtime.contains(lastval)) {
vtime[lastval]+=td;
} else vtime[lastval]=td;
lasttime=time;
lastval=val;
}
}
/*td=last()-lasttime;
if (vtime.contains(lastval)) {
vtime[lastval]+=td;
} else vtime[lastval]=td; */
qint64 s0=0,s1=0,s2=0; // 32bit may all be thats needed here..
for (QHash<EventStoreType,quint32>::iterator i=vtime.begin(); i!=vtime.end(); i++) {
@ -728,8 +721,14 @@ EventDataType Session::wavg(ChannelID id)
s1+=i.key()*s0;
s2+=s0;
}
double j=double(s1)/double(s_last-s_first);
double j=double(s1)/double(s2);
EventDataType v=j*gain;
if (v>32768*gain) {
v=0;
}
if (v<-(32768*gain)) {
v=0;
}
m_wavg[id]=v;
return v;
}

136
daily.cpp
View File

@ -755,54 +755,44 @@ void Daily::Load(QDate date)
}
html+="</table>"
"<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n"
"<tr height='2'><td colspan=4 height='2'><hr></td></tr>\n";
"<tr height='2'><td colspan=5 height='2'><hr></td></tr>\n";
if (mode==MODE_BIPAP) {
html+="<tr><td colspan=4 align='center'><i>"+tr("90%&nbsp;EPAP ")+QString().sprintf("%.2f",eap90)+tr("cmH2O")+"</td></tr>\n"
"<tr><td colspan=4 align='center'><i>"+tr("90%&nbsp;IPAP ")+QString().sprintf("%.2f",iap90)+tr("cmH2O")+"</td></tr>\n";
/* if (mode==MODE_BIPAP) {
html+="<tr><td colspan=4 align='center'><i>"+tr("90%&nbsp; EPAP ")+QString().sprintf("%.2f",eap90)+tr("cmH2O")+"</td></tr>\n"
"<tr><td colspan=4 align='center'><i>"+tr("90%&nbsp; IPAP ")+QString().sprintf("%.2f",iap90)+tr("cmH2O")+"</td></tr>\n";
} else if (mode==MODE_APAP) {
html+=("<tr><td colspan=4 align='center'><i>")+tr("90%&nbsp;Pressure ")+QString().sprintf("%.2f",p90)+("</i></td></tr>\n"); //cpap->summary_weighted_avg(CPAP_PressurePercentValue)
html+=("<tr><td colspan=4 align='center'><i>")+tr("90%&nbsp; Auto Pressure ")+QString().sprintf("%.2f",p90)+("</i></td></tr>\n"); //cpap->summary_weighted_avg(CPAP_PressurePercentValue)
} else if (mode==MODE_CPAP) {
html+=("<tr><td colspan=4 align='center'><i>")+tr("Pressure ")+QString().sprintf("%.2f",cpap->max(CPAP_Pressure))+("</i></td></tr>\n");
}
html+=("<tr><td colspan=4 align='center'><i>")+tr("CPAP Pressure ")+QString().sprintf("%.2f",cpap->max(CPAP_Pressure))+("</i></td></tr>\n");
}*/
//html+=("<tr><td colspan=4 align=center>&nbsp;</td></tr>\n");
html+=("<tr><td> </td><td><b>Min</b></td><td><b>Avg</b></td><td><b>Max</b></td></tr>");
if (mode==MODE_APAP) {
html+="<tr><td align=left>"+tr("Pressure:")+"</td><td>"+a.sprintf("%.2f",cpap->min(CPAP_Pressure));
html+=(" </td><td>")+a.sprintf("%.2f",cpap->wavg(CPAP_Pressure));
html+=("</td><td>")+a.sprintf("%.2f",cpap->max(CPAP_Pressure))+("</td></tr>");
// html+=wxT("<tr><td><b>")+_("90%&nbsp;Pressure")+wxT("</b></td><td>")+wxString::Format(wxT("%.1fcmH2O"),p90)+wxT("</td></tr>\n");
} else if (mode==MODE_BIPAP) {
html+=("<tr><td align=left>"+tr("EPAP:")+"</td><td>")+a.sprintf("%.2f",cpap->min(CPAP_EPAP));
html+=(" </td><td>")+a.sprintf("%.2f",cpap->wavg(CPAP_EPAP));
html+=("</td><td>")+a.sprintf("%.2f",cpap->max(CPAP_EPAP))+("</td></tr>");
html+=("<tr><td align=left>"+tr("IPAP:")+"</td><td>")+a.sprintf("%.2f",cpap->min(CPAP_IPAP));
html+=("</td><td>")+a.sprintf("%.2f",cpap->wavg(CPAP_IPAP));
html+=("</td><td>")+a.sprintf("%.2f",cpap->max(CPAP_IPAP))+("</td></tr>");
html+=("<tr><td align=left>"+tr("PS:")+"</td><td>")+a.sprintf("%.2f",cpap->min(CPAP_PressureSupport));
html+=("</td><td>")+a.sprintf("%.2f",cpap->wavg(CPAP_PressureSupport));
html+=("</td><td>")+a.sprintf("%.2f",cpap->max(CPAP_PressureSupport))+("</td></tr>");
html+=("<tr><td> </td><td><b>Min</b></td><td><b>Avg</b></td><td><b>90%</b></td><td><b>Max</b></td></tr>");
ChannelID chans[]={CPAP_Pressure,CPAP_EPAP,CPAP_IPAP,CPAP_PressureSupport,CPAP_PatientTriggeredBreaths, CPAP_MinuteVentilation,CPAP_RespiratoryRate,CPAP_FlowLimitGraph,CPAP_Leak,CPAP_Snore,CPAP_TidalVolume,CPAP_Pulse,CPAP_SPO2};
int numchans=sizeof(chans)/sizeof(ChannelID);
for (int i=0;i<numchans;i++) {
ChannelID code=chans[i];
if (cpap->channelExists(code)) {
html+="<tr><td align=left>"+channel[code].label();
html+="</td><td>"+a.sprintf("%.2f",cpap->min(code));
html+="</td><td>"+a.sprintf("%.2f",cpap->wavg(code));
html+="</td><td>"+a.sprintf("%.2f",cpap->p90(code));
html+="</td><td>"+a.sprintf("%.2f",cpap->max(code));
html+="</td><tr>";
}
}
html+="<tr><td align=left>"+tr("Leak:");
html+="</td><td>"+a.sprintf("%.2f",cpap->min(CPAP_Leak));
html+="</td><td>"+a.sprintf("%.2f",cpap->wavg(CPAP_Leak));
html+="</td><td>"+a.sprintf("%.2f",cpap->max(CPAP_Leak))+("</td><tr>");
html+="<tr><td align=left>"+tr("Snore:");
/*html+="<tr><td align=left>"+tr("Snore:");
html+="</td><td>"+a.sprintf("%.2f",cpap->min(CPAP_Snore));
html+="</td><td>"+a.sprintf("%.2f",cpap->avg(CPAP_Snore));
html+="</td><td>"+a.sprintf("%.2f",cpap->max(CPAP_Snore))+("</td><tr>");
*/
} else {
html+="<tr><td colspan=4 align=center><i>"+tr("No CPAP data available")+"</i></td></tr>";
html+="<tr><td colspan=4>&nbsp;</td></tr>\n";
html+="<tr><td colspan=5 align=center><i>"+tr("No CPAP data available")+"</i></td></tr>";
html+="<tr><td colspan=5>&nbsp;</td></tr>\n";
}
// Instead of doing this, check whether any data exists..
@ -820,13 +810,17 @@ void Daily::Load(QDate date)
if (oxi) {
html+="<tr><td>"+tr("Pulse:");
html+="</td><td>"+a.sprintf("%.2fbpm",oxi->min(OXI_Pulse));
html+="</td><td>"+a.sprintf("%.2fbpm",oxi->avg(OXI_Pulse));
html+="</td><td>"+a.sprintf("%.2fbpm",oxi->max(OXI_Pulse))+"</td><tr>";
html+="</td><td>"+a.sprintf("%.2fbpm",oxi->wavg(OXI_Pulse));
html+="</td><td>"+a.sprintf("%.2fbpm",oxi->p90(OXI_Pulse));
html+="</td><td>"+a.sprintf("%.2fbpm",oxi->max(OXI_Pulse));
html+="</td><tr>";
html+="<tr><td>"+tr("SpO2:");
html+="</td><td>"+a.sprintf("%.2f%%",oxi->min(OXI_SPO2));
html+="</td><td>"+a.sprintf("%.2f%%",oxi->avg(OXI_SPO2));
html+="</td><td>"+a.sprintf("%.2f%%",oxi->max(OXI_SPO2))+"</td><tr>";
html+="</td><td>"+a.sprintf("%.2f%%",oxi->wavg(OXI_SPO2));
html+="</td><td>"+a.sprintf("%.2f%%",oxi->p90(OXI_SPO2));
html+="</td><td>"+a.sprintf("%.2f%%",oxi->max(OXI_SPO2));
html+="</td><tr>";
//html+=wxT("<tr><td colspan=4>&nbsp;</td></tr>\n");
@ -838,39 +832,39 @@ void Daily::Load(QDate date)
}
if (cpap) {
if (mode==MODE_BIPAP) {
if (pref["EnableGraphSnapshots"].toBool()) {
{
html+=("<tr><td colspan=4 align=center><i>")+tr("Time@EPAP")+("</i></td></tr>\n");
TAP_EAP->setFixedSize(gwwidth,30);
QPixmap pixmap=TAP_EAP->renderPixmap(gwwidth,30,false);
QByteArray byteArray;
QBuffer buffer(&byteArray); // use buffer to store pixmap into byteArray
buffer.open(QIODevice::WriteOnly);
pixmap.save(&buffer, "PNG");
html+="<tr><td colspan=4 align=center><img src=\"data:image/png;base64," + byteArray.toBase64() + "\"></td></tr>\n";
}
{
html+=("<tr><td colspan=4 align=center><i>")+tr("Time@IPAP")+("</i></td></tr>\n");
TAP_IAP->setFixedSize(gwwidth,30);
QPixmap pixmap=TAP_IAP->renderPixmap(gwwidth,30,false);
QByteArray byteArray;
QBuffer buffer(&byteArray); // use buffer to store pixmap into byteArray
buffer.open(QIODevice::WriteOnly);
pixmap.save(&buffer, "PNG");
html+="<tr><td colspan=4 align=center><img src=\"data:image/png;base64," + byteArray.toBase64() + "\"></td></tr>\n";
}
html+="</table>"
"<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n";
if (pref["EnableGraphSnapshots"].toBool()) {
if (cpap->channelExists(CPAP_Pressure)) {
html+=("<tr><td colspan=4 align=center><i>")+tr("Time@Pressure")+("</i></td></tr>\n");
TAP->setFixedSize(gwwidth,30);
QPixmap pixmap=TAP->renderPixmap(gwwidth,30,false);
QByteArray byteArray;
QBuffer buffer(&byteArray); // use buffer to store pixmap into byteArray
buffer.open(QIODevice::WriteOnly);
pixmap.save(&buffer, "PNG");
html+="<tr><td colspan=4 align=center><img src=\"data:image/png;base64," + byteArray.toBase64() + "\"></td></tr>\n";
}
} else if (mode==MODE_APAP) {
if (pref["EnableGraphSnapshots"].toBool()) {
html+=("<tr><td colspan=4 align=center><i>")+tr("Time@Pressure")+("</i></td></tr>\n");
TAP->setFixedSize(gwwidth,30);
QPixmap pixmap=TAP->renderPixmap(gwwidth,30,false);
QByteArray byteArray;
QBuffer buffer(&byteArray); // use buffer to store pixmap into byteArray
buffer.open(QIODevice::WriteOnly);
pixmap.save(&buffer, "PNG");
html+="<tr><td colspan=4 align=center><img src=\"data:image/png;base64," + byteArray.toBase64() + "\"></td></tr>\n";
if (cpap->channelExists(CPAP_EPAP)) {
//html+="<tr height='2'><td colspan=4 height='2'><hr></td></tr>\n";
html+=("<tr><td colspan=4 align=center><i>")+tr("Time@EPAP")+("</i></td></tr>\n");
TAP_EAP->setFixedSize(gwwidth,30);
QPixmap pixmap=TAP_EAP->renderPixmap(gwwidth,30,false);
QByteArray byteArray;
QBuffer buffer(&byteArray); // use buffer to store pixmap into byteArray
buffer.open(QIODevice::WriteOnly);
pixmap.save(&buffer, "PNG");
html+="<tr><td colspan=4 align=center><img src=\"data:image/png;base64," + byteArray.toBase64() + "\"></td></tr>\n";
}
if (cpap->channelExists(CPAP_IPAP)) {
html+=("<tr><td colspan=4 align=center><i>")+tr("Time@IPAP")+("</i></td></tr>\n");
TAP_IAP->setFixedSize(gwwidth,30);
QPixmap pixmap=TAP_IAP->renderPixmap(gwwidth,30,false);
QByteArray byteArray;
QBuffer buffer(&byteArray); // use buffer to store pixmap into byteArray
buffer.open(QIODevice::WriteOnly);
pixmap.save(&buffer, "PNG");
html+="<tr><td colspan=4 align=center><img src=\"data:image/png;base64," + byteArray.toBase64() + "\"></td></tr>\n";
}
}
html+="</table><hr height=2><table cellpadding=0 cellspacing=0 border=0 width=100%>";

View File

@ -34,7 +34,7 @@
<widget class="QSplitter" name="splitter">
<property name="maximumSize">
<size>
<width>265</width>
<width>300</width>
<height>16777215</height>
</size>
</property>
@ -56,7 +56,7 @@
</property>
<property name="maximumSize">
<size>
<width>265</width>
<width>300</width>
<height>180</height>
</size>
</property>
@ -85,7 +85,7 @@
<widget class="QTabWidget" name="tabWidget">
<property name="maximumSize">
<size>
<width>265</width>
<width>300</width>
<height>16777215</height>
</size>
</property>