Index: firmware/App/Modes/Dialysis.c =================================================================== diff -u -rf760ffc4b10556e5186e9ceb90294262063440ca -red4f6eb9692ea0f5f9cb7acae1cf119932fb2d72 --- firmware/App/Modes/Dialysis.c (.../Dialysis.c) (revision f760ffc4b10556e5186e9ceb90294262063440ca) +++ firmware/App/Modes/Dialysis.c (.../Dialysis.c) (revision ed4f6eb9692ea0f5f9cb7acae1cf119932fb2d72) @@ -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 250.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 @@ -80,27 +81,23 @@ static U32 setBloodFlowRate; ///< Currently set blood flow rate (from prescription). static U32 setDialysateFlowRate; ///< Currently set dialysate flow rate (from prescription). -static F32 maxUFVolumeML; ///< Currently set total ultrafiltration volume for treatment (from prescription). +static F32 setUFVolumeML; ///< Currently set total ultrafiltration volume for treatment (from prescription). static F32 setUFRate; ///< Currently set ultrafiltration rate (from prescription). 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 ); @@ -145,21 +142,29 @@ setBloodFlowRate = 0; setDialysateFlowRate = 0; - maxUFVolumeML = 0.0; + setUFVolumeML = 0.0; setUFRate = 0.0; 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(); } @@ -302,7 +307,7 @@ { setBloodFlowRate = bPFlow; setDialysateFlowRate = dPFlow; - maxUFVolumeML = maxUFVol; + setUFVolumeML = maxUFVol; setUFRate = uFRate; // Make rate changes in real time if currently performing dialysis. @@ -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,9 +803,10 @@ // 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 ) + if ( refUFVolume >= setUFVolumeML ) // TODO - is this something we want to do or should we just let UF continue? { setUFRate = 0.0; } @@ -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 ) ) > (F32)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 ) @@ -1074,11 +1061,10 @@ /*********************************************************************//** * @brief - * The updateUFVolumes function updates the ultrafiltration volumes based on - * set UF rate, latest UF elapsed time, and the latest load cell weight for the - * currently used reservoir. Updated UF volumes are then sent to the dialysate - * outlet pump controller. - * @details Inputs: setUFRate, uFTimeMS, load cell weight + * The updateUFVolumes function updates the measured ultrafiltration volume based on + * the latest load cell weight for the currently used reservoir. Updated UF volumes + * are then sent to the dialysate outlet pump controller. + * @details Inputs: measUFVolumeFromPriorReservoirs, resStartVolume[], load cell weight * @details Outputs: refUFVolume, measUFVolume * @return none *************************************************************************/ @@ -1127,6 +1113,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 +1133,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 +1151,34 @@ { 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 ); + } + } + SEND_EVENT_WITH_2_F32_DATA( HD_EVENT_RSRVR_UF_VOLUME_AND_TIME, uFResVolumeInMl, resUFTimeInMin ) + SEND_EVENT_WITH_2_F32_DATA( HD_EVENT_RSRVR_UF_RATE, uFMeasRate, resExpUFRate ) + + // Check redundant load cells checkLoadCellsStablePrimaryBackupDriftOutOfRange( inactiveRes, RESERVOIR_STEADY_CYCLE_FINAL ); }