Optimize waveform/leak/pressure processing calcs, FPIcon cleanup

This commit is contained in:
Mark Watkins 2014-05-16 03:56:53 +10:00
parent ae3fe507b1
commit f0356ee99c
3 changed files with 351 additions and 271 deletions

View File

@ -223,7 +223,7 @@ void FlowParser::openFlow(Session *session, EventList *flow)
EventStoreType *eptr = inraw + m_samples;
// Convert from store type to floats..
for (; inraw < eptr; inraw++) {
for (; inraw < eptr; ++inraw) {
*buf++ = EventDataType(*inraw) * m_gain;
}
@ -437,10 +437,19 @@ void FlowParser::calc(bool calcResp, bool calcTv, bool calcTi, bool calcTe, bool
qint32 timeval = 0; // Time relative to start
for (idx = 0; idx < nm; idx++) {
bs = breaths[idx].start;
bm = breaths[idx].middle;
be = breaths[idx].end;
BreathPeak * bpstr = breaths.data();
BreathPeak * bpend = bpstr + nm;
for (BreathPeak * bp = bpstr; bp != bpend; ++bp) {
bs = bp->start;
bm = bp->middle;
be = bp->end;
// for (idx = 0; idx < nm; idx++) {
// bs = breaths[idx].start;
// bm = breaths[idx].middle;
// be = breaths[idx].end;
// Calculate start, middle and end time of this breath
st = start + bs * m_rate;
@ -524,9 +533,13 @@ void FlowParser::calc(bool calcResp, bool calcTv, bool calcTi, bool calcTe, bool
//et2=et;
// Step back through last minute and count breaths
for (int i = idx; i >= 0; i--) {
st2 = start + double(breaths[i].start) * m_rate;
et2 = start + double(breaths[i].end) * m_rate;
BreathPeak *bpstr1 = bpstr-1;
for (BreathPeak *p = bp; p != bpstr1; --p) {
st2 = start + double(p->start) * m_rate;
et2 = start + double(p->end) * m_rate;
// for (int i = idx; i >= 0; i--) {
// st2 = start + double(breaths[i].start) * m_rate;
// et2 = start + double(breaths[i].end) * m_rate;
if (et2 < stmin) {
break;
@ -631,13 +644,21 @@ void FlowParser::flagEvents()
bool allowDuplicates = PROFILE.cpap->userEventDuplicates();
for (int i = 0; i < numbreaths; i++) {
mx = breaths[i].max;
mn = breaths[i].min;
br.push_back(qAbs(mx));
br.push_back(qAbs(mn));
BreathPeak *bpstr = breaths.data();
BreathPeak *bpend = bpstr + numbreaths;
for (BreathPeak *p = bpstr; p != bpend; ++p) {
br.push_back(qAbs(p->max));
br.push_back(qAbs(p->min));
}
// for (int i = 0; i < numbreaths; i++) {
// mx = breaths[i].max;
// mn = breaths[i].min;
// br.push_back(qAbs(mx));
// br.push_back(qAbs(mn));
// }
//EventList * uf2=m_session->AddEventList(CPAP_UserFlag2,EVL_Event);
//EventList * uf3=m_session->AddEventList(CPAP_UserFlag3,EVL_Event);
@ -651,13 +672,19 @@ void FlowParser::flagEvents()
int bs, bm, be, bs1, bm1, be1;
for (int i = 0; i < numbreaths; i++) {
bs = breaths[i].start;
bm = breaths[i].middle;
be = breaths[i].end;
for (BreathPeak *p = bpstr; p != bpend; ++p) {
bs = p->start;
bm = p->middle;
be = p->end;
mx = p->max;
mn = p->min;
// for (int i = 0; i < numbreaths; i++) {
// bs = breaths[i].start;
// bm = breaths[i].middle;
// be = breaths[i].end;
mx = breaths[i].max;
mn = breaths[i].min;
// mx = breaths[i].max;
// mn = breaths[i].min;
val = mx - mn;
// if (qAbs(mx) > cutoffval) {
@ -779,8 +806,8 @@ void calcRespRate(Session *session, FlowParser *flowparser)
}
QVector<EventList *> &list = session->eventlist[CPAP_RespRate];
for (int i = 0; i < list.size(); i++) {
int size = list.size();
for (int i = 0; i < size; ++i) {
delete list[i];
}
@ -788,7 +815,8 @@ void calcRespRate(Session *session, FlowParser *flowparser)
QVector<EventList *> &list2 = session->eventlist[CPAP_TidalVolume];
for (int i = 0; i < list2.size(); i++) {
size = list2.size();
for (int i = 0; i < size; ++i) {
delete list2[i];
}
@ -796,7 +824,8 @@ void calcRespRate(Session *session, FlowParser *flowparser)
QVector<EventList *> &list3 = session->eventlist[CPAP_MinuteVent];
for (int i = 0; i < list3.size(); i++) {
size = list3.size();
for (int i = 0; i < size; ++i) {
delete list3[i];
}
@ -813,8 +842,11 @@ void calcRespRate(Session *session, FlowParser *flowparser)
//flowparser->addFilter(FilterXPass,0.5);
EventList *flow;
for (int ws = 0; ws < session->eventlist[CPAP_FlowRate].size(); ws++) {
flow = session->eventlist[CPAP_FlowRate][ws];
QVector<EventList *> &EVL = session->eventlist[CPAP_FlowRate];
int size = EVL.size();
for (int ws = 0; ws < size; ++ws) {
flow = EVL[ws];
if (flow->count() > 20) {
flowparser->openFlow(session, flow);
@ -1157,23 +1189,26 @@ void zMaskProfile::scanPressure(Session *session)
prescnt = session->count(CPAP_Pressure);
Pressure.reserve(prescnt);
for (int j = 0; j < session->eventlist[CPAP_Pressure].size(); j++) {
QVector<EventList *> &el = session->eventlist[CPAP_Pressure];
// WTF IS THIS DOING??? WHY THE HECK DID I PUT AN INNER LOOP HERE??
QVector<EventList *> &EVL=session->eventlist[CPAP_Pressure];
int size = EVL.size();
for (int j = 0; j < size; ++j) {
scanPressureList(EVL[j]);
// QVector<EventList *> &el = session->eventlist[CPAP_Pressure];
for (int e = 0; e < el.size(); e++) {
scanPressureList(el[e]);
}
// for (int e = 0; e < el.size(); e++) {
// scanPressureList(el[e]);
// }
}
} else if (session->eventlist.contains(CPAP_IPAP)) {
prescnt = session->count(CPAP_IPAP);
Pressure.reserve(prescnt);
for (int j = 0; j < session->eventlist[CPAP_IPAP].size(); j++) {
QVector<EventList *> &el = session->eventlist[CPAP_IPAP];
QVector<EventList *> &EVL=session->eventlist[CPAP_IPAP];
int size = EVL.size();
for (int e = 0; e < el.size(); e++) {
scanPressureList(el[e]);
}
for (int j = 0; j < size; ++j) {
scanPressureList(EVL[j]);
}
}
@ -1195,6 +1230,12 @@ void zMaskProfile::scanLeakList(EventList *el)
qint64 ti;
bool found;
int psize = Pressure.size();
if (psize == 0) return;
TimeValue *tvstr = Pressure.data();
TimeValue *tvend = tvstr + (psize - 1);
TimeValue *p1, *p2;
for (; dptr < eptr; dptr++) {
leak = *dptr;
ti = start + *tptr++;
@ -1202,20 +1243,34 @@ void zMaskProfile::scanLeakList(EventList *el)
found = false;
pressure = Pressure[0].value;
if (Pressure.size() > 1) {
for (int i = 0; i < Pressure.size() - 1; i++) {
const TimeValue &p1 = Pressure[i];
const TimeValue &p2 = Pressure[i + 1];
if (psize > 1) {
for (p1 = tvstr; p1 != tvend; ++p1) {
p2 = p1+1;
if ((p2.time > ti) && (p1.time <= ti)) {
pressure = p1.value;
if ((p2->time > ti) && (p1->time <= ti)) {
pressure = p1->value;
found = true;
break;
} else if (p2.time == ti) {
pressure = p2.value;
} else if (p2->time == ti) {
pressure = p2->value;
found = true;
break;
}
// for (int i = 0; i < Pressure.size() - 1; i++) {
// const TimeValue &p1 = Pressure[i];
// const TimeValue &p2 = Pressure[i + 1];
// if ((p2.time > ti) && (p1.time <= ti)) {
// pressure = p1.value;
// found = true;
// break;
// } else if (p2.time == ti) {
// pressure = p2.value;
// found = true;
// break;
// }
}
} else {
found = true;
@ -1245,8 +1300,14 @@ void zMaskProfile::scanLeaks(Session *session)
{
QVector<EventList *> &elv = session->eventlist[CPAP_LeakTotal];
for (int i = 0; i < elv.size(); i++) {
scanLeakList(elv[i]);
int size=elv.size();
if (!size)
return;
QVector<EventList *>::iterator end = elv.end();
QVector<EventList *>::iterator it;
for (it = elv.begin(); it != end; ++it) {
scanLeakList(*it);
}
}
void zMaskProfile::updatePressureMin()
@ -1266,14 +1327,19 @@ void zMaskProfile::updatePressureMin()
int sum1, sum2, w1, w2, N, k;
for (it = pressureleaks.begin(); it != pressureleaks.end(); it++) {
QMap<EventStoreType, QMap<EventStoreType, quint32> >::iterator plend = pressureleaks.end();
QMap<EventStoreType, quint32>::iterator lmend;
for (it = pressureleaks.begin(); it != plend; it++) {
pressure = it.key();
QMap<EventStoreType, quint32> &leakmap = it.value();
lks = leakmap.size();
SN = 0;
// First sum total counts of all leaks
for (QMap<EventStoreType, quint32>::iterator lit = leakmap.begin(); lit != leakmap.end(); lit++) {
lmend = leakmap.end();
for (QMap<EventStoreType, quint32>::iterator lit = leakmap.begin(); lit != lmend; ++lit) {
SN += lit.value();
}
@ -1292,15 +1358,14 @@ void zMaskProfile::updatePressureMin()
bool found = false;
double total = 0;
for (QMap<EventStoreType, quint32>::iterator lit = leakmap.begin(); lit != leakmap.end();
lit++, k++) {
// why do this effectively twice? and k = size
for (QMap<EventStoreType, quint32>::iterator lit = leakmap.begin(); lit != lmend; ++lit, ++k) {
total += lit.value();
}
pressuretotal[pressure] = total;
for (QMap<EventStoreType, quint32>::iterator lit = leakmap.begin(); lit != leakmap.end();
lit++, k++) {
for (QMap<EventStoreType, quint32>::iterator lit = leakmap.begin(); lit != lmend; ++lit, ++k) {
//for (k=0;k < N;k++) {
v1 = lit.key();
w1 = lit.value();
@ -1379,8 +1444,13 @@ void zMaskProfile::updateProfile(Session *session)
EventDataType maxcnt, maxval, lastval, lastcnt;
for (QMap<EventStoreType, QMap<EventStoreType, quint32> >::iterator it = pressureleaks.begin();
it != pressureleaks.end(); it++) {
QMap<EventStoreType, QMap<EventStoreType, quint32> >::iterator plend = pressureleaks.end();
QMap<EventStoreType, QMap<EventStoreType, quint32> >::iterator it = pressureleaks.begin();
QMap<EventStoreType, quint32>::iterator lit;
QMap<EventStoreType, quint32>::iterator lvend;
for (; it != plend; ++it) {
p = it.key();
l = pressuremin[p];
QMap<EventStoreType, quint32> &leakval = it.value();
@ -1391,7 +1461,8 @@ void zMaskProfile::updateProfile(Session *session)
maxcnt = 0, maxval = 0, lastval = 0, lastcnt = 0;
for (QMap<EventStoreType, quint32>::iterator lit = leakval.begin(); lit != leakval.end(); lit++) {
lvend = leakval.end();
for (lit = leakval.begin(); lit != lvend; ++lit) {
cnt += lit.value();
if (lit.value() > maxcnt) {
@ -1418,7 +1489,7 @@ void zMaskProfile::updateProfile(Session *session)
pressuremax[p] = lastval;
sum = 0;
for (QMap<EventStoreType, quint32>::iterator lit = leakval.begin(); lit != leakval.end(); lit++) {
for (lit = leakval.begin(); lit != lvend; lit++) {
tmp = lit.key() - mean;
sum += tmp * tmp;
}
@ -1435,16 +1506,16 @@ void zMaskProfile::updateProfile(Session *session)
QMap<EventStoreType, EventDataType> pressureval2;
EventDataType max = 0, tmp2, tmp3;
for (QMap<EventStoreType, EventDataType>::iterator it = pressuretotal.begin();
it != pressuretotal.end(); it++) {
if (max < it.value()) { max = it.value(); }
QMap<EventStoreType, EventDataType>::iterator ptit;
QMap<EventStoreType, EventDataType>::iterator ptend = pressuretotal.end();
for (ptit = pressuretotal.begin(); ptit != ptend; ++ptit) {
if (max < ptit.value()) { max = ptit.value(); }
}
for (QMap<EventStoreType, EventDataType>::iterator it = pressuretotal.begin();
it != pressuretotal.end(); it++) {
p = it.key();
for (ptit = pressuretotal.begin(); ptit != pressuretotal.end(); ptit++) {
p = ptit.key();
tmp = pressurecount[p];
tmp2 = it.value();
tmp2 = ptit.value();
tmp3 = (tmp / tmp2) * (tmp2 / max);
@ -1546,8 +1617,18 @@ int calcLeaks(Session *session)
EventList *leak = session->AddEventList(CPAP_Leak, EVL_Event, 1);
for (int i = 0; i < session->eventlist[CPAP_LeakTotal].size(); i++) {
EventList &el = *session->eventlist[CPAP_LeakTotal][i];
QVector<EventList *> & EVL = session->eventlist[CPAP_LeakTotal];
int evlsize = EVL.size();
TimeValue *p2, *pstr, *pend;
// can this go out of the loop?
int mppressize = maskProfile->Pressure.size();
pstr = maskProfile->Pressure.data();
pend = maskProfile->Pressure.data()+(mppressize-1);
for (int i = 0; i < evlsize; ++i) {
EventList &el = *EVL[i];
EventDataType gain = el.gain(), tmp, val;
int count = el.count();
EventStoreType *dptr = el.rawData();
@ -1560,28 +1641,41 @@ int calcLeaks(Session *session)
bool found;
for (; dptr < eptr; dptr++) {
for (; dptr < eptr; ++dptr) {
tmp = EventDataType(*dptr) * gain;
ti = start + *tptr++;
found = false;
pressure = maskProfile->Pressure[0].value;
pressure = pstr->value;
for (int i = 0; i < maskProfile->Pressure.size() - 1; i++) {
const TimeValue &p1 = maskProfile->Pressure[i];
const TimeValue &p2 = maskProfile->Pressure[i + 1];
if ((p2.time > ti) && (p1.time <= ti)) {
pressure = p1.value;
for (TimeValue *p1 = pstr; p1 != pend; ++p1) {
p2 = p1+1;
if ((p2->time > ti) && (p1->time <= ti)) {
pressure = p1->value;
found = true;
break;
} else if (p2.time == ti) {
pressure = p2.value;
} else if (p2->time == ti) {
pressure = p2->value;
found = true;
break;
}
}
// for (int i = 0; i < mppressize - 1; ++i) {
// const TimeValue &p1 = &maskProfile->Pressure[i];
// const TimeValue &p2 = maskProfile->Pressure[i + 1];
// if ((p2.time > ti) && (p1.time <= ti)) {
// pressure = p1.value;
// found = true;
// break;
// } else if (p2.time == ti) {
// pressure = p2.value;
// found = true;
// break;
// }
// }
if (found) {
val = tmp - maskProfile->calcLeak(pressure);
@ -1622,10 +1716,12 @@ int calcPulseChange(Session *session)
int max;
for (int e = 0; e < it.value().size(); e++) {
int size = it.value().size();
for (int e = 0; e < size; ++e) {
EventList &el = *(it.value()[e]);
for (unsigned i = 0; i < el.count(); i++) {
int elcount=el.count();
for (int i = 0; i < elcount; ++i) {
val = el.data(i);
time = el.time(i);
@ -1634,7 +1730,7 @@ int calcPulseChange(Session *session)
lv = change;
max = 0;
for (unsigned j = i + 1; j < el.count(); j++) { // scan ahead in the window
for (int j = i + 1; j < elcount; ++j) { // scan ahead in the window
time2 = el.time(j);
if (time2 > time + window) { break; }
@ -1709,10 +1805,12 @@ int calcSPO2Drop(Session *session)
// Calculate median baseline
QList<EventDataType> med;
for (int e = 0; e < it.value().size(); e++) {
int evsize = it.value().size();
for (int e = 0; e < evsize; ++e) {
EventList &el = *(it.value()[e]);
for (unsigned i = 0; i < el.count(); i++) {
int elcount = el.count();
for (int i = 0; i < elcount; i++) {
val = el.data(i);
time = el.time(i);
@ -1746,10 +1844,11 @@ int calcSPO2Drop(Session *session)
EventDataType current;
qDebug() << "Calculated baseline" << baseline;
for (int e = 0; e < it.value().size(); e++) {
for (int e = 0; e < evsize; ++e) {
EventList &el = *(it.value()[e]);
for (unsigned i = 0; i < el.count(); i++) {
int elcount = el.count();
for (int i = 0; i < elcount; ++i) {
current = el.data(i);
if (!current) { continue; }
@ -1785,7 +1884,7 @@ int calcSPO2Drop(Session *session)
min = val;
for (unsigned j = i; j < el.count(); j++) { // scan ahead in the window
for (int j = i; j < elcount; ++j) { // scan ahead in the window
time2 = el.time(j);
//if (time2 > time+window) break;
val2 = el.data(j);

View File

@ -286,28 +286,97 @@ int FPIconLoader::OpenMachine(Machine *mach, QString &path, Profile *profile)
return true;
}
QDateTime FPIconLoader::readFPDateTime(quint8 *data)
// !\brief Convert F&P 32bit date format to 32bit UNIX Timestamp
quint32 convertDate(quint32 timestamp)
{
quint32 ts = (data[3] << 24) | (data[2] << 16) | ((data[1] << 8) | data[0]); // ^ 0xc00000;
// 0x20a41b18
quint8 day, month,hour, minute, second;
quint16 year;
quint8 day = ts & 0x1f; // 0X18 24
ts >>= 5; // 10520D8
quint8 month = ts & 0x0f; // 0X08 8
ts >>= 4; // 10520D
quint8 year = ts & 0x3f; // 0X0D 13
ts >>= 6; // 4148
quint8 second = ts & 0x3f; // 0X08 8
ts >>= 6; // 20A
quint8 minute = ts & 0x3f; // 0A 10
ts >>= 6; // 10
quint8 hour = ts & 0x1f; // 10 16
QDate date = QDate(2000 + year, month, day);
QTime time = QTime(hour, minute, second);
QDateTime datetime = QDateTime(date, time, Qt::UTC);
return datetime;
day = timestamp & 0x1f;
month = (timestamp >> 5) & 0x0f;
year = 2000 + ((timestamp >> 9) & 0x3f);
timestamp >>= 15;
timestamp |= (timestamp >> 15) & 1;
// Okay, why did I swap the first and last bits of the time field?
// What am I forgetting?? This seems to work properly like this
// Was I looking at older data that worked like this?
second = timestamp & 0x3f;
minute = (timestamp >> 6) & 0x3f;
hour = (timestamp >> 12) & 0x1f;
// in >> a1;
// in >> a2;
// t1 = a2 << 8 | a1;
// if (t1 == 0xfafe) {
// break;
// }
// day = t1 & 0x1f;
// month = (t1 >> 5) & 0x0f;
// year = 2000 + ((t1 >> 9) & 0x3f);
// in >> a1;
// in >> a2;
// ts = ((a2 << 8) | a1) << 1;
// ts |= (t1 >> 15) & 1;
// second = (ts & 0x3f);
// minute = (ts >> 6) & 0x3f;
// hour = (ts >> 12) & 0x1f;
QDateTime dt = QDateTime(QDate(year, month, day), QTime(hour, minute, second), Qt::UTC);
return dt.toTime_t();
}
quint32 convertFLWDate(quint32 timestamp)
{
quint8 day, month, hour, minute, second;
quint16 year;
day = timestamp & 0x1f;
month = (timestamp >> 5) & 0x0f;
year = 2000 + ((timestamp >> 9) & 0x3f);
timestamp >>= 15;
// Okay, why did I swap the first and last bits of the time field?
// What am I forgetting?? This seems to work properly like this
// Was I looking at older data that worked like this?
second = timestamp & 0x3f;
minute = (timestamp >> 6) & 0x3f;
hour = (timestamp >> 12) & 0x1f;
QDateTime dt = QDateTime(QDate(year, month, day), QTime(hour, minute, second), Qt::UTC);
return dt.toTime_t();
}
//QDateTime FPIconLoader::readFPDateTime(quint8 *data)
//{
// quint32 ts = (data[3] << 24) | (data[2] << 16) | ((data[1] << 8) | data[0]); // ^ 0xc00000;
// // 0x20a41b18
// quint8 day = ts & 0x1f; // 0X18 24
// ts >>= 5; // 10520D8
// quint8 month = ts & 0x0f; // 0X08 8
// ts >>= 4; // 10520D
// quint8 year = ts & 0x3f; // 0X0D 13
// ts >>= 6; // 4148
// quint8 second = ts & 0x3f; // 0X08 8
// ts >>= 6; // 20A
// quint8 minute = ts & 0x3f; // 0A 10
// ts >>= 6; // 10
// quint8 hour = ts & 0x1f; // 10 16
// QDate date = QDate(2000 + year, month, day);
// QTime time = QTime(hour, minute, second);
// QDateTime datetime = QDateTime(date, time, Qt::UTC);
// return datetime;
//}
/*
*in >> a1;
in >> a2;
@ -348,19 +417,13 @@ bool FPIconLoader::OpenFLW(Machine *mach, QString filename, Profile *profile)
{
Q_UNUSED(mach);
Q_UNUSED(profile);
QByteArray data;
quint16 t1;
quint32 ts;
double ti;
EventList *flow = nullptr, * pressure = nullptr, *leak = nullptr;
QDateTime datetime;
unsigned char *buf, *endbuf;
EventList *flow = nullptr, * pressure = nullptr;
qDebug() << filename;
QByteArray header;
QFile file(filename);
if (!file.open(QFile::ReadOnly)) {
@ -368,19 +431,14 @@ bool FPIconLoader::OpenFLW(Machine *mach, QString filename, Profile *profile)
return false;
}
header = file.read(0x200);
QByteArray header = file.read(0x200);
if (header.size() != 0x200) {
qDebug() << "Short file" << filename;
return false;
}
unsigned char hsum = 0xff;
for (int i = 0; i < 0x1ff; i++) {
hsum += header[i];
}
unsigned char hsum = 0x0;
for (int i = 0; i < 0x1ff; i++) { hsum ^= header[i]; }
if (hsum != header[0x1ff]) {
qDebug() << "Header checksum mismatch" << filename;
}
@ -399,41 +457,21 @@ bool FPIconLoader::OpenFLW(Machine *mach, QString filename, Profile *profile)
}
fname.chop(4);
QString num = fname.right(4);
int filenum = num.toInt();
// QString num = fname.right(4);
// int filenum = num.toInt();
data = file.readAll();
buf = (unsigned char *)data.data();
endbuf = buf + data.size();
QByteArray buf = file.read(4);
unsigned char * data = (unsigned char *)buf.data();
t1 = buf[1] << 8 | buf[0];
ts = data[0] | data[1] << 8 | data[2] << 16 | data[3] << 24;
if (t1 == 0xfafe) { // End of file marker..
qDebug() << "FaFE observed in" << filename;
if (ts == 0xffffffff)
return false;
}
datetime = readFPDateTime(buf);
buf += 4;
QDate date;
QTime time;
if (!datetime.isValid()) {
qDebug() << "DateTime invalid in OpenFLW:" << filename;
return false;
} else {
date = datetime.date();
time = datetime.time();
ts = datetime.toTime_t();
}
ts = convertFLWDate(ts);
ti = qint64(ts) * 1000L;
EventStoreType pbuf[256];
QMap<SessionID, Session *>::iterator sit = Sessions.find(ts);
Session *sess;
@ -442,8 +480,9 @@ bool FPIconLoader::OpenFLW(Machine *mach, QString filename, Profile *profile)
if (sit != Sessions.end()) {
sess = sit.value();
qDebug() << filenum << ":" << date << sess->session() << ":" << sess->hours() * 60.0;
// qDebug() << filenum << ":" << date << sess->session() << ":" << sess->hours() * 60.0;
} else {
// Create a session
qint64 k = -1;
Session *s1 = nullptr;
sess = nullptr;
@ -470,7 +509,7 @@ bool FPIconLoader::OpenFLW(Machine *mach, QString filename, Profile *profile)
sess->setFirst(CPAP_FlowRate, ti);
sess->setFirst(CPAP_MaskPressure, ti);
newsess = true;
qDebug() << filenum << ":" << date << "couldn't find matching session for" << ts;
// qDebug() << filenum << ":" << date << "couldn't find matching session for" << ts;
}
}
@ -479,72 +518,65 @@ bool FPIconLoader::OpenFLW(Machine *mach, QString filename, Profile *profile)
// F&P Overwrites this file, not appends to it.
flow = new EventList(EVL_Waveform, 1.0F, 0, 0, 0, rate);
//leak=new EventList(EVL_Event,1.0,0,0,0,rate*double(samples_per_block)); // 1 per second
pressure = new EventList(EVL_Event, 0.01F, 0, 0, 0,
rate * double(samples_per_block)); // 1 per second
pressure = new EventList(EVL_Event, 0.01F, 0, 0, 0, rate * double(samples_per_block));
flow->setFirst(ti);
//leak->setFirst(ti);
pressure->setFirst(ti);
qint16 pr;
quint16 lkaj;
quint16 endMarker;
quint8 offset; // offset from center for this block
quint16 pres; // mask pressure
qint16 tmp;
QByteArray block;
qint16 samples[samples_per_block];
EventDataType val;
qint16 tmp;
// Each block represents 1 second of data.. therefore Flow waveform is at 50hz, and Pressure is at 1hz
do {
quint8 *p = buf;
// Scan ahead looking for end of block, marked by ff ff
do {
p++;
if (p >= endbuf) {
delete flow;
delete leak;
delete pressure;
return false;
}
} while (!((p[0] == 0xff) && (p[1] == 0xff)));
// The Pressure and lkaj codes are before the end of block marker
p -= 3;
pr = p[1] << 8 | p[0];
lkaj = p[2];
int i = 0;
pressure->AddEvent(ti, pr);
//leak->AddEvent(ti,lkaj);
do {
tmp = buf[1] << 8 | buf[0];
val = (EventDataType(tmp) / 100.0) - lkaj;
if (val < -128) { val = -128; }
else if (val > 128) { val = 128; }
buf += 2;
pbuf[i++] = val;
} while (buf < p);
flow->AddWaveform(ti, pbuf, i, rate);
ti += i * rate;
buf = p + 5;
if (buf >= endbuf) {
block = file.read(105);
if (block.size() != 105) {
break;
}
} while (!((buf[0] == 0xff) && (buf[1] == 0x7f)));
data = (unsigned char *)block.data();
endMarker = data[1] << 8 | data[0];
if (endMarker == 0x7fff) {
// Reached end of file
break;
}
pres = data[101] << 8 | data[100];
offset = data[102];
pressure->AddEvent(ti, pres);
for (int i=0; i < samples_per_block; i++) {
tmp = ((char *)data)[(i<<1) + 1] << 8 | data[(i << 1)];
// Assuming Litres per hour, converting to litres per minute and applying offset?
// As in should be 60.0?
val = (EventDataType(tmp) / 100.0) - offset;
// if (val < -128) { val = -128; }
// else if (val > 128) { val = 128; }
samples[i]=val;
}
flow->AddWaveform(ti, samples, samples_per_block, rate);
endMarker = data[103] << 8 | data[104];
ti += samples_per_block * rate;
} while (endMarker == 0xffff);
if (endMarker != 0x7fff) {
qDebug() << fname << "waveform does not end with the corrent marker";
}
if (sess) {
sess->setLast(CPAP_FlowRate, ti);
sess->setLast(CPAP_MaskPressure, ti);
sess->eventlist[CPAP_FlowRate].push_back(flow);
// sess->eventlist[CPAP_Leak].push_back(leak);
sess->eventlist[CPAP_MaskPressure].push_back(pressure);
}
@ -555,6 +587,7 @@ bool FPIconLoader::OpenFLW(Machine *mach, QString filename, Profile *profile)
return true;
}
////////////////////////////////////////////////////////////////////////////////////////////
// Open Summary file
////////////////////////////////////////////////////////////////////////////////////////////
@ -620,32 +653,11 @@ bool FPIconLoader::OpenSummary(Machine *mach, QString filename, Profile *profile
QDate date;
do {
in >> a1;
in >> a2;
t1 = a2 << 8 | a1;
in >> ts;
if (ts == 0xffffffff) break;
if ((ts & 0xfafe) == 0xfafe) break;
if (t1 == 0xfafe) {
break;
}
day = t1 & 0x1f;
month = (t1 >> 5) & 0x0f;
year = 2000 + ((t1 >> 9) & 0x3f);
in >> a1;
in >> a2;
ts = ((a2 << 8) | a1) << 1;
ts |= (t1 >> 15) & 1;
second = (ts & 0x3f);
minute = (ts >> 6) & 0x3f;
hour = (ts >> 12) & 0x1f;
datetime = QDateTime(QDate(year, month, day), QTime(hour, minute, second), Qt::UTC);
date = datetime.date();
ts = datetime.toTime_t();
ts = convertDate(ts);
// the following two quite often match in value
in >> a1; // 0x04 Run Time
@ -733,8 +745,8 @@ bool FPIconLoader::OpenDetail(Machine *mach, QString filename, Profile *profile)
return false;
}
// Calculate and test checksum
unsigned char hsum = 0;
for (int i = 0; i < 0x1ff; i++) {
hsum += header[i];
}
@ -743,64 +755,29 @@ bool FPIconLoader::OpenDetail(Machine *mach, QString filename, Profile *profile)
qDebug() << "Header checksum mismatch" << filename;
}
QByteArray index;
index = file.read(0x800);
//long size=index.size(),pos=0;
QByteArray index = file.read(0x800);
QDataStream in(index);
in.setVersion(QDataStream::Qt_4_6);
in.setByteOrder(QDataStream::LittleEndian);
quint32 ts;
QDateTime datetime;
QDate date;
QTime time;
//FPDetIdx *idx=(FPDetIdx *)index.data();
QVector<quint32> times;
QVector<quint16> start;
QVector<quint8> records;
quint16 t1;
quint16 strt;
quint8 recs, z1, z2;
int day, month, year, hour, minute, second;
quint8 recs;
int totalrecs = 0;
do {
in >> z1;
in >> z2;
t1 = z2 << 8 | z1;
in >> ts;
if (ts == 0xffffffff) break;
if ((ts & 0xfafe) == 0xfafe) break;
if (t1 == 0xfafe) {
break;
}
ts = convertDate(ts);
day = t1 & 0x1f;
month = (t1 >> 5) & 0x0f;
year = 2000 + ((t1 >> 9) & 0x3f);
in >> z1;
in >> z2;
//
ts = ((z2 << 8) | z1) << 1;
ts |= (t1 >> 15) & 1;
//
second = (ts & 0x3f);
minute = (ts >> 6) & 0x3f;
hour = (ts >> 12) & 0x1f;
datetime = QDateTime(QDate(year, month, day), QTime(hour, minute, second), Qt::UTC);
//datetime=datetime.toTimeSpec(Qt::UTC);
ts = datetime.toTime_t();
date = datetime.date();
time = datetime.time();
in >> strt;
in >> recs;
totalrecs += recs;
@ -816,13 +793,14 @@ bool FPIconLoader::OpenDetail(Machine *mach, QString filename, Profile *profile)
in.setVersion(QDataStream::Qt_4_6);
in.setByteOrder(QDataStream::BigEndian);
// 5 byte repeating patterns
quint8 *data = (quint8 *)databytes.data();
qint64 ti;
quint8 pressure, leak, a1, a2, a3;
quint8 sa1, sa2; // The two sense awake bits per 2 minutes
quint8 pressure, leak, a1, a2, a3, a4;
// quint8 sa1, sa2; // The two sense awake bits per 2 minutes
SessionID sessid;
Session *sess;
int idx;
@ -834,7 +812,6 @@ bool FPIconLoader::OpenDetail(Machine *mach, QString filename, Profile *profile)
sess->really_set_first(ti);
EventList *LK = sess->AddEventList(CPAP_LeakTotal, EVL_Event, 1);
EventList *PR = sess->AddEventList(CPAP_Pressure, EVL_Event, 0.1F);
// EventList *FLG = sess->AddEventList(CPAP_FLG, EVL_Event);
EventList *OA = sess->AddEventList(CPAP_Obstructive, EVL_Event);
EventList *H = sess->AddEventList(CPAP_Hypopnea, EVL_Event);
EventList *FL = sess->AddEventList(CPAP_FlowLimit, EVL_Event);
@ -846,8 +823,8 @@ bool FPIconLoader::OpenDetail(Machine *mach, QString filename, Profile *profile)
idx = stidx * 15;
quint8 bitmask;
for (int i = 0; i < rec; i++) {
for (int j = 0; j < 3; j++) {
for (int i = 0; i < rec; ++i) {
for (int j = 0; j < 3; ++j) {
pressure = data[idx];
PR->AddEvent(ti, pressure);
@ -858,17 +835,19 @@ bool FPIconLoader::OpenDetail(Machine *mach, QString filename, Profile *profile)
a2 = data[idx + 3]; // [0..5] Hypopnea, [6..7] Unknown
a3 = data[idx + 4]; // [0..5] Flow Limitation, [6..7] SensAwake bitflags, 1 per minute
sa1 = (a3 >> 6) & 1; // Sense awake bit for first minutes
sa2 = (a3 >> 7) & 1; // Sense awake bit for second minute
// Sure there isn't 6 SenseAwake bits?
a4 = (a1 >> 6) << 4 | ((a2 >> 6) << 2) | (a3 >> 6);
if (sa1) { SA->AddEvent(ti, 1); }
if (sa2) { SA->AddEvent(ti + 60000L, 1); }
// this does the same thing as behaviour
//a4 = (a3 >> 7) << 3 | ((a3 >> 6)&1);
bitmask = 1;
for (int k = 0; k < 6; k++) { // There are 6 flag sets per 2 minutes
if (a1 & bitmask) { OA->AddEvent(ti, 1); }
if (a2 & bitmask) { H->AddEvent(ti, 1); }
if (a3 & bitmask) { FL->AddEvent(ti, 1); }
if (a4 & bitmask) { SA->AddEvent(ti, 1); }
bitmask <<= 1;
ti += 20000L; // Increment 20 seconds
}

View File

@ -309,6 +309,8 @@ Daily::Daily(QWidget *parent,gGraphView * shared)
graphlist[schema::channel[CPAP_Snore].label()]->AddLayer(AddCPAP(new gLineChart(CPAP_Snore, COLOR_Snore, true)));
graphlist[schema::channel[CPAP_PTB].label()]->AddLayer(AddCPAP(new gLineChart(CPAP_PTB, COLOR_PTB, square)));
graphlist[schema::channel[CPAP_MaskPressure].label()]->AddLayer(AddCPAP(new gLineChart(CPAP_MaskPressure, COLOR_MaskPressure, false)));
graphlist[schema::channel[CPAP_RespRate].label()]->AddLayer(AddCPAP(lc=new gLineChart(CPAP_RespRate, COLOR_RespRate, square)));