mirror of
https://gitlab.com/pholy/OSCAR-code.git
synced 2025-04-05 10:40:42 +00:00
ResMed S9 Flow Rate Data
This commit is contained in:
parent
c6c7cda0fc
commit
b88ac87548
@ -43,7 +43,7 @@ void WaveData::Reload(Day *day)
|
||||
Waveform *w=(*l);
|
||||
double st=w->start().toMSecsSinceEpoch()/86400000.0;
|
||||
double rate=(w->duration()/w->samples())/86400.0;
|
||||
//qDebug("Waveform Chunk contains %i samples",w->samples());
|
||||
qDebug("Waveform Chunk contains %i samples",w->samples());
|
||||
for (int i=0;i<w->samples();i++) {
|
||||
QPointD r(st,(*w)[i]);
|
||||
st+=rate;
|
||||
@ -377,6 +377,8 @@ void HistoryData::Reload(Day *day)
|
||||
double y,lasty=0;
|
||||
min_y=max_y=0;
|
||||
min_x=max_x=0;
|
||||
if (real_min_x<0) return;
|
||||
if (real_max_x<0) return;
|
||||
for (double x=floor(real_min_x);x<=ceil(real_max_x);x++) {
|
||||
date=QDateTime::fromMSecsSinceEpoch(x*86400000.0L);
|
||||
date.setTime(QTime(0,0,0));
|
||||
|
@ -26,11 +26,19 @@ EDFParser::~EDFParser()
|
||||
vector<EDFSignal *>::iterator s;
|
||||
for (s=edfsignals.begin();s!=edfsignals.end();s++) {
|
||||
if ((*s)->data) delete [] (*s)->data;
|
||||
if ((*s)->adata) delete [] (*s)->adata;
|
||||
delete *s;
|
||||
}
|
||||
if (buffer) delete [] buffer;
|
||||
}
|
||||
qint16 EDFParser::Read16()
|
||||
{
|
||||
unsigned char *buf=(unsigned char *)buffer;
|
||||
if (pos>=filesize) return 0;
|
||||
qint16 res=*(qint16 *)&buf[pos];
|
||||
//qint16 res=(buf[pos] ^128)<< 8 | buf[pos+1] ^ 128;
|
||||
pos+=2;
|
||||
return res;
|
||||
}
|
||||
QString EDFParser::Read(int si)
|
||||
{
|
||||
QString str;
|
||||
@ -59,7 +67,19 @@ bool EDFParser::Parse()
|
||||
}
|
||||
temp=Read(8);
|
||||
temp+=" "+Read(8);
|
||||
startdate.fromString(temp,"dd.MM.yy HH.mm.ss");
|
||||
startdate=QDateTime::fromString(temp,"dd.MM.yy HH.mm.ss");
|
||||
QDate d2=startdate.date();
|
||||
if (d2.year()<2000) {
|
||||
d2.setYMD(d2.year()+100,d2.month(),d2.day());
|
||||
startdate.setDate(d2);
|
||||
}
|
||||
if (!startdate.isValid()) {
|
||||
qDebug(("Invalid date time retreieved parsing EDF File"+filename).toLatin1());
|
||||
return false;
|
||||
}
|
||||
|
||||
qDebug(startdate.toString("yyyy-MM-dd HH:mm:ss").toLatin1());
|
||||
|
||||
num_header_bytes=Read(8).toLong(&ok);
|
||||
if (!ok)
|
||||
return false;
|
||||
@ -80,7 +100,6 @@ bool EDFParser::Parse()
|
||||
EDFSignal *signal=new EDFSignal;
|
||||
edfsignals.push_back(signal);
|
||||
signal->data=NULL;
|
||||
signal->adata=NULL;
|
||||
edfsignals[i]->label=Read(16);
|
||||
}
|
||||
|
||||
@ -94,27 +113,28 @@ bool EDFParser::Parse()
|
||||
for (int i=0;i<num_signals;i++) edfsignals[i]->nr=Read(8).toLong(&ok);
|
||||
for (int i=0;i<num_signals;i++) edfsignals[i]->reserved=Read(32);
|
||||
|
||||
// allocate the buffers
|
||||
for (int i=0;i<num_signals;i++) {
|
||||
//qDebug//cout << "Reading signal " << signals[i]->label << endl;
|
||||
if (edfsignals[i]->label!="EDF Annotations") {
|
||||
// Waveforms
|
||||
edfsignals[i]->data=new qint16 [edfsignals[i]->nr];
|
||||
for (int j=0;j<edfsignals[i]->nr;j++){
|
||||
long t;
|
||||
t=Read(2).toLong(&ok);
|
||||
if (!ok)
|
||||
return false;
|
||||
edfsignals[i]->data[j]=t & 0xffff;
|
||||
}
|
||||
EDFSignal & sig=*edfsignals[i];
|
||||
|
||||
} else { // Annotation data..
|
||||
edfsignals[i]->adata=(char *) new char [edfsignals[i]->nr*2];
|
||||
//cout << signals[i]->nr << endl;;
|
||||
for (int j=0;j<edfsignals[i]->nr*2;j++)
|
||||
edfsignals[i]->adata[j]=buffer[pos++];
|
||||
}
|
||||
//cout << "Read Signal" << endl;
|
||||
long recs=sig.nr * num_data_records;
|
||||
if (num_data_records<0)
|
||||
return false;
|
||||
sig.data=new qint16 [recs];
|
||||
sig.pos=0;
|
||||
}
|
||||
|
||||
for (int x=0;x<num_data_records;x++) {
|
||||
for (int i=0;i<num_signals;i++) {
|
||||
EDFSignal & sig=*edfsignals[i];
|
||||
for (int j=0;j<sig.nr;j++) {
|
||||
qint16 t=Read16();
|
||||
sig.data[sig.pos++]=t;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
bool EDFParser::Open(QString name)
|
||||
@ -124,10 +144,12 @@ bool EDFParser::Open(QString name)
|
||||
if (!f.isReadable()) return false;
|
||||
filename=name;
|
||||
filesize=f.size();
|
||||
qDebug(("Opening "+name).toLatin1());
|
||||
buffer=new char [filesize];
|
||||
f.read(buffer,filesize);
|
||||
f.close();
|
||||
pos=0;
|
||||
return true;
|
||||
}
|
||||
|
||||
ResmedLoader::ResmedLoader()
|
||||
@ -187,55 +209,60 @@ bool ResmedLoader::Open(QString & path,Profile *profile)
|
||||
dir.setSorting(QDir::Name);
|
||||
QFileInfoList flist=dir.entryInfoList();
|
||||
map<SessionID,vector<QString> > sessfiles;
|
||||
|
||||
QString ext,rest,datestr,s,codestr;
|
||||
SessionID sessionid;
|
||||
QDateTime date;
|
||||
map<SessionID,Session *> sessions;
|
||||
Session *sess;
|
||||
Machine *m;
|
||||
|
||||
for (int i=0;i<flist.size();i++) {
|
||||
QFileInfo fi=flist.at(i);
|
||||
QString filename=fi.fileName();
|
||||
ext=filename.section(".",1).toLower();
|
||||
if (ext!="edf") continue;
|
||||
|
||||
rest=filename.section(".",0,0);
|
||||
datestr=filename.section("_",0,1);
|
||||
date=QDateTime::fromString(datestr,"yyyyMMdd_HHmmss");
|
||||
sessionid=date.toTime_t();
|
||||
|
||||
s.sprintf("%li",sessionid);
|
||||
codestr=rest.section("_",2).toUpper();
|
||||
int code;
|
||||
if (codestr=="EVE") code=0;
|
||||
else if (codestr=="PLD") code=1;
|
||||
else if (codestr=="BRP") code=2;
|
||||
else if (codestr=="SAD") code=3;
|
||||
else {
|
||||
qDebug(("Unknown file EDF type"+filename).toLatin1());
|
||||
continue;
|
||||
}
|
||||
qDebug(("Parsing "+filename).toLatin1());
|
||||
EDFParser edf(fi.canonicalFilePath());
|
||||
if (!edf.Parse()) continue;
|
||||
sessfiles[sessionid].push_back(fi.canonicalFilePath());
|
||||
}
|
||||
|
||||
Machine *m=CreateMachine(edf.serialnumber,profile);
|
||||
Machine *m=NULL;
|
||||
|
||||
if (sessions.find(sessionid)==sessions.end()) {
|
||||
sessions[sessionid]=new Session(m,sessionid);
|
||||
}
|
||||
Session *sess=NULL;
|
||||
for (map<SessionID,vector<QString> >::iterator si=sessfiles.begin();si!=sessfiles.end();si++) {
|
||||
sessionid=si->first;
|
||||
qDebug("Parsing Session %li",sessionid);
|
||||
bool done=false;
|
||||
bool first=true;
|
||||
for (int i=0;i<si->second.size();i++) {
|
||||
QString fn=si->second[i].section("_",-1).toLower();
|
||||
EDFParser edf(si->second[i]);
|
||||
qDebug("Parsing File %i %i",i,edf.filesize);
|
||||
|
||||
sess=sessions[sessionid];
|
||||
sess->SetChanged(true);
|
||||
switch(code) {
|
||||
case 0: LoadEVE(m,sess,edf);
|
||||
break;
|
||||
case 1: LoadPLD(m,sess,edf);
|
||||
break;
|
||||
case 2: LoadBRP(m,sess,edf);
|
||||
break;
|
||||
case 3: LoadSAD(m,sess,edf);
|
||||
break;
|
||||
if (!edf.Parse())
|
||||
continue;
|
||||
|
||||
if (first) { // First EDF file parsed, check if this data set is already imported
|
||||
m=CreateMachine(edf.serialnumber,profile);
|
||||
if (m->SessionExists(sessionid)) {
|
||||
done=true;
|
||||
break;
|
||||
}
|
||||
sess=new Session(m,sessionid);
|
||||
}
|
||||
if (!done) {
|
||||
if (fn=="eve.edf") LoadEVE(m,sess,edf);
|
||||
else if (fn=="pld.edf") LoadPLD(m,sess,edf);
|
||||
else if (fn=="brp.edf") LoadBRP(m,sess,edf);
|
||||
else if (fn=="sad.edf") LoadSAD(m,sess,edf);
|
||||
}
|
||||
if (first) {
|
||||
sess->SetChanged(true);
|
||||
m->AddSession(sess,profile); // Adding earlier than I really like here..
|
||||
first=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@ -244,14 +271,34 @@ bool ResmedLoader::LoadEVE(Machine *mach,Session *sess,EDFParser &edf)
|
||||
{
|
||||
QString t;
|
||||
for (int s=0;s<edf.GetNumSignals();s++) {
|
||||
t.sprintf("%i",edf.edfsignals[s]->nr);
|
||||
long recs=edf.edfsignals[s]->nr*edf.GetNumDataRecords();
|
||||
double duration=edf.GetNumDataRecords()*edf.GetDuration();
|
||||
duration/=3600.0;
|
||||
t.sprintf("EVE: %li %.2f",recs,duration);
|
||||
qDebug((edf.edfsignals[s]->label+" "+t).toLatin1());
|
||||
if (edf.edfsignals[s]->adata) {
|
||||
}
|
||||
char * data=(char *)edf.edfsignals[s]->data;
|
||||
}
|
||||
}
|
||||
bool ResmedLoader::LoadBRP(Machine *mach,Session *sess,EDFParser &edf)
|
||||
{
|
||||
QString t;
|
||||
for (int s=0;s<edf.GetNumSignals();s++) {
|
||||
long recs=edf.edfsignals[s]->nr*edf.GetNumDataRecords();
|
||||
double duration=edf.GetNumDataRecords()*edf.GetDuration();
|
||||
MachineCode code;
|
||||
if (edf.edfsignals[s]->label=="Flow") code=CPAP_FlowRate;
|
||||
else if (edf.edfsignals[s]->label=="Mask Pres") code=CPAP_MaskPressure;
|
||||
sess->set_first(edf.startdate);
|
||||
QDateTime e=edf.startdate.addSecs(duration);
|
||||
sess->set_last(e);
|
||||
//duration/=3600.0;
|
||||
sess->set_hours(duration/3600.0);
|
||||
Waveform *w=new Waveform(edf.startdate,code,edf.edfsignals[s]->data,recs,duration,edf.edfsignals[s]->digital_minimum,edf.edfsignals[s]->digital_maximum);
|
||||
edf.edfsignals[s]->data=NULL; // so it doesn't get deleted when edf gets trashed.
|
||||
sess->AddWaveform(w);
|
||||
t.sprintf("BRP: %li %.2f",recs,duration);
|
||||
qDebug((edf.edfsignals[s]->label+" "+t).toLatin1());
|
||||
}
|
||||
}
|
||||
bool ResmedLoader::LoadSAD(Machine *mach,Session *sess,EDFParser &edf)
|
||||
{
|
||||
|
@ -39,7 +39,7 @@ public:
|
||||
long nr;
|
||||
QString reserved;
|
||||
qint16 * data;
|
||||
char *adata;
|
||||
int pos;
|
||||
};
|
||||
|
||||
class EDFParser
|
||||
@ -50,12 +50,13 @@ public:
|
||||
bool Open(QString name);
|
||||
|
||||
QString Read(int si);
|
||||
qint16 Read16();
|
||||
|
||||
vector<EDFSignal *> edfsignals;
|
||||
|
||||
long GetNumSignals() { return num_signals; };
|
||||
long GetNumDataRecords() { return num_data_records; };
|
||||
long GetDuration() { return dur_data_record; };
|
||||
double GetDuration() { return dur_data_record; };
|
||||
QString GetPatient() { return patientident; };
|
||||
bool Parse();
|
||||
char *buffer;
|
||||
|
@ -32,7 +32,7 @@ enum MachineCode//:qint16
|
||||
{
|
||||
// General Event Codes
|
||||
CPAP_Obstructive=0, CPAP_Hypopnea, CPAP_ClearAirway, CPAP_RERA, CPAP_VSnore, CPAP_FlowLimit,
|
||||
CPAP_Leak, CPAP_Pressure, CPAP_EAP, CPAP_IAP, CPAP_CSR, CPAP_FlowRate,
|
||||
CPAP_Leak, CPAP_Pressure, CPAP_EAP, CPAP_IAP, CPAP_CSR, CPAP_FlowRate, CPAP_MaskPressure,
|
||||
CPAP_BreathsPerMinute,
|
||||
|
||||
// General CPAP Summary Information
|
||||
|
16
daily.cpp
16
daily.cpp
@ -114,13 +114,13 @@ Daily::Daily(QWidget *parent,QGLContext *context) :
|
||||
LEAK->setMinimumHeight(150);
|
||||
|
||||
|
||||
AddCPAPData(frw=new WaveData(CPAP_FlowRate));
|
||||
AddCPAPData(frw=new WaveData(CPAP_FlowRate,700000)); // Holy crap resmed stuff is huge..
|
||||
AddGraph(FRW=new gGraphWindow(gSplitter,tr("Flow Rate"),SF));
|
||||
//FRW->AddLayer(new gFooBar());
|
||||
FRW->AddLayer(new gYAxis());
|
||||
FRW->AddLayer(new gXAxis());
|
||||
FRW->AddLayer(new gLineOverlayBar(flags[0],QColor("light green"),"CSR"));
|
||||
gLineChart *g=new gLineChart(frw,Qt::black,200000,true);
|
||||
gLineChart *g=new gLineChart(frw,Qt::black,700000,true);
|
||||
g->ReportEmpty(true);
|
||||
|
||||
|
||||
@ -203,12 +203,12 @@ Daily::Daily(QWidget *parent,QGLContext *context) :
|
||||
l->AddName(tr("FL"));
|
||||
l->AddName(tr("CSR"));
|
||||
l->color.clear();
|
||||
l->color.push_back(QColor("blue"));
|
||||
l->color.push_back(QColor(0x40,0xaf,0xbf,0xff)); //#40afbf
|
||||
l->color.push_back(QColor(0xb2,0x54,0xcd,0xff)); //b254cd; //wxPURPLE);
|
||||
l->color.push_back(QColor("yellow"));
|
||||
l->color.push_back(QColor(0x40,0x40,0x40,255));
|
||||
l->color.push_back(QColor(0x60,0xff,0x60,0xff)); //80ff80
|
||||
l->color.push_back(QColor(0x40,0x40,0xff,0xff)); // blue
|
||||
l->color.push_back(QColor(0x40,0xaf,0xbf,0xff)); // aqua
|
||||
l->color.push_back(QColor(0xb2,0x54,0xcd,0xff)); // purple
|
||||
l->color.push_back(QColor(0xff,0xff,0x80,0xff)); // yellow
|
||||
l->color.push_back(QColor(0x40,0x40,0x40,0xff)); // dark grey
|
||||
l->color.push_back(QColor(0x60,0xff,0x60,0xff)); // green
|
||||
G_AHI->AddLayer(l);
|
||||
G_AHI->SetGradientBackground(false);
|
||||
//G_AHI->setMaximumSize(2000,30);
|
||||
|
Loading…
Reference in New Issue
Block a user