PRS1/Intellipap Leak improvements

This commit is contained in:
Mark Watkins 2011-11-30 22:32:16 +10:00
parent 8aefb817b4
commit 1fcfdb2854
9 changed files with 98 additions and 28 deletions

View File

@ -279,6 +279,59 @@ int CalcAHIGraph::calculate(Session *session)
return AHI->count();
}
int calcLeaks(Session *session)
{
if (session->eventlist.contains(CPAP_Leak)) return 0; // abort if already there
if (!session->eventlist.contains(CPAP_LeakTotal)) return 0; // can't calculate without this..
const qint64 winsize=3600000; // 5 minute window
qint64 first=session->first(),
last=session->last(),
f;
EventList *leak=new EventList(EVL_Event);
session->eventlist[CPAP_Leak].push_back(leak);
const int rbsize=128;
EventDataType rbuf[rbsize],tmp,median;
qint64 rtime[rbsize],ti;
int rpos=0;
int tcnt=0;
QVector<EventDataType> med;
for (int i=0;i<session->eventlist[CPAP_LeakTotal].size();i++) {
EventList & el=*session->eventlist[CPAP_LeakTotal][i];
for (unsigned j=0;j<el.count();j++) {
tmp=el.data(j);
ti=el.time(j);
rbuf[rpos]=tmp;
rtime[rpos]=ti;
tcnt++;
rpos++;
int rcnt;
if (tcnt<rbsize) rcnt=tcnt; else rcnt=rbsize;
med.clear();
for (int k=0;k<rcnt;k++) {
if (rtime[k] > ti-winsize) // if fits in time window, add to the list
med.push_back(rbuf[k]);
}
qSort(med);
int idx=float(med.size() * 0.0);
if (idx>=med.size()) idx--;
median=tmp-med[idx];
if (median<0) median=0;
leak->AddEvent(ti,median);
rpos=rpos % rbsize;
}
}
return leak->count();
}
int calcPulseChange(Session *session)
{

View File

@ -36,6 +36,8 @@ public:
protected:
};
int calcLeaks(Session *session);
int calcPulseChange(Session *session);
int calcSPO2Drop(Session *session);

View File

