Index: firmware/App/Services/Reservoirs.c =================================================================== diff -u -r525770ee7cc0fcbfdc2836ac101c7e2b98d2d9c2 -r49fc89b6cd5f629a201dc9a901b8aac68087da6f --- firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision 525770ee7cc0fcbfdc2836ac101c7e2b98d2d9c2) +++ firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision 49fc89b6cd5f629a201dc9a901b8aac68087da6f) @@ -33,7 +33,6 @@ #define RESERVOIR_FRESH_SETTLE_TIME_MS 15000 ///< Allocated time to settle the freshly filled reservoir in milliseconds. #define RESERVOIR_USED_SETTLE_TIME_MS 5000 ///< Allocated time to settle the depleted reservoir in milliseconds. - // TODO Why use this margin factor? RESERVOIR_CYCLE_EXTRA_MARGIN_TIME_MS #define RESERVOIR_CYCLE_EXTRA_MARGIN_TIME_MS 8000 ///< Reservoir extra time in during the cycle for error in milliseconds. #define MAX_RESERVOIR_VOLUME_ML 1900.0F ///< Maximum allowed fluid in a reservoir in milliliters. @@ -57,6 +56,7 @@ #define DIALYSATE_FLOW_RATE_550_ML_PER_MIN 0.55F ///< Dialysate flow rate 550 mL/min. #define TGT_FILL_FLOW_FOR_DIA_FLOW_100_TO_350_ML_PER_MIN 0.5F ///< Target fill flow rate for dialysate flow rates in between 100 to 350 mL/min. #define TGT_FILL_FLOW_FOR_DIA_FLOW_550_TO_600_ML_PER_MIN 0.8F ///< Target fill flow rate for dialysate flow rates in between 500 to 600 mL/min. +#define TGT_FILL_FLOW_ERROR_ALLOWANCE 0.9F ///< Target fill flow rate for dialysate allowed error percentage. #define DIA_FLOW_TO_FILL_FLOW_SECOND_ORDER_COEFF 10.0F ///< Dialysate flow rate to fill flow rate second order coefficient. #define DIA_FLOW_TO_FILL_FLOW_FIRST_ORDER_COEFF 7.5F ///< Dialysate flow rate to fill flow rate first order coefficient. @@ -172,7 +172,7 @@ * The execReservoirs function executes the state machine for the treatment * reservoir management during treatment mode. * @details Inputs: reservoirsState - * @details Outputs: reservoirsState, timeReservoirInUse, volSpentML + * @details Outputs: reservoirsState, timeReservoirInUse, volSpentML, recirculationLevelPct * @return none *************************************************************************/ void execReservoirs( void ) @@ -304,7 +304,7 @@ * The getTargetFillFlowRateLPM function sets the target fill flow rate for DG * based on the target dialysate flow rate. * @details Inputs: none - * @details Outputs: none + * @details Outputs: targetFillFlowLPM * @return target fill flow rate *************************************************************************/ static F32 getTargetFillFlowRateLPM( void ) @@ -338,13 +338,14 @@ /*********************************************************************//** * @brief * The getFillTimeMS function calculates the fill time in milliseconds. - * @details Inputs: none + * @details Inputs: ratios * @details Outputs: none - * @return target fill flow rate + * @return target maximum fill time *************************************************************************/ static U32 getFillTimeMS( void ) { - F32 targetFillFlowRate = getTargetFillFlowRateLPM(); + // Get target flow * error allowance to make sure there is enough time to fill + F32 targetFillFlowRate = getTargetFillFlowRateLPM() * TGT_FILL_FLOW_ERROR_ALLOWANCE; // The target fill flow rate is RO flow rate plus acid and bicarb flow rates F32 totalTargetFillFlow = targetFillFlowRate + ( targetFillFlowRate * ratios.acidMixingRatio ) + ( targetFillFlowRate * ratios.bicarbMixingRatio ); @@ -375,13 +376,27 @@ F32 timeTotalCycleMS = fillTimeMS + RESERVOIR_FRESH_SETTLE_TIME_MS + RESERVOIR_CYCLE_EXTRA_MARGIN_TIME_MS + ratios.timeFillPrepMS; F32 timeReservoirCycleMS = 0.0F; F32 timeUFDepletionMS = NEARLY_INFINITY; + F32 volFreshML = FILL_RESERVOIR_TO_VOLUME_ML - volSpentML; + F32 timeFreshRemainingMS = ( volFreshML / (F32)dialysateFlowMLP ) * SEC_PER_MIN * MS_PER_SECOND; + F32 volMaxUFML = FILL_RESERVOIR_TO_VOLUME_ML * MAX_RESERVOIR_DILUTION; // Check if target UF flow is not zero to consider it in the calculations too if ( targetUFFlowMLP > NEARLY_ZERO ) { // If UF is not 0, the active reservoir cycle time is minimum of UF depletion and fill time timeUFDepletionMS = ( ( (F32)FILL_RESERVOIR_TO_VOLUME_ML * RESERVOIR_DILUTION_RATIO ) / targetUFFlowMLP ) * SEC_PER_MIN * MS_PER_SECOND; + // Calculate the ultra-filtration remaining volume + // Using the ultra-filtration remaining volume and the ultra-filtration target flow rate calculate the time + // The depletion time in milliseconds is the minimum time of the fresh remaining time and the depletion remaining time + // The depletion time is then used to calculate the time to wait to fill and whether to trigger a fill command or not + F32 volRemainingUFML = volMaxUFML - volSpentUFML; + F32 timeDepleteRemainingMS = ( volRemainingUFML / targetUFFlowMLP ) * SEC_PER_MIN * MS_PER_SECOND; + timeDepleteMS = MIN( timeFreshRemainingMS, timeDepleteRemainingMS ); } + else + { + timeDepleteMS = timeFreshRemainingMS; + } timeDepletionMS = MIN( timeDepletionMS, timeUFDepletionMS ); timeReservoirCycleMS = MAX( timeTotalCycleMS, timeDepletionMS ); @@ -393,6 +408,7 @@ DG_CMD_DIALYSATE_HEATING_PARAMS_T params; params.trimmerTargetTemperature = getTreatmentParameterF32( TREATMENT_PARAM_DIALYSATE_TEMPERATURE ); + // TODO timeReservoirWait2SwitchMS Should this be the calculated value? Or just RESERVOIR_FRESH_SETTLE_TIME_MS? params.timeReservoirWait2SwitchMS = RESERVOIR_FRESH_SETTLE_TIME_MS + RESERVOIR_CYCLE_EXTRA_MARGIN_TIME_MS; params.timeReservoirFillMS = fillTimeMS; params.timeReservoirCycleMS = timeReservoirCycleMS; @@ -552,36 +568,10 @@ } else { - // The fresh left volume in the reservoir is the nominal volume - the spent volume - // Using the fresh remaining volume, time to spent the fresh remaining is calculated by dividing the volume to - // target dialysate flow rate. The target dialysate flow rate is used to be able to respond to the flow changes - // by the user - U32 targetDialysateFlowMLP = getTreatmentParameterU32( TREATMENT_PARAM_DIALYSATE_FLOW ); - F32 volFreshML = FILL_RESERVOIR_TO_VOLUME_ML - volSpentML; - F32 timeFreshRemainingMS = ( volFreshML / (F32)targetDialysateFlowMLP ) * SEC_PER_MIN * MS_PER_SECOND; - F32 volMaxUFML = FILL_RESERVOIR_TO_VOLUME_ML * MAX_RESERVOIR_DILUTION; - F32 ultrafiltrationFlowMLP = getCurrentUFSetRate(); - - // If the ultra-filtration volume is not 0 check the depletion time for that too - if ( ultrafiltrationFlowMLP > NEARLY_ZERO ) - { - // Calculate the ultra-filtration remaining volume - // Using the ultra-filtration remaining volume and the ultra-filtration target flow rate calculate the time - // The depletion time in milliseconds is the minimum time of the fresh remaining time and the depletion remaining time - // The depletion time is then used to calculate the time to wait to fill and whether to trigger a fill command or not - F32 volRemainingUFML = volMaxUFML - volSpentUFML; - F32 timeDepleteRemainingMS = ( volRemainingUFML / ultrafiltrationFlowMLP ) * SEC_PER_MIN * MS_PER_SECOND; - timeDepleteMS = MIN( timeFreshRemainingMS, timeDepleteRemainingMS ); - } - else - { - timeDepleteMS = timeFreshRemainingMS; - } - // Time to wait prior to next fill is depletion time - the whole group of how much time is needed to fill a reservoir + // the time it takes to wait for a reservoir to settle and the extra margin time for ramp up of the RO and drain pumps and // any other extra times. - timeWaitToFillMS = timeDepleteMS - ( getFillTimeMS() + RESERVOIR_FRESH_SETTLE_TIME_MS - RESERVOIR_CYCLE_EXTRA_MARGIN_TIME_MS ); + timeWaitToFillMS = timeDepleteMS - ( getFillTimeMS() + RESERVOIR_FRESH_SETTLE_TIME_MS + RESERVOIR_CYCLE_EXTRA_MARGIN_TIME_MS ); // If the wait time has elapsed, trigger a fill command if ( timeWaitToFillMS <= 0 ) @@ -659,7 +649,7 @@ volSpentUFML = getReservoirUltrafiltrationVol( activeReservoir ); dilutionLevelPct = volSpentUFML / (F32)FILL_RESERVOIR_TO_VOLUME_ML; - // Wait for the reservoir to settle and then send the commands to switch the active reservoir TODO - restore #define below + // Wait for the reservoir to settle and then send the commands to switch the active reservoir if ( ( TRUE == didTimeout( reservoirSwitchStartTimeMS, RESERVOIR_FRESH_SETTLE_TIME_MS ) ) && ( ( dilutionLevelPct >= MAX_RESERVOIR_DILUTION ) || ( volSpentML >= (F32)FILL_RESERVOIR_TO_VOLUME_ML ) || ( getReservoirWeight( active ) > MAX_RESERVOIR_VOL_BEFORE_SWITCH_ML ) ) ) {