Index: firmware/App/Modes/Dialysis.c =================================================================== diff -u -ra9c1eee2bed2b569a6f32cbc5e80c4631559d683 -r0ef0dc2039726fd956ea74102ec7ff0e42bd2aab --- firmware/App/Modes/Dialysis.c (.../Dialysis.c) (revision a9c1eee2bed2b569a6f32cbc5e80c4631559d683) +++ firmware/App/Modes/Dialysis.c (.../Dialysis.c) (revision 0ef0dc2039726fd956ea74102ec7ff0e42bd2aab) @@ -39,12 +39,11 @@ // ********** private definitions ********** -#define MAX_UF_RATE_ML_PER_HOUR 2750.0F ///< Maximum ultrafiltration rate in mL/hour -#define MAX_UF_ACCURACY_ERROR_ML 50.0F ///< Maximum ultrafiltration accuracy error in mL over the entire treatment. +#define MAX_UF_VOLUME_ACCURACY_ERROR_ML 50.0F ///< Maximum ultrafiltration volume accuracy error in mL over the entire treatment. +#define MAX_UF_RATE_ACCURACY_ERROR_ML_MIN 5.0F ///< Maximum ultrafiltration rate accuracy error in mL/min over use of single reservoir during treatment. + /// Saline bolus data broadcast interval (ms/task time) count. static const U32 SALINE_BOLUS_DATA_PUB_INTERVAL = ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ); -/// Ultrafiltration rate accuracy check interval count. -static const U32 UF_ACCURACY_CHECK_INTERVAL = ((1 * MIN_PER_HOUR * SEC_PER_MIN * MS_PER_SECOND) / TASK_GENERAL_INTERVAL); #define MAX_SALINE_VOLUME_DELIVERED 800 ///< Maximum saline volume delivered for a treatment. #define SALINE_BOLUS_RATE_ML_MIN 300 ///< Fixed rate for saline bolus delivery. @@ -70,8 +69,10 @@ static F32 measUFVolume; ///< Current total measured volume for ultrafiltration (Where are we w/r/t ultrafiltration). static F32 resStartVolume[ NUM_OF_DG_RESERVOIRS ]; ///< Reservoir start volume for ultrafiltration (i.e. where did we start with each reservoir). static F32 resFinalVolume[ NUM_OF_DG_RESERVOIRS ]; ///< Reservoir final volume for ultrafiltration (i.e. where did we end after switch with each reservoir). +static F32 resStartRefVolume[ NUM_OF_DG_RESERVOIRS ]; ///< Starting ultrafiltration reference volume for reservoirs. +static F32 resFinalRefVolume[ NUM_OF_DG_RESERVOIRS ]; ///< Final ultrafiltration reference volume for reservoirs. static F32 resCurrVolume[ NUM_OF_DG_RESERVOIRS ]; ///< Reservoir current volume. -static F32 resLastVolume[ NUM_OF_DG_RESERVOIRS ]; ///< Reservoir previous volume. +static F32 resLastVolume[ NUM_OF_DG_RESERVOIRS ]; ///< Previous reading of reservoir volume. static F32 measUFVolumeFromPriorReservoirs; ///< Current total ultrafiltration volume from previous reservoirs in current treatment. static F32 lcLastSteadyWeight[NUM_OF_RESERVOIR_STEADY_CYCLES][NUM_OF_LOAD_CELLS]; ///< Load Cell Last Steady Weight for drift test Start/Final cycle @@ -85,22 +86,18 @@ static U32 salineBolusBroadcastTimerCtr; ///< Saline bolus data broadcast timer counter used to schedule when to transmit data. static BOOL salineBolusStartRequested; ///< Flag indicates a saline bolus start has been requested by user. -static BOOL salineBolusAbortRequested; ///< Flag indicates a salien bolus abort has been requested by user. +static BOOL salineBolusAbortRequested; ///< Flag indicates a saline bolus abort has been requested by user. static BOOL salineBolusAutoResumeUF = FALSE; ///< Flag indicates UF should be auto-resumed after saline bolus completes. static F32 totalSalineVolumeDelivered_mL; ///< Volume (mL) in total of saline delivered so far (cumulative for all boluses including current one). static F32 bolusSalineVolumeDelivered_mL; ///< Volume (mL) of current bolus delivered so far (calculated from measured blood flow rate). static F32 expectedSalineBolusVolume_mL; ///< Volume (mL) of current bolus delivered so far (calculated from target blood flow rate). static U32 bolusSalineLastVolumeTimeStamp; ///< Time stamp for last saline volume update. -static U32 uFAccuracyCheckTimerCtr; ///< Timer counter to determine when next to check ultrafiltration accuracy. -static F32 lastUFVolumeChecked; ///< Starting ultrafiltration volume for accuracy check. - // ********** private function prototypes ********** static DIALYSIS_STATE_T handleDialysisUltrafiltrationState( void ); static DIALYSIS_STATE_T handleDialysisSalineBolusState( void ); -static UF_STATE_T handleUFStartState( DIALYSIS_STATE_T *dialysisState ); static UF_STATE_T handleUFPausedState( DIALYSIS_STATE_T *dialysisState ); static UF_STATE_T handleUFRunningState( DIALYSIS_STATE_T *dialysisState ); @@ -109,7 +106,7 @@ static SALINE_BOLUS_STATE_T handleSalineBolusInProgressState( DIALYSIS_STATE_T *dialysisState ); static SALINE_BOLUS_STATE_T handleSalineBolusMaxDeliveredState( DIALYSIS_STATE_T *dialysisState ); -static void checkUFAccuracyAndVolume( void ); +static void checkUFControl( void ); static void updateUFVolumes( void ); static void publishSalineBolusData( void ); @@ -151,15 +148,23 @@ salineBolusBroadcastTimerCtr = 0; totalSalineVolumeDelivered_mL = 0.0; - uFAccuracyCheckTimerCtr = 0; - lastUFVolumeChecked = 0.0; - for ( i = 0; i < NUM_OF_LOAD_CELLS; i++ ) { lcLastSteadyWeight[RESERVOIR_STEADY_CYCLE_START][i] = LOAD_CELL_ILLEGAL_WEIGHT_VALUE; lcLastSteadyWeight[RESERVOIR_STEADY_CYCLE_FINAL][i] = LOAD_CELL_ILLEGAL_WEIGHT_VALUE; } + for ( i = 0; i < NUM_OF_DG_RESERVOIRS; i++ ) + { + resStartVolume[ i ] = 0.0F; + resFinalVolume[ i ] = 0.0F; + resStartRefVolume[ i ] = 0.0F; + resFinalRefVolume[ i ] = 0.0F; + resCurrVolume[ i ] = 0.0F; + resLastVolume[ i ] = 0.0F; + + } + resetSalineBolus(); } @@ -622,8 +627,8 @@ { DIALYSIS_STATE_T priorSubState = currentDialysisState; - // Check ultrafiltration max rate and accuracy during dialysis (even when ultrafiltration is paused). - checkUFAccuracyAndVolume(); + // Check ultrafiltration control during dialysis (even when ultrafiltration is paused). + checkUFControl(); // Dialysis state machine switch ( currentDialysisState ) @@ -798,6 +803,7 @@ // Update UF ref volume in UF running state only refUFVolume += ( ( (F32)msSinceLast / MS_PER_SECOND ) / SEC_PER_MIN ) * setUFRate; + updateReservoirUFTime(); // If we have reached target UF volume, UF is complete - set UF rate to zero for remainder of treatment if ( refUFVolume >= maxUFVolumeML ) @@ -1032,36 +1038,17 @@ /*********************************************************************//** * @brief - * The checkUF function checks ultrafiltration accuracy for the last - * hour and checks total UF volume. Triggers an alarm if out of spec. - * @details Inputs: uFAccuracyCheckTimerCtr, lastUFVolumeChecked, measUFVolume - * @details Outputs: uFAccuracyCheckTimerCtr, lastUFVolumeChecked + * The checkUFControl function checks ultrafiltration control to ensure measured + * UF volume does not deviate too far from the UF reference volume (indicating + * poor UF control). + * @details Inputs: none + * @details Outputs: none * @return none *************************************************************************/ -static void checkUFAccuracyAndVolume( void ) +static void checkUFControl( void ) { - F32 uFMeasRate = measUFVolume - lastUFVolumeChecked; // Volumes are at start/end of 1 hour period, so implied rate is per hour - - // Check UF rate over last hour - if ( uFMeasRate > MAX_UF_RATE_ML_PER_HOUR ) - { -#ifndef _RELEASE_ - if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_ULTRAFILTRATION_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) -#endif - { - SET_ALARM_WITH_1_F32_DATA( ALARM_ID_UF_RATE_TOO_HIGH_ERROR, uFMeasRate ); - } - } - // Increment timer and see if time to start another 1 hour check period - if ( ++uFAccuracyCheckTimerCtr >= UF_ACCURACY_CHECK_INTERVAL ) - { - // Reset for next check interval - lastUFVolumeChecked = measUFVolume; - uFAccuracyCheckTimerCtr = 0; - } - // Check total UF volume error - if ( ( fabs( refUFVolume - measUFVolume ) ) > MAX_UF_ACCURACY_ERROR_ML ) + if ( ( fabs( refUFVolume - measUFVolume ) ) > MAX_UF_VOLUME_ACCURACY_ERROR_ML ) { #ifndef _RELEASE_ if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_ULTRAFILTRATION_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) @@ -1127,6 +1114,7 @@ // Set starting baseline volume for next reservoir before we switch to it resStartVolume[ reservoirID ] = resVolume; resFinalVolume[ reservoirID ] = resVolume; + resStartRefVolume[ reservoirID ] = refUFVolume; checkLoadCellsStablePrimaryBackupDriftOutOfRange( reservoirID, RESERVOIR_STEADY_CYCLE_START ); } @@ -1146,6 +1134,9 @@ // Update UF volume from prior reservoirs per tentative res volume for last reservoir measUFVolumeFromPriorReservoirs += ( resFinalVolume[ inactiveRes ] - resStartVolume[ inactiveRes ] ); + + // Record final UF ref volume for the spent reservoir + resFinalRefVolume[ inactiveRes ] = refUFVolume; } /*********************************************************************//** @@ -1161,12 +1152,33 @@ { DG_RESERVOIR_ID_T inactiveRes = getDGInactiveReservoir(); F32 resVolume = getReservoirWeightLargeFilter( inactiveRes ); + F32 resUFTimeInMs = (F32)getLastReservoirUFTimeInMs(); + F32 resUFTimeInMin = ( resUFTimeInMs / (F32)( SEC_PER_MIN * MS_PER_SECOND ) ); + F32 resExpUFVolumeInMl = resFinalRefVolume[ inactiveRes ] - resStartRefVolume[ inactiveRes ]; + F32 resExpUFRate = resExpUFVolumeInMl / resUFTimeInMin; + F32 uFResVolumeInMl; + F32 uFMeasRate; // Update UF volume from prior reservoirs per final res volume for last reservoir a bit after we have switched and reservoir has settled measUFVolumeFromPriorReservoirs -= ( resFinalVolume[ inactiveRes ] - resStartVolume[ inactiveRes ] ); resFinalVolume[ inactiveRes ] = resVolume; - measUFVolumeFromPriorReservoirs += ( resFinalVolume[ inactiveRes ] - resStartVolume[ inactiveRes ] ); + uFResVolumeInMl = ( resFinalVolume[ inactiveRes ] - resStartVolume[ inactiveRes ] ); + measUFVolumeFromPriorReservoirs += uFResVolumeInMl; + // Check UF rate + uFMeasRate = uFResVolumeInMl / resUFTimeInMin; + + if ( fabs( resExpUFRate - uFMeasRate ) > MAX_UF_RATE_ACCURACY_ERROR_ML_MIN ) + { +#ifndef _RELEASE_ + if ( getSoftwareConfigStatus( SW_CONFIG_DISABLE_ULTRAFILTRATION_ALARMS ) != SW_CONFIG_ENABLE_VALUE ) +#endif + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_UF_RATE_TOO_HIGH_ERROR, uFMeasRate ); + } + } + + // Check redundant load cells checkLoadCellsStablePrimaryBackupDriftOutOfRange( inactiveRes, RESERVOIR_STEADY_CYCLE_FINAL ); }