Index: firmware/App/Controllers/DialInFlow.c =================================================================== diff -u -rdc7d8d337cb5f3647e3cbd1bcd054d83fbe7bd2a -r14d9389c9db66c265e17d975e30ed73c66dcc21b --- firmware/App/Controllers/DialInFlow.c (.../DialInFlow.c) (revision dc7d8d337cb5f3647e3cbd1bcd054d83fbe7bd2a) +++ firmware/App/Controllers/DialInFlow.c (.../DialInFlow.c) (revision 14d9389c9db66c265e17d975e30ed73c66dcc21b) @@ -110,6 +110,8 @@ #define DIP_PWM_FROM_ML_PER_MIN(rate) ( (rate) * DIP_ML_PER_MIN_TO_PUMP_RPM_FACTOR * DIP_GEAR_RATIO * DIP_MOTOR_RPM_TO_PWM_DC_FACTOR + DIP_PWM_ZERO_OFFSET ) /// Conversion from PWM duty cycle % to commanded pump motor speed. PWM range is 10% to 90%. RPM range is 0 to 3200. 3200 / 0.8 = 4000. #define DIP_PWM_TO_MOTOR_SPEED_RPM(pwm) ( ((pwm) - DIP_PWM_ZERO_OFFSET) * 4000.0F ) +/// Conversion from pump motor speed to PWM duty cycle. +#define DIP_MOTOR_SPEED_RPM_TO_PWM(rpm) ( ( rpm / 4000.0F ) + 0.1 ) // Macro converts PWM to estimate flow rate needed to achieve it. #define DIP_ML_PER_MIN_FROM_PWM(pwm) ( (( pwm - DIP_PWM_ZERO_OFFSET) * 684.73F ) + 49.121F ) @@ -126,14 +128,16 @@ //Hybrid flow rate algorithm parameters #define DIAL_IN_FLOW_A_ZERO 1.267F ///< Y intercept used for alpha flow coefficient calculation. -#define DIAL_IN_FLOW_WEAR_A_TERM 0.000000003551F ///< A term used for wear portion of alpha flow coefficient. -#define DIAL_IN_FLOW_WEAR_B_TERM 0.002244F ///< B term used for wear portion of alpha flow coefficient. +#define DIAL_IN_FLOW_WEAR_A_TERM 0.000000003551F ///< A term used for wear portion of alpha flow coefficient (m'). +#define DIAL_IN_FLOW_WEAR_B_TERM 0.002244F ///< B term used for wear portion of alpha flow coefficient (m0). #define DIAL_IN_FLOW_QHIGHTRANSITION 400.0F ///< High flow rate transition for blended algorithm #define DIAL_IN_FLOW_QLOWTRANSITION 300.0F ///< Low flow rate transition for blended algorithm #define DIAL_IN_FLOW_PEST_A_TERM -0.000491F ///< a (2nd order) term in polynomial fit for pressure estimation #define DIAL_IN_FLOW_PEST_B_TERM -0.04672F ///< b (first order) term in polynomial fit for pressure estimation #define DIAL_IN_FLOW_PEST_C_TERM 18.648F ///< c (zero order) term in polynomial fit for pressure estimation #define DIAL_IN_MAX_ROTOR_COUNT_FOR_WEAR 25000 ///< Maximum rotor count for determining wear of the cartridge (negligible affect beyond this threshold). +#define DIAL_IN_STROKE_VOLUME 3.405 ///< Stroke volume (SV) used for Flow Estimation ALgorithm +#define DIAL_IN_GEAR_RATIO 32 ///< Gear ratio used for Flow Estimation ALgorithm /// Enumeration of dialysate inlet pump states. typedef enum DialInPump_States @@ -235,7 +239,6 @@ static void checkDialInPumpFlowRate( void ); static F32 calcDialInFlow( void ); static F32 dialysateInPumpPWMFromTargetFlowRate( F32 QdTarget ); -static void resetDialInPumpRotorCount( void ); /*********************************************************************//** * @brief @@ -781,26 +784,27 @@ *************************************************************************/ static F32 calcDialInFlow( void ) { + F32 estimatedFlow; + F32 QdTarget = getTargetDialInFlowRate(); + F32 deltaFlow; - F32 estimatedFlow; - F32 QdTarget = getTargetDialInFlowRate(); - - if (QdTarget >= DIAL_IN_FLOW_QHIGHTRANSITION) + if ( QdTarget >= DIAL_IN_FLOW_QHIGHTRANSITION ) { //At higher flow rates, use the flow meter value. Assume target flow rate has already checked for out of bounds on high end. estimatedFlow = filteredDialInFlowMeterReading; } else { //Use blended or calculated flow rate - F32 pumpRPM = getMeasuredDialInPumpRotorSpeed(); - U32 r = getDialInPumpRotorCount(); - U32 rotCnt = CAP( r, DIAL_IN_MAX_ROTOR_COUNT_FOR_WEAR ); - F32 wear = DIAL_IN_FLOW_WEAR_A_TERM * (F32)rotCnt + DIAL_IN_FLOW_WEAR_B_TERM; - F32 Pest = DIAL_IN_FLOW_PEST_A_TERM * ( QdTarget * QdTarget ) + DIAL_IN_FLOW_PEST_B_TERM * QdTarget + DIAL_IN_FLOW_PEST_C_TERM; - F32 alpha = wear * Pest + DIAL_IN_FLOW_A_ZERO; - F32 calculatedFlow = ( alpha * pumpRPM * ML_PER_LITER ) / DIP_REV_PER_LITER; + F32 motorRPM = getMeasuredDialInPumpMCSpeed(); + U32 r = getDialInPumpRotorCount(); + U32 rotCount = CAP( r, DIAL_IN_MAX_ROTOR_COUNT_FOR_WEAR ); + F32 wearFactor = DIAL_IN_FLOW_WEAR_A_TERM * (F32)rotCount + DIAL_IN_FLOW_WEAR_B_TERM; + F32 Pest = DIAL_IN_FLOW_PEST_A_TERM * ( QdTarget * QdTarget ) + DIAL_IN_FLOW_PEST_B_TERM * QdTarget + DIAL_IN_FLOW_PEST_C_TERM; + F32 alphaTerm = wearFactor * Pest + DIAL_IN_FLOW_A_ZERO; - if ( ( QdTarget < DIAL_IN_FLOW_QHIGHTRANSITION ) && ( QdTarget >= DIAL_IN_FLOW_QLOWTRANSITION ) ) + F32 calculatedFlow = ( motorRPM * 2 * DIAL_IN_STROKE_VOLUME/DIAL_IN_GEAR_RATIO ) * alphaTerm; + + if ( ( QdTarget < DIAL_IN_FLOW_QHIGHTRANSITION ) && ( QdTarget > DIAL_IN_FLOW_QLOWTRANSITION ) ) { // use blended flow rate calculation estimatedFlow = ( ( QdTarget - DIAL_IN_FLOW_QLOWTRANSITION ) / ( DIAL_IN_FLOW_QHIGHTRANSITION - DIAL_IN_FLOW_QLOWTRANSITION ) ) * calculatedFlow + ( ( DIAL_IN_FLOW_QHIGHTRANSITION - QdTarget ) / ( DIAL_IN_FLOW_QHIGHTRANSITION - DIAL_IN_FLOW_QLOWTRANSITION ) ) * filteredDialInFlowMeterReading; @@ -811,6 +815,13 @@ } } + // Check the measured flow against estimated flow - / + deltaFlow = 0.5 * estimatedFlow; // 50% estimated flow + if ( deltaFlow < fabs( estimatedFlow - filteredDialInFlowMeterReading ) ) + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_DIAL_IN_FLOW_CHECK_FAILURE, filteredDialInFlowMeterReading, estimatedFlow ); + } + return estimatedFlow; } @@ -826,15 +837,15 @@ *************************************************************************/ static F32 dialysateInPumpPWMFromTargetFlowRate( F32 QdTarget ) { - F32 uncorrectedPWM = DIP_PWM_FROM_ML_PER_MIN( QdTarget ); U32 r = getDialInPumpRotorCount(); - U32 rotCnt = CAP( r, DIAL_IN_MAX_ROTOR_COUNT_FOR_WEAR ); - F32 wear = DIAL_IN_FLOW_WEAR_A_TERM * (F32)rotCnt + DIAL_IN_FLOW_WEAR_B_TERM; - F32 Pest = DIAL_IN_FLOW_PEST_A_TERM * (QdTarget * QdTarget) + DIAL_IN_FLOW_PEST_B_TERM * QdTarget + DIAL_IN_FLOW_PEST_C_TERM; - F32 alpha = wear * Pest + DIAL_IN_FLOW_A_ZERO; - F32 correctedPWM = ( uncorrectedPWM / alpha ); + U32 rotCount = CAP( r, DIAL_IN_MAX_ROTOR_COUNT_FOR_WEAR ); + F32 wearFactor = DIAL_IN_FLOW_WEAR_A_TERM * (F32)rotCount + DIAL_IN_FLOW_WEAR_B_TERM; + F32 Pest = DIAL_IN_FLOW_PEST_A_TERM * ( QdTarget * QdTarget ) + DIAL_IN_FLOW_PEST_B_TERM * QdTarget + DIAL_IN_FLOW_PEST_C_TERM; + F32 alphaTerm = wearFactor * Pest + DIAL_IN_FLOW_A_ZERO; + F32 rpmTgt = QdTarget * DIAL_IN_GEAR_RATIO / ( 2 * DIAL_IN_STROKE_VOLUME * alphaTerm ); + F32 pwmDC = DIP_MOTOR_SPEED_RPM_TO_PWM( rpmTgt ); - return correctedPWM; + return pwmDC; } /*********************************************************************//** @@ -1059,7 +1070,7 @@ payload.measMCSpd = getMeasuredDialInPumpMCSpeed(); payload.measMCCurr = getMeasuredDialInPumpMCCurrent(); payload.pwmDC = dialInPumpPWMDutyCyclePctSet * FRACTION_TO_PERCENT_FACTOR; - payload.flowSigStrength = 0.0; + payload.rotorCount = getDialInPumpRotorCount(); broadcastData( MSG_ID_DIALYSATE_FLOW_DATA, COMM_BUFFER_OUT_CAN_HD_BROADCAST, (U08*)&payload, sizeof( DIALIN_PUMP_STATUS_PAYLOAD_T ) ); dialInFlowDataPublicationTimerCounter = 0; } @@ -1820,14 +1831,14 @@ /*********************************************************************//** * @brief - * The testSetDialInPumpRotorCountOverride function overrides the dialin pump + * The testSetDialysateInPumpRotorCountOverride function overrides the dialin pump * rotor counter value. * @details Inputs: none * @details Outputs: dialInPumpRotorCounter * @param value override dialin pump rotor counter value * @return TRUE if override successful, FALSE if not *************************************************************************/ -BOOL testSetDialInPumpRotorCountOverride( U32 value ) +BOOL testSetDialysateInPumpRotorCountOverride( U32 value ) { BOOL result = FALSE;