Index: firmware/App/Controllers/BloodFlow.c =================================================================== diff -u -rf1c099b79e0825afe54379577454518f7a134a73 -rbd241ef5231a9869adaf7bb5ed166135beb2c0fb --- firmware/App/Controllers/BloodFlow.c (.../BloodFlow.c) (revision f1c099b79e0825afe54379577454518f7a134a73) +++ firmware/App/Controllers/BloodFlow.c (.../BloodFlow.c) (revision bd241ef5231a9869adaf7bb5ed166135beb2c0fb) @@ -93,7 +93,13 @@ #define BP_MAX_CURR_WHEN_RUNNING_MA 2000.0 ///< Motor controller current should not exceed this when pump should be running. #define BP_MAX_CURR_ERROR_DURATION_MS 2000 ///< Motor controller current errors persisting beyond this duration will trigger an alarm. -#define BP_SPEED_ADC_TO_RPM_FACTOR 1.751752 ///< Conversion factor from ADC counts to RPM for blood pump motor. +#define BLOODPUMP_ADC_FULL_SCALE_V 3.0 ///< BP analog signals are 0-3V (while int. ADC ref may be different). +#define BLOODPUMP_ADC_ZERO 1998 ///< Blood pump ADC channel zero offset. + +/// Macro converts 12 bit ADC value to signed 16-bit value. +#define SIGN_FROM_12_BIT_VALUE(v) ( (S16)(v) - (S16)BLOODPUMP_ADC_ZERO ) + +#define BP_SPEED_ADC_TO_RPM_FACTOR 1.751752 ///< Conversion factor from ADC counts to RPM for blood pump motor (3500 RPM/1998 counts). #define BP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.000238 ///< ~42 BP motor RPM = 1% PWM duty cycle. #define BP_CURRENT_ADC_TO_MA_FACTOR 3.002 ///< Conversion factor from ADC counts to mA for blood pump motor. @@ -108,20 +114,16 @@ /// Conversion from PWM duty cycle % to commanded pump motor speed. #define BP_PWM_TO_MOTOR_SPEED_RPM(pwm) ( ((pwm) - BP_PWM_ZERO_OFFSET) * 4000.0 ) -#define BLOODPUMP_ADC_FULL_SCALE_V 3.0 ///< BP analog signals are 0-3V (while int. ADC ref may be different). -#define BLOODPUMP_ADC_ZERO 1998 ///< Blood pump ADC channel zero offset. -/// Macro converts 12 bit ADC value to signed 16-bit value. -#define SIGN_FROM_12_BIT_VALUE(v) ( (S16)(v) - (S16)BLOODPUMP_ADC_ZERO ) - /// Measured blood flow is filtered w/ moving average. #define SIZE_OF_ROLLING_AVG ( ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) * 1 ) #define PUMP_DIR_ERROR_COUNT_MASK 0x3F ///< Bit mask for pump direction error counter. -#define BP_FLOW_ALPHA_Y_INTERCEPT 1.218 ///< Y intercept used for alpha flow coefficient calculation. -#define BP_FLOW_WEAR_A_TERM 0.000000007474 ///< A term used for wear portion of alpha flow coefficient. -#define BP_FLOW_WEAR_B_TERM 0.0006053 ///< B term used for wear portion of alpha flow coefficient. +#define BP_FLOW_ALPHA_Y_INTERCEPT 1.2163 ///< Y intercept used for alpha flow coefficient calculation. +#define BP_FLOW_WEAR_A_TERM 0.000000005665 ///< A term used for wear portion of alpha flow coefficient. +#define BP_FLOW_WEAR_B_TERM 0.0006125 ///< B term used for wear portion of alpha flow coefficient. #define BP_MAX_ROTOR_COUNT_FOR_WEAR 25000 ///< Maximum rotor count for determining wear of the cartridge (negligible affect beyond this threshold). +#define BP_FLOW_CORRECTION_FACTOR 0.9 // TODO - why do we need this /// Enumeration of blood pump controller states. typedef enum BloodPump_States @@ -225,7 +227,7 @@ { U32 i; - stopBloodPump(); + signalBloodPumpHardStop(); setBloodPumpDirection( MOTOR_DIR_FORWARD ); // Zero rolling pump speed average buffer @@ -271,58 +273,64 @@ // Direction change while pump is running is not allowed if ( ( FALSE == isBloodPumpOn ) || ( 0 == flowRate ) || ( dir == bloodPumpDirectionSet ) ) - { + { + S32 dirFlowRate = ( dir == MOTOR_DIR_FORWARD ? (S32)flowRate : (S32)flowRate * -1 ); + + // Don't interrupt pump control unless rate or mode is changing + if ( ( dirFlowRate != targetBloodFlowRate ) || ( mode != bloodPumpControlMode ) ) + { #ifndef NO_PUMP_FLOW_LIMITS - // Verify flow rate - if ( flowRate <= MAX_SET_BLOOD_FLOW_RATE ) + // Verify flow rate + if ( flowRate <= MAX_SET_BLOOD_FLOW_RATE ) #endif - { - resetBloodPumpRPMMovingAverage(); - targetBloodFlowRate = ( dir == MOTOR_DIR_FORWARD ? (S32)flowRate : (S32)flowRate * -1 ); - bloodPumpDirection = dir; - bloodPumpControlMode = mode; - // Set PWM duty cycle target to an estimated initial target to ramp to based on target flow rate - then we will control to flow when ramp completed - bloodPumpPWMDutyCyclePct = BP_PWM_FROM_ML_PER_MIN((F32)flowRate); // ~ 8% per 100 mL/min with a 10% zero offset added in (e.g. 100 mL/min = 8+10 = 18%) - - switch ( bloodPumpState ) { - case BLOOD_PUMP_RAMPING_UP_STATE: // See if we need to reverse direction of ramp - if ( bloodPumpPWMDutyCyclePct < bloodPumpPWMDutyCyclePctSet ) - { - bloodPumpState = BLOOD_PUMP_RAMPING_DOWN_STATE; - } - break; + resetBloodPumpRPMMovingAverage(); + targetBloodFlowRate = dirFlowRate; + bloodPumpDirection = dir; + bloodPumpControlMode = mode; + // Set PWM duty cycle target to an estimated initial target to ramp to based on target flow rate - then we will control to flow when ramp completed + bloodPumpPWMDutyCyclePct = BP_PWM_FROM_ML_PER_MIN((F32)flowRate); // ~ 8% per 100 mL/min with a 10% zero offset added in (e.g. 100 mL/min = 8+10 = 18%) - case BLOOD_PUMP_RAMPING_DOWN_STATE: // See if we need to reverse direction of ramp - if ( bloodPumpPWMDutyCyclePct > bloodPumpPWMDutyCyclePctSet ) - { - bloodPumpState = BLOOD_PUMP_RAMPING_UP_STATE; - } - break; + switch ( bloodPumpState ) + { + case BLOOD_PUMP_RAMPING_UP_STATE: // See if we need to reverse direction of ramp + if ( bloodPumpPWMDutyCyclePct < bloodPumpPWMDutyCyclePctSet ) + { + bloodPumpState = BLOOD_PUMP_RAMPING_DOWN_STATE; + } + break; - case BLOOD_PUMP_CONTROL_TO_TARGET_STATE: // Start ramp to new target in appropriate direction - if ( bloodPumpPWMDutyCyclePctSet > bloodPumpPWMDutyCyclePct ) - { - bloodPumpState = BLOOD_PUMP_RAMPING_DOWN_STATE; - } - else - { - bloodPumpState = BLOOD_PUMP_RAMPING_UP_STATE; - } - break; + case BLOOD_PUMP_RAMPING_DOWN_STATE: // See if we need to reverse direction of ramp + if ( bloodPumpPWMDutyCyclePct > bloodPumpPWMDutyCyclePctSet ) + { + bloodPumpState = BLOOD_PUMP_RAMPING_UP_STATE; + } + break; - default: - // Ok - not all states need to be handled here - break; + case BLOOD_PUMP_CONTROL_TO_TARGET_STATE: // Start ramp to new target in appropriate direction + if ( bloodPumpPWMDutyCyclePctSet > bloodPumpPWMDutyCyclePct ) + { + bloodPumpState = BLOOD_PUMP_RAMPING_DOWN_STATE; + } + else + { + bloodPumpState = BLOOD_PUMP_RAMPING_UP_STATE; + } + break; + + default: + // Ok - not all states need to be handled here + break; + } + result = TRUE; } - result = TRUE; - } #ifndef NO_PUMP_FLOW_LIMITS - else // Requested flow rate too high - { - SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_BLOOD_FLOW_SET_TOO_HIGH, flowRate ) - } -#endif + else // Requested flow rate too high + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_HD_SOFTWARE_FAULT, SW_FAULT_ID_BLOOD_FLOW_SET_TOO_HIGH, flowRate ) + } +#endif + } } return result; @@ -339,17 +347,18 @@ *************************************************************************/ static F32 calcBloodFlow( void ) { +#ifndef PBA_ESTIMATION F32 artPres = getLongFilteredArterialPressure(); +#else + // TODO - temporary test code - remove later + F32 artPres = -200.0; +#endif F32 rotSpd = filteredBloodPumpSpeed / BP_GEAR_RATIO; -#ifndef WORN_OUT_CARTRIDGE U32 r = getBloodPumpRotorCount(); U32 rotCnt = CAP( r, BP_MAX_ROTOR_COUNT_FOR_WEAR ); -#else - U32 rotCnt = BP_MAX_ROTOR_COUNT_FOR_WEAR; -#endif F32 wear = BP_FLOW_WEAR_A_TERM * (F32)rotCnt + BP_FLOW_WEAR_B_TERM; F32 alpha = wear * artPres + BP_FLOW_ALPHA_Y_INTERCEPT; - F32 flow = alpha * BP_ML_PER_ROTOR_REV * rotSpd; + F32 flow = alpha * BP_ML_PER_ROTOR_REV * rotSpd * BP_FLOW_CORRECTION_FACTOR; return flow; } @@ -478,7 +487,11 @@ *************************************************************************/ void resetBloodPumpRotorCount( void ) { +#ifndef WORN_OUT_CARTRIDGE bloodPumpRotorCounter.data = 0; +#else + bloodPumpRotorCounter.data = BP_MAX_ROTOR_COUNT_FOR_WEAR; +#endif } /*********************************************************************//** @@ -639,7 +652,7 @@ // Have we essentially reached zero speed? if ( bloodPumpPWMDutyCyclePctSet < (MAX_BLOOD_PUMP_PWM_STEP_DN_CHANGE + BP_PWM_ZERO_OFFSET) ) { - stopBloodPump(); + signalBloodPumpHardStop(); result = BLOOD_PUMP_OFF_STATE; } // Have we reached end of ramp down? @@ -1042,7 +1055,9 @@ if ( lastBloodPumpDirectionCount != dirErrorCnt ) { lastBloodPumpDirectionCount = dirErrorCnt; +#ifndef DISABLE_PUMP_DIRECTION_CHECKS SET_ALARM_WITH_1_U32_DATA( ALARM_ID_HD_PUMP_DIRECTION_STATUS_ERROR, (U32)HD_PUMP_BLOOD_PUMP ) +#endif } #endif bpMCDir = ( getMeasuredBloodPumpMCSpeed() >= 0.0 ? MOTOR_DIR_FORWARD : MOTOR_DIR_REVERSE ); @@ -1172,23 +1187,6 @@ { SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_BLOOD_FLOW_OUT_OF_RANGE, flow ); } - - // Flow vs. speed check only performed while in treatment mode and while we are in control to target state - if ( ( MODE_TREA == getCurrentOperationMode() ) && ( BLOOD_PUMP_CONTROL_TO_TARGET_STATE == bloodPumpState ) ) - { - F32 speed = getMeasuredBloodPumpSpeed(); - F32 impliedSpeed = ( (F32)targetBloodFlowRate / (F32)ML_PER_LITER ) * BP_REV_PER_LITER * BP_GEAR_RATIO; - F32 delta = fabs( speed - impliedSpeed ); - - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_FLOW_VS_MOTOR_SPEED_CHECK, delta > BP_MAX_FLOW_VS_SPEED_DIFF_RPM ) ) - { - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_BLOOD_PUMP_FLOW_VS_MOTOR_SPEED_CHECK, flow, speed ); - } - } - else - { - resetPersistentAlarmTimer( ALARM_ID_BLOOD_PUMP_FLOW_VS_MOTOR_SPEED_CHECK ); - } #endif }