@ -206,10 +206,10 @@ int IntellipapLoader::Open(QString & path,Profile *profile)
sess->AddEventList(CPAP_Te,EVL_Event);
sess->AddEventList(CPAP_Ti,EVL_Event);
sess->AddEventList(CPAP_Leak,EVL_Event);
sess->AddEventList(CPAP_LeakTotal,EVL_Event);
sess->AddEventList(CPAP_MaxLeak,EVL_Event);
//sess->AddEventList(CPAP_AHI,EVL_Event);
sess->AddEventList(CPAP_TidalVolume,EVL_Event);
sess->AddEventList(CPAP_MinuteVent,EVL_Event);
sess->AddEventList(CPAP_RespRate,EVL_Event);
sess->AddEventList(CPAP_Snore,EVL_Event);
} else {
@ -243,15 +243,16 @@ int IntellipapLoader::Open(QString & path,Profile *profile)
if ((ts1>=(quint32)sid) && (ts1<SessionEnd[j])){
Session *sess=Sessions[sid];
qint64 time=quint64(ts1)*1000L;
sess->eventlist[CPAP_Pressure][0]->AddEvent(time,m_buffer[pos+0xd]/10.0); // 0x0d
sess->eventlist[CPAP_EPAP][0]->AddEvent(time,m_buffer[pos+0x13]/10.0);
sess->eventlist[CPAP_IPAP][0]->AddEvent(time,m_buffer[pos+0x14]/10.0);
sess->eventlist[CPAP_Pressure][0]->AddEvent(time,m_buffer[pos+0xd]/10.0); // current pressure
sess->eventlist[CPAP_EPAP][0]->AddEvent(time,m_buffer[pos+0x13]/10.0); // epap / low
sess->eventlist[CPAP_IPAP][0]->AddEvent(time,m_buffer[pos+0x14]/10.0); // ipap / high
sess->eventlist[CPAP_Leak][0]->AddEvent(time,m_buffer[pos+0x7]); //correct
sess->eventlist[CPAP_MaxLeak][0]->AddEvent(time,m_buffer[pos+0x6]); //correct
sess->eventlist[CPAP_LeakTotal][0]->AddEvent(time,m_buffer[pos+0x7]); // "Average Leak"
sess->eventlist[CPAP_MaxLeak][0]->AddEvent(time,m_buffer[pos+0x6]); // "Max Leak"
sess->eventlist[CPAP_RespRate][0]->AddEvent(time,m_buffer[pos+0xa]); // 0x0a is correct
sess->eventlist[CPAP_Te][0]->AddEvent(time,m_buffer[pos+0xf]);
int rr=m_buffer[pos+0xa];
sess->eventlist[CPAP_RespRate][0]->AddEvent(time,rr); // Respiratory Rate
sess->eventlist[CPAP_Te][0]->AddEvent(time,m_buffer[pos+0xf]); //
sess->eventlist[CPAP_Ti][0]->AddEvent(time,m_buffer[pos+0xc]);
sess->eventlist[CPAP_Snore][0]->AddEvent(time,m_buffer[pos+0x4]); //4/5??
@ -269,30 +270,39 @@ int IntellipapLoader::Open(QString & path,Profile *profile)
if (!sess->eventlist.contains(CPAP_ExP)) {
sess->AddEventList(CPAP_ExP,EVL_Event);
}
sess->eventlist[CPAP_ExP][0]->AddEvent(time,m_buffer[pos+0x5]);
for (int q=0;q<m_buffer[pos+0x5];q++)
sess->eventlist[CPAP_ExP][0]->AddEvent(time,m_buffer[pos+0x5]);
}
if (m_buffer[pos+0x10]>0) {
if (!sess->eventlist.contains(CPAP_Obstructive)) {
sess->AddEventList(CPAP_Obstructive,EVL_Event);
}
sess->eventlist[CPAP_Obstructive][0]->AddEvent(time,m_buffer[pos+0x10]);
for (int q=0;q<m_buffer[pos+0x10];q++)
sess->eventlist[CPAP_Obstructive][0]->AddEvent(time,m_buffer[pos+0x10]);
}
if (m_buffer[pos+0x11]>0) {
if (!sess->eventlist.contains(CPAP_Hypopnea)) {
sess->AddEventList(CPAP_Hypopnea,EVL_Event);
}
//for (int i=0;i<m_buffer[pos+0x11];i++)
sess->eventlist[CPAP_Hypopnea][0]->AddEvent(time,m_buffer[pos+0x11]);
for (int q=0;q<m_buffer[pos+0x11];q++)
sess->eventlist[CPAP_Hypopnea][0]->AddEvent(time,m_buffer[pos+0x11]);
}
if (m_buffer[pos+0x12]>0) { // NRI // is this == to RERA?? CA??
if (!sess->eventlist.contains(CPAP_NRI)) {
sess->AddEventList(CPAP_NRI,EVL_Event);
}
sess->eventlist[CPAP_NRI][0]->AddEvent(time,m_buffer[pos+0x12]);
for (int q=0;q<m_buffer[pos+0x12];q++)
sess->eventlist[CPAP_NRI][0]->AddEvent(time,m_buffer[pos+0x12]);
}
quint16 tv=(m_buffer[pos+0x8] << 8) | m_buffer[pos+0x9]; // correct
sess->eventlist[CPAP_TidalVolume][0]->AddEvent(time,tv);
EventDataType mv=tv*rr; // MinuteVent=TidalVolume * Respiratory Rate
sess->eventlist[CPAP_MinuteVent][0]->AddEvent(time,mv/1000.0);
break;
}

View File

@ -18,7 +18,7 @@
//********************************************************************************************
// Please INCREMENT the following value when making changes to this loaders implementation.
//
const int intellipap_data_version=0;
const int intellipap_data_version=1;
//
//********************************************************************************************

View File

