From a92b4143a3c33fad8b8ca46e4839b4917b74e81e Mon Sep 17 00:00:00 2001 From: LoudSnorer Date: Thu, 23 Nov 2023 10:15:21 -0500 Subject: [PATCH] Statistics: Updated Usage rows and removed compilance word --- oscar/statistics.cpp | 201 ++++++++++++++++++++++++++++++------------- oscar/statistics.h | 7 +- 2 files changed, 145 insertions(+), 63 deletions(-) diff --git a/oscar/statistics.cpp b/oscar/statistics.cpp index 495120ed..cb84dc74 100644 --- a/oscar/statistics.cpp +++ b/oscar/statistics.cpp @@ -7,10 +7,16 @@ * License. See the file COPYING in the main directory of the source code * for more details. */ -#define TEST_MACROS_ENABLEDoff +#define TEST_MACROS_ENABLEDoff // remember to turn off for release. #include -#define HI_RES_FONT_SIZE +/* +ToDO ?? +mild yellow 5-15 +moderate Orange 16-29 +server= red 30+ +*/ + #include #include @@ -627,6 +633,44 @@ void Statistics::updateRXChanges() delete progress; } +EventDataType calcAHI(QDate start, QDate end); //forward declareation + +EventDataType MEDIAN_NULL = std::numeric_limits::infinity(); + +EventDataType getHours(Day* day) {return day->hours(MT_CPAP); }; +EventDataType getAHI(Day* day) {QDate date=day->date(); return calcAHI(date,date); }; + +typedef EventDataType (*DAY_VALUE)(Day*) ; + +EventDataType calcMedian(QDate start, QDate end, DAY_VALUE funct ) +{ + QListlist = p_profile->getDays(MT_CPAP,start,end); + QVector vec; vec.clear(); + for (Day* day:list) vec.push_back(funct(day)); + int len = vec.size(); + if (len==0) return MEDIAN_NULL; + int mediaOffset = len/2; + auto be = vec.begin(); + auto me = be+mediaOffset ; + auto en = vec.end(); + EventDataType median; + if ((len&1)==0) { + // have an even number of sample to find median. must take average of two. + auto me0 = me-1; + nth_element(be ,me0, en); + EventDataType median0 = vec[mediaOffset-1]; + + nth_element(be ,me, en); + median = (median0+vec[mediaOffset])/2; + } else { + // Odd then there will be a unique number that is truely the median + nth_element(be ,me, en); + median = vec[mediaOffset]; + } + IF(len < 66) DEBUGFC Q(len) Q(median) Z(vec); + return median; +} + // Statistics constructor is responsible for creating list of rows that will on the Statistics page // and skeletons of column 1 text that correspond to each calculation type. @@ -644,18 +688,31 @@ Statistics::Statistics(QObject *parent) : rows.push_back(StatisticsRow(disabledInfo.display(2),SC_WARNING2,MT_CPAP)); } } - rows.push_back(StatisticsRow("", SC_DAYS, MT_CPAP)); + rows.push_back(StatisticsRow("", SC_DAYS, MT_CPAP)); rows.push_back(StatisticsRow("", SC_COLUMNHEADERS, MT_CPAP)); rows.push_back(StatisticsRow(tr("CPAP Usage"), SC_SUBHEADING, MT_CPAP)); - rows.push_back(StatisticsRow(tr("Days In Period"), SC_SELECTED_DAYS , MT_CPAP)); - rows.push_back(StatisticsRow(tr("Days Used"), SC_DAYS_W_DATA , MT_CPAP)); + + rows.push_back(StatisticsRow(tr("Total Days"), SC_SELECTED_DAYS , MT_CPAP)); + rows.push_back(StatisticsRow(tr("Used Days"), SC_DAYS_W_DATA , MT_CPAP)); + rows.push_back(StatisticsRow(tr("Used Days %1%2 hrs/day"), SC_COMPLIANCE_DAYS , MT_CPAP)); + + rows.push_back(StatisticsRow(tr("Percent Total Days %1%2 hrs/day"), SC_COMPLIANCE , MT_CPAP)); + rows.push_back(StatisticsRow(tr("Percent Used Days %1%2 hrs/day"), SC_USED_DAY_COMPLIANCE_PERCENT , MT_CPAP)); + + rows.push_back(StatisticsRow(tr("Used Days %1%2 hrs/day"), SC_NON_COMPLIANCE_DAYS , MT_CPAP)); rows.push_back(StatisticsRow(tr("Days Not Used"), SC_DAYS_WO_DATA , MT_CPAP)); - rows.push_back(StatisticsRow(tr("Days (%1 hrs/day)"), SC_COMPLIANCE_DAYS , MT_CPAP)); - rows.push_back(StatisticsRow(tr("Percent Days (%1 hrs/day)"), SC_COMPLIANCE, MT_CPAP)); + rows.push_back(StatisticsRow(tr("Average Hours per Night"), SC_HOURS, MT_CPAP)); + rows.push_back(StatisticsRow(tr("Median Hours per Night"), SC_MEDIAN_HOURS , MT_CPAP)); rows.push_back(StatisticsRow(tr("Therapy Efficacy"), SC_SUBHEADING, MT_CPAP)); - rows.push_back(StatisticsRow("AHI", SC_AHI, MT_CPAP)); + rows.push_back(StatisticsRow("AHI", SC_AHI_RDI, MT_CPAP)); + if (p_profile->general->calculateRDI()) { + // then RDI will be displayed instead of AHI everywhere. + // so to see AHI a new row must be added. + rows.push_back(StatisticsRow(STR_TR_AHI , SC_AHI_ONLY , MT_CPAP)); + } + rows.push_back(StatisticsRow(tr("AHI Median"), SC_MEDIAN_AHI,MT_CPAP)); rows.push_back(StatisticsRow("AllApnea", SC_CPH, MT_CPAP)); rows.push_back(StatisticsRow("Obstructive", SC_CPH, MT_CPAP)); rows.push_back(StatisticsRow("Hypopnea", SC_CPH, MT_CPAP)); @@ -774,9 +831,7 @@ const QString table_width = "width='100%'"; QString Statistics::generateHeader(bool onScreen) { QString html = QString(""); - #if defined(HI_RES_FONT_SIZE) html += ""; - #endif html += "Oscar Statistics Report"; html += "