Index: firmware/App/Controllers/BloodFlow.c =================================================================== diff -u -rabbad386f4cc94f315300dffef321fe8c03fbd52 -r8466e63f95f65a3ffb18c3af85ac99328e41167b --- firmware/App/Controllers/BloodFlow.c (.../BloodFlow.c) (revision abbad386f4cc94f315300dffef321fe8c03fbd52) +++ firmware/App/Controllers/BloodFlow.c (.../BloodFlow.c) (revision 8466e63f95f65a3ffb18c3af85ac99328e41167b) @@ -49,10 +49,11 @@ #define MAX_BLOOD_PUMP_PWM_DUTY_CYCLE 0.89 ///< Controller will error if PWM duty cycle > 90%, so set max to 89% #define MIN_BLOOD_PUMP_PWM_DUTY_CYCLE 0.10 ///< Controller will error if PWM duty cycle < 10%, so set min to 10% +#define BP_CONTROL_INTERVAL_SEC 10 ///< Blood pump control interval (in seconds). /// Interval (ms/task time) at which the blood pump is controlled. -static const U32 BP_CONTROL_INTERVAL = ( 10000 / TASK_GENERAL_INTERVAL ); -#define BP_P_COEFFICIENT 0.00035 ///< P term for blood pump control -#define BP_I_COEFFICIENT 0.00035 ///< I term for blood pump control +static const U32 BP_CONTROL_INTERVAL = ( BP_CONTROL_INTERVAL_SEC * MS_PER_SECOND / TASK_GENERAL_INTERVAL ); +#define BP_P_COEFFICIENT 0.0001 ///< P term for blood pump control +#define BP_I_COEFFICIENT 0.00075 ///< I term for blood pump control #define BP_HOME_RATE 100 ///< Target pump speed (in estimate mL/min) for homing. #define BP_HOME_TIMEOUT_MS 10000 ///< Maximum time allowed for homing to complete (in ms). @@ -61,7 +62,9 @@ /// Number of hall sensor counts kept in buffer to hold last 1 second of count data. #define BP_SPEED_CALC_BUFFER_LEN ( MS_PER_SECOND / BP_SPEED_CALC_INTERVAL / TASK_PRIORITY_INTERVAL ) #define BP_MAX_ROTOR_SPEED_RPM 100.0 ///< Maximum rotor speed allowed for blood pump. - + +#define BP_MAX_FLOW_RATE 1320.0 ///< Maximum measured BP flow rate allowed. +#define BP_MIN_FLOW_RATE -1320.0 ///< Minimum measured BP flow rate allowed. #define BP_MAX_FLOW_VS_SPEED_DIFF_RPM 200.0 ///< Maximum difference between measured speed and speed implied by measured flow. #define BP_MAX_MOTOR_SPEED_WHILE_OFF_RPM 100.0 ///< Maximum motor speed (RPM) while motor is commanded off. #define BP_MAX_ROTOR_VS_MOTOR_DIFF_RPM 5.0 ///< Maximum difference in speed between motor and rotor (in rotor RPM). @@ -78,26 +81,25 @@ static const U32 BP_DIRECTION_ERROR_PERSIST = ( 250 ); /// Persist time period blood pump rotor speed too fast error condition. static const U32 BP_MAX_ROTOR_SPEED_ERROR_PERSIST = ( 1 * MS_PER_SECOND ); +/// Persist time (task intervals) blood flow rate out of range error condition. +static const U32 BP_MAX_FLOW_RATE_OUT_OF_RANGE_PERSIST = ((1 * MS_PER_SECOND) / TASK_PRIORITY_INTERVAL); #define BP_MAX_CURR_WHEN_STOPPED_MA 150.0 ///< Motor controller current should not exceed this when pump should be stopped #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 -#ifndef V2_0_SYSTEM - #define BP_SPEED_ADC_TO_RPM_FACTOR 1.751752 ///< Conversion factor from ADC counts to RPM for blood pump motor - #define BP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.00025 ///< ~40 BP motor RPM = 1% PWM duty cycle -#else - #define BP_SPEED_ADC_TO_RPM_FACTOR 1.280938 ///< Conversion factor from ADC counts to RPM for blood pump motor - #define BP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.0003125 ///< ~32 BP motor RPM = 1% PWM duty cycle -#endif +#define BP_SPEED_ADC_TO_RPM_FACTOR 1.751752 ///< Conversion factor from ADC counts to RPM for blood pump motor +#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 #define BP_REV_PER_LITER 150.0 ///< Rotor revolutions per liter #define BP_ML_PER_MIN_TO_PUMP_RPM_FACTOR ( BP_REV_PER_LITER / ML_PER_LITER ) ///< Conversion factor from mL/min to motor RPM. #define BP_GEAR_RATIO 32.0 ///< Blood pump motor to blood pump gear ratio #define BP_PWM_ZERO_OFFSET 0.1 ///< 10% PWM duty cycle = zero speed -/// Conversion factor from mL/min to estimated PWM duty cycle %. -#define BP_PWM_FROM_ML_PER_MIN(rate) ( (rate) * BP_ML_PER_MIN_TO_PUMP_RPM_FACTOR * BP_GEAR_RATIO * BP_MOTOR_RPM_TO_PWM_DC_FACTOR + BP_PWM_ZERO_OFFSET ) +/// Conversion macro from mL/min to estimated PWM duty cycle %. +#define BP_PWM_FROM_ML_PER_MIN(rate) ( (rate) * BP_ML_PER_MIN_TO_PUMP_RPM_FACTOR * BP_GEAR_RATIO * BP_MOTOR_RPM_TO_PWM_DC_FACTOR + BP_PWM_ZERO_OFFSET ) +/// 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. @@ -107,7 +109,7 @@ #define SIZE_OF_ROLLING_AVG ( ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) * 10 ) /// Blood flow sensor signal strength low alarm persistence. -#define FLOW_SIG_STRGTH_ALARM_PERSIST ( 5 * MS_PER_SECOND ) +#define FLOW_SIG_STRGTH_ALARM_PERSIST ( BP_CONTROL_INTERVAL_SEC * MS_PER_SECOND ) #define MIN_FLOW_SIG_STRENGTH 0.9 ///< Minimum flow sensor signal strength (90%). /// Blood flow fast read timeout alarm persistence. @@ -216,7 +218,6 @@ static void checkBloodPumpMCCurrent( void ); static void checkBloodFlowSensorSignalStrength( void ); static BOOL processCalibrationData( void ); -static U32 getPublishBloodFlowDataInterval( void ); /*********************************************************************//** * @brief @@ -254,11 +255,12 @@ initPersistentAlarm( ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_CHECK, 0, BP_ROTOR_SPEED_ERROR_PERSIST ); initPersistentAlarm( ALARM_ID_BLOOD_PUMP_MC_DIRECTION_CHECK, 0, BP_DIRECTION_ERROR_PERSIST ); initPersistentAlarm( ALARM_ID_BLOOD_PUMP_ROTOR_SPEED_TOO_HIGH, 0, BP_MAX_ROTOR_SPEED_ERROR_PERSIST ); - initPersistentAlarm( ALARM_ID_BLOOD_FLOW_SIGNAL_STRENGTH_TOO_LOW, 0, FLOW_SIG_STRGTH_ALARM_PERSIST ); initPersistentAlarm( ALARM_ID_BLOOD_PUMP_MC_CURRENT_CHECK, 0, BP_MAX_CURR_ERROR_DURATION_MS ); + initPersistentAlarm( ALARM_ID_BLOOD_FLOW_SIGNAL_STRENGTH_TOO_LOW, FLOW_SIG_STRGTH_ALARM_PERSIST, FLOW_SIG_STRGTH_ALARM_PERSIST ); initPersistentAlarm( ALARM_ID_HD_BP_FLOW_READ_TIMEOUT_ERROR, 0, BLOOD_FLOW_FAST_READ_TO_PERSIST ); initPersistentAlarm( ALARM_ID_HD_BP_FLOW_SLOW_READ_TIMEOUT_ERROR, 0, BLOOD_FLOW_SLOW_READ_TO_PERSIST ); initPersistentAlarm( ALARM_ID_HD_BP_FLOW_SENSOR_ERROR, 0, BLOOD_FLOW_COMM_ERROR_PERSIST ); + initPersistentAlarm( ALARM_ID_HD_BLOOD_FLOW_OUT_OF_RANGE, 0, BP_MAX_FLOW_RATE_OUT_OF_RANGE_PERSIST ); } /*********************************************************************//** @@ -279,8 +281,10 @@ // Direction change while pump is running is not allowed if ( ( FALSE == isBloodPumpOn ) || ( 0 == flowRate ) || ( dir == bloodPumpDirectionSet ) ) { +#ifndef NO_PUMP_FLOW_LIMITS // Verify flow rate - if ( flowRate <= MAX_BLOOD_FLOW_RATE ) + if ( flowRate <= MAX_SET_BLOOD_FLOW_RATE ) +#endif { resetBloodFlowMovingAverage(); targetBloodFlowRate = ( dir == MOTOR_DIR_FORWARD ? (S32)flowRate : (S32)flowRate * -1 ); @@ -319,10 +323,12 @@ } 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 } return result; @@ -608,14 +614,11 @@ else if ( bloodPumpPWMDutyCyclePctSet >= bloodPumpPWMDutyCyclePct ) { resetBloodFlowMovingAverage(); + bloodPumpPWMDutyCyclePctSet = bloodPumpPWMDutyCyclePct; resetPIController( PI_CONTROLLER_ID_BLOOD_FLOW, bloodPumpPWMDutyCyclePctSet ); bloodPumpControlModeSet = bloodPumpControlMode; - // If open loop mode, set PWM to requested duty cycle where it will stay during control state - if ( bloodPumpControlModeSet == PUMP_CONTROL_MODE_OPEN_LOOP ) - { - bloodPumpPWMDutyCyclePctSet = bloodPumpPWMDutyCyclePct; - setBloodPumpControlSignalPWM( bloodPumpPWMDutyCyclePct ); - } + setBloodPumpControlSignalPWM( bloodPumpPWMDutyCyclePctSet ); + bpControlTimerCounter = 0; result = BLOOD_PUMP_CONTROL_TO_TARGET_STATE; } // Continue ramp up @@ -650,14 +653,11 @@ else if ( bloodPumpPWMDutyCyclePctSet <= bloodPumpPWMDutyCyclePct ) { resetBloodFlowMovingAverage(); + bloodPumpPWMDutyCyclePctSet = bloodPumpPWMDutyCyclePct; resetPIController( PI_CONTROLLER_ID_BLOOD_FLOW, bloodPumpPWMDutyCyclePctSet ); bloodPumpControlModeSet = bloodPumpControlMode; - // If open loop mode, set PWM to requested duty cycle where it will stay during control state - if ( bloodPumpControlModeSet == PUMP_CONTROL_MODE_OPEN_LOOP ) - { - bloodPumpPWMDutyCyclePctSet = bloodPumpPWMDutyCyclePct; - setBloodPumpControlSignalPWM( bloodPumpPWMDutyCyclePct ); - } + setBloodPumpControlSignalPWM( bloodPumpPWMDutyCyclePctSet ); + bpControlTimerCounter = 0; result = BLOOD_PUMP_CONTROL_TO_TARGET_STATE; } // Continue ramp down @@ -725,7 +725,7 @@ static void stopBloodPump( void ) { isBloodPumpOn = FALSE; - bloodPumpPWMDutyCyclePctSet = 0.0; + bloodPumpPWMDutyCyclePctSet = BP_PWM_ZERO_OFFSET; etpwmSetCmpA( etpwmREG1, 0 ); SET_BP_STOP(); } @@ -773,33 +773,13 @@ /*********************************************************************//** * @brief - * The getPublishBloodFlowDataInterval function gets the blood flow data - * publication interval. - * @details Inputs: bloodFlowDataPublishInterval - * @details Outputs: none - * @return the current blood flow data publication interval (in task intervals). - *************************************************************************/ -U32 getPublishBloodFlowDataInterval( void ) -{ - U32 result = bloodFlowDataPublishInterval.data; - - if ( OVERRIDE_KEY == bloodFlowDataPublishInterval.override ) - { - result = bloodFlowDataPublishInterval.ovData; - } - - return result; -} - -/*********************************************************************//** - * @brief * The getMeasuredBloodFlowRate function gets the measured blood flow * rate. * @details Inputs: measuredBloodFlowRate * @details Outputs: none * @return the current blood flow rate (in mL/min). *************************************************************************/ -F32 getMeasuredBloodFlowRate( void ) +F32 getMeasuredBloodFlowRate( void ) { F32 result = measuredBloodFlowRate.data; @@ -839,7 +819,7 @@ * @details Outputs: none * @return the current blood flow rate (in mL/min). *************************************************************************/ -F32 getMeasuredBloodPumpRotorSpeed( void ) +F32 getMeasuredBloodPumpRotorSpeed( void ) { F32 result = bloodPumpRotorSpeedRPM.data; @@ -859,7 +839,7 @@ * @details Outputs: none * @return the current blood flow rate (in mL/min). *************************************************************************/ -F32 getMeasuredBloodPumpSpeed( void ) +F32 getMeasuredBloodPumpSpeed( void ) { F32 result = bloodPumpSpeedRPM.data; @@ -879,7 +859,7 @@ * @details Outputs: none * @return the current blood pump speed (in RPM). *************************************************************************/ -F32 getMeasuredBloodPumpMCSpeed( void ) +F32 getMeasuredBloodPumpMCSpeed( void ) { F32 result = adcBloodPumpMCSpeedRPM.data; @@ -899,7 +879,7 @@ * @details Outputs: none * @return the current blood pump current (in mA). *************************************************************************/ -F32 getMeasuredBloodPumpMCCurrent( void ) +F32 getMeasuredBloodPumpMCCurrent( void ) { F32 result = adcBloodPumpMCCurrentmA.data; @@ -923,7 +903,7 @@ static void publishBloodFlowData( void ) { // Publish blood flow data on interval - if ( ++bloodFlowDataPublicationTimerCounter >= getPublishBloodFlowDataInterval() ) + if ( ++bloodFlowDataPublicationTimerCounter >= getU32OverrideValue( &bloodFlowDataPublishInterval ) ) { BLOOD_PUMP_STATUS_PAYLOAD_T payload; @@ -1122,30 +1102,33 @@ static void checkBloodPumpSpeeds( void ) { F32 measMotorSpeed = fabs( getMeasuredBloodPumpSpeed() ); - S32 cmdRate = targetBloodFlowRate; + F32 measMCMotorSpeed = fabs( getMeasuredBloodPumpMCSpeed() ); // Check for pump running while commanded off - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_OFF_CHECK, ( 0 == cmdRate ) && ( measMotorSpeed > BP_MAX_MOTOR_SPEED_WHILE_OFF_RPM ) ) ) + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_OFF_CHECK, ( 0 == targetBloodFlowRate ) && ( measMotorSpeed > BP_MAX_MOTOR_SPEED_WHILE_OFF_RPM ) ) ) { #ifndef DISABLE_PUMP_SPEED_CHECKS SET_ALARM_WITH_1_F32_DATA( ALARM_ID_BLOOD_PUMP_OFF_CHECK, measMotorSpeed ); activateSafetyShutdown(); #endif } + // Checks that only occur when pump is running (and beyond ramp). if ( BLOOD_PUMP_CONTROL_TO_TARGET_STATE == bloodPumpState ) { - F32 cmdMotorSpeed = ( (F32)cmdRate / (F32)ML_PER_LITER ) * BP_REV_PER_LITER * BP_GEAR_RATIO; - F32 deltaMotorSpeed = fabs( measMotorSpeed - cmdMotorSpeed ); + F32 cmdMotorSpeed = BP_PWM_TO_MOTOR_SPEED_RPM( bloodPumpPWMDutyCyclePctSet ); + F32 deltaMotorSpeed = fabs( measMotorSpeed - cmdMotorSpeed ); + F32 deltaMCMotorSpeed = fabs( measMCMotorSpeed - cmdMotorSpeed ); F32 measRotorSpeed = getMeasuredBloodPumpRotorSpeed(); F32 measMotorSpeedInRotorRPM = measMotorSpeed / BP_GEAR_RATIO; F32 deltaRotorSpeed = fabs( measRotorSpeed - measMotorSpeedInRotorRPM ); // Check measured motor speed vs. commanded motor speed while controlling to target - if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_MOTOR_SPEED_CHECK, deltaMotorSpeed > BP_MAX_MOTOR_SPEED_ERROR_RPM ) ) + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_BLOOD_PUMP_MOTOR_SPEED_CHECK, + ( deltaMotorSpeed > BP_MAX_MOTOR_SPEED_ERROR_RPM ) || ( deltaMCMotorSpeed > BP_MAX_MOTOR_SPEED_ERROR_RPM ) ) ) { #ifndef DISABLE_PUMP_SPEED_CHECKS - SET_ALARM_WITH_2_F32_DATA( ALARM_ID_BLOOD_PUMP_MOTOR_SPEED_CHECK, (F32)cmdRate, measMotorSpeed ); + SET_ALARM_WITH_2_F32_DATA( ALARM_ID_BLOOD_PUMP_MOTOR_SPEED_CHECK, cmdMotorSpeed, measMotorSpeed ); #endif } @@ -1176,10 +1159,19 @@ *************************************************************************/ static void checkBloodPumpFlowAgainstSpeed( void ) { - // Check only performed while in treatment mode and while we are in control to target state + F32 flow = getMeasuredBloodFlowRate(); + + // Range check on measure BP flow rate. +#ifndef DISABLE_PUMP_FLOW_CHECKS + if ( TRUE == isPersistentAlarmTriggered( ALARM_ID_HD_BLOOD_FLOW_OUT_OF_RANGE, ( flow > BP_MAX_FLOW_RATE ) || ( flow < BP_MIN_FLOW_RATE ) ) ) + { + SET_ALARM_WITH_1_F32_DATA( ALARM_ID_HD_BLOOD_FLOW_OUT_OF_RANGE, flow ); + } +#endif + + // 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 flow = getMeasuredBloodFlowRate(); F32 speed = getMeasuredBloodPumpSpeed(); F32 impliedSpeed = ( flow / (F32)ML_PER_LITER ) * BP_REV_PER_LITER * BP_GEAR_RATIO; F32 delta = fabs( speed - impliedSpeed ); @@ -1334,6 +1326,7 @@ * TEST SUPPORT FUNCTIONS *************************************************************************/ + /*********************************************************************//** * @brief * The testSetBloodFlowDataPublishIntervalOverride function overrides the