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);
|
Waveform *w=(*l);
|
||||||
double st=w->start().toMSecsSinceEpoch()/86400000.0;
|
double st=w->start().toMSecsSinceEpoch()/86400000.0;
|
||||||
double rate=(w->duration()/w->samples())/86400.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++) {
|
for (int i=0;i<w->samples();i++) {
|
||||||
QPointD r(st,(*w)[i]);
|
QPointD r(st,(*w)[i]);
|
||||||
st+=rate;
|
st+=rate;
|
||||||
@ -377,6 +377,8 @@ void HistoryData::Reload(Day *day)
|
|||||||
double y,lasty=0;
|
double y,lasty=0;
|
||||||
min_y=max_y=0;
|
min_y=max_y=0;
|
||||||
min_x=max_x=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++) {
|
for (double x=floor(real_min_x);x<=ceil(real_max_x);x++) {
|
||||||
date=QDateTime::fromMSecsSinceEpoch(x*86400000.0L);
|
date=QDateTime::fromMSecsSinceEpoch(x*86400000.0L);
|
||||||
date.setTime(QTime(0,0,0));
|
date.setTime(QTime(0,0,0));
|
||||||
|
@ -26,11 +26,19 @@ EDFParser::~EDFParser()
|
|||||||
vector<EDFSignal *>::iterator s;
|
vector<EDFSignal *>::iterator s;
|
||||||
for (s=edfsignals.begin();s!=edfsignals.end();s++) {
|
for (s=edfsignals.begin();s!=edfsignals.end();s++) {
|
||||||
if ((*s)->data) delete [] (*s)->data;
|
if ((*s)->data) delete [] (*s)->data;
|
||||||
if ((*s)->adata) delete [] (*s)->adata;
|
|
||||||
delete *s;
|
delete *s;
|
||||||
}
|
}
|
||||||
if (buffer) delete [] buffer;
|
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 EDFParser::Read(int si)
|
||||||
{
|
{
|
||||||
QString str;
|
QString str;
|
||||||
@ -59,7 +67,19 @@ bool EDFParser::Parse()
|
|||||||
}
|
}
|
||||||
temp=Read(8);
|
temp=Read(8);
|
||||||
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);
|
num_header_bytes=Read(8).toLong(&ok);
|
||||||
if (!ok)
|
if (!ok)
|
||||||
return false;
|
return false;
|
||||||
@ -80,7 +100,6 @@ bool EDFParser::Parse()
|
|||||||
EDFSignal *signal=new EDFSignal;
|
EDFSignal *signal=new EDFSignal;
|
||||||
edfsignals.push_back(signal);
|
edfsignals.push_back(signal);
|
||||||
signal->data=NULL;
|
signal->data=NULL;
|
||||||
signal->adata=NULL;
|
|
||||||
edfsignals[i]->label=Read(16);
|
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]->nr=Read(8).toLong(&ok);
|
||||||
for (int i=0;i<num_signals;i++) edfsignals[i]->reserved=Read(32);
|
for (int i=0;i<num_signals;i++) edfsignals[i]->reserved=Read(32);
|
||||||
|
|
||||||
|
// allocate the buffers
|
||||||
for (int i=0;i<num_signals;i++) {
|
for (int i=0;i<num_signals;i++) {
|
||||||
//qDebug//cout << "Reading signal " << signals[i]->label << endl;
|
//qDebug//cout << "Reading signal " << signals[i]->label << endl;
|
||||||
if (edfsignals[i]->label!="EDF Annotations") {
|
EDFSignal & sig=*edfsignals[i];
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
} else { // Annotation data..
|
long recs=sig.nr * num_data_records;
|
||||||
edfsignals[i]->adata=(char *) new char [edfsignals[i]->nr*2];
|
if (num_data_records<0)
|
||||||
//cout << signals[i]->nr << endl;;
|
return false;
|
||||||
for (int j=0;j<edfsignals[i]->nr*2;j++)
|
sig.data=new qint16 [recs];
|
||||||
edfsignals[i]->adata[j]=buffer[pos++];
|
sig.pos=0;
|
||||||
}
|
|
||||||
//cout << "Read Signal" << endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
bool EDFParser::Open(QString name)
|
bool EDFParser::Open(QString name)
|
||||||
@ -124,10 +144,12 @@ bool EDFParser::Open(QString name)
|
|||||||
if (!f.isReadable()) return false;
|
if (!f.isReadable()) return false;
|
||||||
filename=name;
|
filename=name;
|
||||||
filesize=f.size();
|
filesize=f.size();
|
||||||
|
qDebug(("Opening "+name).toLatin1());
|
||||||
buffer=new char [filesize];
|
buffer=new char [filesize];
|
||||||
f.read(buffer,filesize);
|
f.read(buffer,filesize);
|
||||||
f.close();
|
f.close();
|
||||||
pos=0;
|
pos=0;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
ResmedLoader::ResmedLoader()
|
ResmedLoader::ResmedLoader()
|
||||||
@ -187,55 +209,60 @@ bool ResmedLoader::Open(QString & path,Profile *profile)
|
|||||||
dir.setSorting(QDir::Name);
|
dir.setSorting(QDir::Name);
|
||||||
QFileInfoList flist=dir.entryInfoList();
|
QFileInfoList flist=dir.entryInfoList();
|
||||||
map<SessionID,vector<QString> > sessfiles;
|
map<SessionID,vector<QString> > sessfiles;
|
||||||
|
|
||||||
QString ext,rest,datestr,s,codestr;
|
QString ext,rest,datestr,s,codestr;
|
||||||
SessionID sessionid;
|
SessionID sessionid;
|
||||||
QDateTime date;
|
QDateTime date;
|
||||||
map<SessionID,Session *> sessions;
|
|
||||||
Session *sess;
|
|
||||||
Machine *m;
|
|
||||||
|
|
||||||
for (int i=0;i<flist.size();i++) {
|
for (int i=0;i<flist.size();i++) {
|
||||||
QFileInfo fi=flist.at(i);
|
QFileInfo fi=flist.at(i);
|
||||||
QString filename=fi.fileName();
|
QString filename=fi.fileName();
|
||||||
ext=filename.section(".",1).toLower();
|
ext=filename.section(".",1).toLower();
|
||||||
if (ext!="edf") continue;
|
if (ext!="edf") continue;
|
||||||
|
|
||||||
rest=filename.section(".",0,0);
|
rest=filename.section(".",0,0);
|
||||||
datestr=filename.section("_",0,1);
|
datestr=filename.section("_",0,1);
|
||||||
date=QDateTime::fromString(datestr,"yyyyMMdd_HHmmss");
|
date=QDateTime::fromString(datestr,"yyyyMMdd_HHmmss");
|
||||||
sessionid=date.toTime_t();
|
sessionid=date.toTime_t();
|
||||||
|
|
||||||
s.sprintf("%li",sessionid);
|
sessfiles[sessionid].push_back(fi.canonicalFilePath());
|
||||||
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;
|
|
||||||
|
|
||||||
Machine *m=CreateMachine(edf.serialnumber,profile);
|
Machine *m=NULL;
|
||||||
|
|
||||||
if (sessions.find(sessionid)==sessions.end()) {
|
Session *sess=NULL;
|
||||||
sessions[sessionid]=new Session(m,sessionid);
|
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];
|
if (!edf.Parse())
|
||||||
sess->SetChanged(true);
|
continue;
|
||||||
switch(code) {
|
|
||||||
case 0: LoadEVE(m,sess,edf);
|
if (first) { // First EDF file parsed, check if this data set is already imported
|
||||||
break;
|
m=CreateMachine(edf.serialnumber,profile);
|
||||||
case 1: LoadPLD(m,sess,edf);
|
if (m->SessionExists(sessionid)) {
|
||||||
break;
|
done=true;
|
||||||
case 2: LoadBRP(m,sess,edf);
|
break;
|
||||||
break;
|
}
|
||||||
case 3: LoadSAD(m,sess,edf);
|
sess=new Session(m,sessionid);
|
||||||
break;
|
}
|
||||||
|
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;
|
return 0;
|
||||||
@ -244,14 +271,34 @@ bool ResmedLoader::LoadEVE(Machine *mach,Session *sess,EDFParser &edf)
|
|||||||
{
|
{
|
||||||
QString t;
|
QString t;
|
||||||
for (int s=0;s<edf.GetNumSignals();s++) {
|
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());
|
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)
|
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)
|
bool ResmedLoader::LoadSAD(Machine *mach,Session *sess,EDFParser &edf)
|
||||||
{
|
{
|
||||||
|
@ -39,7 +39,7 @@ public:
|
|||||||
long nr;
|
long nr;
|
||||||
QString reserved;
|
QString reserved;
|
||||||
qint16 * data;
|
qint16 * data;
|
||||||
char *adata;
|
int pos;
|
||||||
};
|
};
|
||||||
|
|
||||||
class EDFParser
|
class EDFParser
|
||||||
@ -50,12 +50,13 @@ public:
|
|||||||
bool Open(QString name);
|
bool Open(QString name);
|
||||||
|
|
||||||
QString Read(int si);
|
QString Read(int si);
|
||||||
|
qint16 Read16();
|
||||||
|
|
||||||
vector<EDFSignal *> edfsignals;
|
vector<EDFSignal *> edfsignals;
|
||||||
|
|
||||||
long GetNumSignals() { return num_signals; };
|
long GetNumSignals() { return num_signals; };
|
||||||
long GetNumDataRecords() { return num_data_records; };
|
long GetNumDataRecords() { return num_data_records; };
|
||||||
long GetDuration() { return dur_data_record; };
|
double GetDuration() { return dur_data_record; };
|
||||||
QString GetPatient() { return patientident; };
|
QString GetPatient() { return patientident; };
|
||||||
bool Parse();
|
bool Parse();
|
||||||
char *buffer;
|
char *buffer;
|
||||||
|
@ -32,7 +32,7 @@ enum MachineCode//:qint16
|
|||||||
{
|
{
|
||||||
// General Event Codes
|
// General Event Codes
|
||||||
CPAP_Obstructive=0, CPAP_Hypopnea, CPAP_ClearAirway, CPAP_RERA, CPAP_VSnore, CPAP_FlowLimit,
|
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,
|
CPAP_BreathsPerMinute,
|
||||||
|
|
||||||
// General CPAP Summary Information
|
// General CPAP Summary Information
|
||||||
|
16
daily.cpp
16
daily.cpp
@ -114,13 +114,13 @@ Daily::Daily(QWidget *parent,QGLContext *context) :
|
|||||||
LEAK->setMinimumHeight(150);
|
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));
|
AddGraph(FRW=new gGraphWindow(gSplitter,tr("Flow Rate"),SF));
|
||||||
//FRW->AddLayer(new gFooBar());
|
//FRW->AddLayer(new gFooBar());
|
||||||
FRW->AddLayer(new gYAxis());
|
FRW->AddLayer(new gYAxis());
|
||||||
FRW->AddLayer(new gXAxis());
|
FRW->AddLayer(new gXAxis());
|
||||||
FRW->AddLayer(new gLineOverlayBar(flags[0],QColor("light green"),"CSR"));
|
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);
|
g->ReportEmpty(true);
|
||||||
|
|
||||||
|
|
||||||
@ -203,12 +203,12 @@ Daily::Daily(QWidget *parent,QGLContext *context) :
|
|||||||
l->AddName(tr("FL"));
|
l->AddName(tr("FL"));
|
||||||
l->AddName(tr("CSR"));
|
l->AddName(tr("CSR"));
|
||||||
l->color.clear();
|
l->color.clear();
|
||||||
l->color.push_back(QColor("blue"));
|
l->color.push_back(QColor(0x40,0x40,0xff,0xff)); // blue
|
||||||
l->color.push_back(QColor(0x40,0xaf,0xbf,0xff)); //#40afbf
|
l->color.push_back(QColor(0x40,0xaf,0xbf,0xff)); // aqua
|
||||||
l->color.push_back(QColor(0xb2,0x54,0xcd,0xff)); //b254cd; //wxPURPLE);
|
l->color.push_back(QColor(0xb2,0x54,0xcd,0xff)); // purple
|
||||||
l->color.push_back(QColor("yellow"));
|
l->color.push_back(QColor(0xff,0xff,0x80,0xff)); // yellow
|
||||||
l->color.push_back(QColor(0x40,0x40,0x40,255));
|
l->color.push_back(QColor(0x40,0x40,0x40,0xff)); // dark grey
|
||||||
l->color.push_back(QColor(0x60,0xff,0x60,0xff)); //80ff80
|
l->color.push_back(QColor(0x60,0xff,0x60,0xff)); // green
|
||||||
G_AHI->AddLayer(l);
|
G_AHI->AddLayer(l);
|
||||||
G_AHI->SetGradientBackground(false);
|
G_AHI->SetGradientBackground(false);
|
||||||
//G_AHI->setMaximumSize(2000,30);
|
//G_AHI->setMaximumSize(2000,30);
|
||||||
|
Loading…
Reference in New Issue
Block a user