@ -567,7 +567,7 @@ bool PRS1Loader::Parse002(Session *session,unsigned char *buffer,int size,qint64
/*ChannelID Codes[]={
PRS1_Unknown00, PRS1_Unknown01, CPAP_Pressure, CPAP_EPAP, CPAP_PressurePulse, CPAP_RERA, CPAP_Obstructive, CPAP_ClearAirway,
PRS1_Unknown08, PRS1_Unknown09, CPAP_Hypopnea, PRS1_Unknown0B, CPAP_FlowLimit, CPAP_VSnore, PRS1_Unknown0E, CPAP_CSR, PRS1_Unknown10,
CPAP_Leak, PRS1_Unknown12
CPAP_LeakTotal, PRS1_Unknown12
};
int ncodes=sizeof(Codes)/sizeof(ChannelID); */
@ -698,7 +698,7 @@ bool PRS1Loader::Parse002(Session *session,unsigned char *buffer,int size,qint64
data[0]=buffer[pos++];
data[1]=buffer[pos++];
if (!Code[14]) {
if (!(Code[14]=session->AddEventList(CPAP_Leak,EVL_Event))) return false;
if (!(Code[14]=session->AddEventList(CPAP_LeakTotal,EVL_Event))) return false;
if (!(Code[15]=session->AddEventList(CPAP_Snore,EVL_Event))) return false;
}
Code[14]->AddEvent(t,data[0]);
@ -773,7 +773,7 @@ bool PRS1Loader::Parse002ASV(Session *session,unsigned char *buffer,int size,qin
PRS1_00, PRS1_01, CPAP_Pressure, CPAP_EPAP, CPAP_PressurePulse, CPAP_Obstructive,
CPAP_ClearAirway, CPAP_Hypopnea, PRS1_08, CPAP_FlowLimit, PRS1_0A, CPAP_CSR,
PRS1_0C, CPAP_VSnore, PRS1_0E, PRS1_0F, PRS1_10,
CPAP_Leak, PRS1_12
CPAP_LeakTotal, PRS1_12
};
int ncodes=sizeof(Codes)/sizeof(QString);
@ -929,7 +929,7 @@ bool PRS1Loader::Parse002ASV(Session *session,unsigned char *buffer,int size,qin
if (!(Code[12]=session->AddEventList(CPAP_IPAP,EVL_Event,0.1))) return false;
if (!(Code[13]=session->AddEventList(CPAP_IPAPLo,EVL_Event,0.1))) return false;
if (!(Code[14]=session->AddEventList(CPAP_IPAPHi,EVL_Event,0.1))) return false;
if (!(Code[15]=session->AddEventList(CPAP_Leak,EVL_Event))) return false;
if (!(Code[15]=session->AddEventList(CPAP_LeakTotal,EVL_Event))) return false;
if (!(Code[16]=session->AddEventList(CPAP_RespRate,EVL_Event))) return false;
if (!(Code[17]=session->AddEventList(CPAP_PTB,EVL_Event))) return false;

View File

@ -21,7 +21,7 @@ License: GPL
//********************************************************************************************
// Please INCREMENT the following value when making changes to this loaders implementation.
//
const int prs1_data_version=6;
const int prs1_data_version=7;
//
//********************************************************************************************

View File

@ -90,6 +90,8 @@ const QString CPAP_RespRate="RespRate";
const QString CPAP_TidalVolume="TidalVolume";
const QString CPAP_PTB="PTB";
const QString CPAP_Leak="Leak";
const QString CPAP_LeakMedian="LeakMedian";
const QString CPAP_LeakTotal="LeakTotal";
const QString CPAP_MaxLeak="MaxLeak";
const QString CPAP_FLG="FLG";
const QString CPAP_IE="IE";

View File

@ -413,6 +413,8 @@ void Session::UpdateSummaries()
ahi.calculate(this);
calc.calculate(this);
calcLeaks(this);
ChannelID id;
QHash<ChannelID,QVector<EventList *> >::iterator c;
for (c=eventlist.begin();c!=eventlist.end();c++) {

View File

@ -182,16 +182,17 @@ Daily::Daily(QWidget *parent,gGraphView * shared, MainWindow *mw)
bool square=PROFILE["SquareWavePlots"].toBool();
PRD->AddLayer(AddCPAP(new gLineChart(CPAP_Pressure,QColor("dark green"),square)));
PRD->AddLayer(AddCPAP(new gLineChart(CPAP_EPAP,Qt::blue,square)));
PRD->AddLayer(AddCPAP(new gLineChart(CPAP_IPAPLo,Qt::red,square)));
PRD->AddLayer(AddCPAP(new gLineChart(CPAP_IPAP,Qt::yellow,square)));
PRD->AddLayer(AddCPAP(new gLineChart(CPAP_IPAPHi,Qt::red,square)));
PRD->AddLayer(AddCPAP(new gLineChart(CPAP_Pressure,QColor("dark green"),square)));
AHI->AddLayer(AddCPAP(new gLineChart(CPAP_AHI,QColor("light green"),square)));
//AHI->AddLayer(AddCPAP(new AHIChart(QColor("#37a24b"))));
LEAK->AddLayer(AddCPAP(new gLineChart(CPAP_Leak,Qt::darkYellow,square)));
LEAK->AddLayer(AddCPAP(new gLineChart(CPAP_LeakTotal,Qt::yellow,square)));
LEAK->AddLayer(AddCPAP(new gLineChart(CPAP_Leak,Qt::darkMagenta,square)));
LEAK->AddLayer(AddCPAP(new gLineChart(CPAP_MaxLeak,Qt::darkRed,square)));
SNORE->AddLayer(AddCPAP(new gLineChart(CPAP_Snore,Qt::darkGray,true)));
@ -607,10 +608,10 @@ void Daily::Load(QDate date)
"</table></td>";
} else if (cpap->machine->GetClass()=="Intellipap") {
html+="<td colspan=2><table cellspacing=0 cellpadding=2 border=0 width='100%'>"
"<tr><td align='right' bgcolor='#ffff80'><b><a href='event=NRI'>"+tr("NRI")+"</a></b></td><td width=20% bgcolor='#ffff80'>"+QString().sprintf("%.2f",nri)+"</td></tr>\n"
"<tr><td align='right' bgcolor='#404040'><b><font color='white'><a href='event=Leak'>"+tr("Leak Idx")+"</a></font></b></td><td bgcolor='#404040'><font color='white'>"+a.sprintf("%.2f",lki)+"</font></td></tr>\n"
"<tr><td align='right' bgcolor='#ff4040'><b><a href='event=VSnore'>"+tr("Vibratory Snore")+"</a></b></td><td bgcolor='#ff4040'>"+QString().sprintf("%.2f",vsi)+"</td></tr>\n"
"<tr><td align='right' bgcolor='#80ff80'><b><a href='event=ExP'>"+tr("Exhalation Puff")+"</a></b></td><td bgcolor='#80ff80'>"+QString().sprintf("%.2f",exp)+"%</td></tr>\n"
"<tr><td align='right' bgcolor='#ffff80'><b>&nbsp;<a href='event=NRI'>"+tr("NRI")+"</a></b></td><td width=20% bgcolor='#ffff80'>"+QString().sprintf("%.2f",nri)+"</td></tr>\n"
"<tr><td align='right' bgcolor='#404040'><b>&nbsp;<font color='white'><a href='event=Leak'>"+tr("Leak Idx")+"</a></font></b></td><td bgcolor='#404040'><font color='white'>"+a.sprintf("%.2f",lki)+"</font></td></tr>\n"
"<tr><td align='right' bgcolor='#ff4040'><b>&nbsp;<a href='event=VSnore'>"+tr("V.Snore")+"</a></b></td><td bgcolor='#ff4040'>"+QString().sprintf("%.2f",vsi)+"</td></tr>\n"
"<tr><td align='right' bgcolor='#80ff80'><b>&nbsp;<a href='event=ExP'>"+tr("Exh.&nbsp;Puff")+"</a></b></td><td bgcolor='#80ff80'>"+QString().sprintf("%.2f",exp)+"</td></tr>\n"
"</table></td>";
}
@ -650,12 +651,12 @@ void Daily::Load(QDate date)
CPAP_TidalVolume, OXI_Pulse, OXI_SPO2
};
int numchans=sizeof(chans)/sizeof(ChannelID);
int suboffset;
int suboffset=0;
for (int i=0;i<numchans;i++) {
ChannelID code=chans[i];
if (cpap && cpap->channelHasData(code)) {
if (code==CPAP_Leak) suboffset=PROFILE["IntentionalLeak"].toDouble(); else suboffset=0;
//if (code==CPAP_LeakTotal) suboffset=PROFILE["IntentionalLeak"].toDouble(); else suboffset=0;
html+="<tr><td align=left>"+schema::channel[code].label();
html+="</td><td>"+a.sprintf("%.2f",cpap->min(code)-suboffset);
html+="</td><td>"+a.sprintf("%.2f",cpap->wavg(code)-suboffset);