Index: firmware/App/Controllers/BloodFlow.c =================================================================== diff -u -rbe83f01a4d54cbd0d92b68cb95a15dcbb06a9a51 -r070554b23739bf16ea2bf9528ebabda1ce0ffeb3 --- firmware/App/Controllers/BloodFlow.c (.../BloodFlow.c) (revision be83f01a4d54cbd0d92b68cb95a15dcbb06a9a51) +++ firmware/App/Controllers/BloodFlow.c (.../BloodFlow.c) (revision 070554b23739bf16ea2bf9528ebabda1ce0ffeb3) @@ -23,6 +23,7 @@ #include "FPGA.h" #include "InternalADC.h" #include "SystemCommMessages.h" +#include "TaskGeneral.h" #include "TaskPriority.h" #include "Timers.h" #include "BloodFlow.h" @@ -33,19 +34,22 @@ #define MAX_BLOOD_FLOW_RATE 600 // mL/min -#define MAX_BLOOD_PUMP_PWM_STEP_CHANGE 0.005 // duty cycle TODO - fixed or parameterized or set in motor controller? +#define MAX_BLOOD_PUMP_PWM_STEP_CHANGE 0.02 // duty cycle TODO - fixed or parameterized or set in motor controller? #define MAX_BLOOD_PUMP_PWM_DUTY_CYCLE 0.88 // controller will error if PWM duty cycle > 90%, so set max to 88% #define MIN_BLOOD_PUMP_PWM_DUTY_CYCLE 0.12 // controller will error if PWM duty cycle < 10%, so set min to 12% -#define BP_CONTROL_INTERVAL (200 / TASK_PRIORITY_INTERVAL) // interval (ms/task time) at which the blood pump is controlled -#define BP_P_COEFFICIENT 0.001 // P term for blood pump control -#define BP_I_COEFFICIENT 0.001 // I term for blood pump control -#define BP_MAX_ERROR_SUM 20.0 // for anti-wind-up in I term +#define BP_CONTROL_INTERVAL (500 / TASK_GENERAL_INTERVAL) // interval (ms/task time) at which the blood pump is controlled +#define BP_P_COEFFICIENT 0.0002 // P term for blood pump control +#define BP_I_COEFFICIENT 0.00002 // I term for blood pump control +#define BP_MAX_ERROR_SUM 10.0 // for anti-wind-up in I term +#define BP_MIN_ERROR_SUM -10.0 +#define BP_MAX_PWM_DC_DELTA 0.01 // prevents large steps in PWM duty cycle +#define BP_MIN_PWM_DC_DELTA -0.01 -#define BP_SPEED_ADC_TO_RPM_FACTOR 1.375 // conversion factor from ADC counts to RPM for blood pump motor TODO - set appropriate value -#define BP_CURRENT_ADC_TO_MA_FACTOR 2.65 // conversion factor from ADC counts to mA for blood pump motor TODO - set appropriate value +#define BP_SPEED_ADC_TO_RPM_FACTOR 1.375 // conversion factor from ADC counts to RPM for blood pump motor +#define BP_CURRENT_ADC_TO_MA_FACTOR 2.65 // conversion factor from ADC counts to mA for blood pump motor -#define BP_ML_PER_MIN_TO_PUMP_RPM_FACTOR (80.0 / 1000.0) // 80 pump revolutions = 1 liter or 1,000 mL +#define BP_ML_PER_MIN_TO_PUMP_RPM_FACTOR (124.0 / 1000.0)// 124 pump revolutions = 1 liter or 1,000 mL #define BP_GEAR_RATIO 32.0 // blood pump motor to blood pump gear ratio #define BP_MOTOR_RPM_TO_PWM_DC_FACTOR 0.0003125 // ~32 BP motor RPM = 1% PWM duty cycle #define BP_PWM_ZERO_OFFSET 0.1 // 10% PWM duty cycle = zero speed @@ -55,6 +59,8 @@ #define BLOODPUMP_ADC_MID_PT_BITS ((F32)(INT_ADC_FULL_SCALE_BITS >> 1) * (BLOODPUMP_ADC_FULL_SCALE_V / INT_ADC_REF_V)) #define SIGN_FROM_12_BIT_VALUE(v) ((S16)(v) - (S16)BLOODPUMP_ADC_MID_PT_BITS) +#define SIZE_OF_ROLLING_AVG 100 // flow samples in rolling average calculations + typedef enum BloodPump_States { BLOOD_PUMP_OFF_STATE = 0, @@ -101,6 +107,10 @@ static F32 bpFlowErrorSum = 0.0; // blood flow error sum static U32 bpControlTimerCounter = 0; // determines when to perform control on blood flow +static F32 flowReadings[SIZE_OF_ROLLING_AVG]; // holds flow samples for a rolling average +static U32 flowReadingsIdx = 0; // index for next sample in rolling average array +static F32 flowReadingsTotal = 0.0; // rolling total - used to calc average + static BLOOD_FLOW_SELF_TEST_STATE_T bloodPumpSelfTestState = BLOOD_FLOW_SELF_TEST_STATE_START; // current blood pump self test state static U32 bloodPumpSelfTestTimerCount = 0; // timer counter for blood pump self test @@ -126,8 +136,16 @@ *************************************************************************/ void initBloodFlow( void ) { + U32 i; + stopBloodPump(); setBloodPumpDirection( MOTOR_DIR_FORWARD ); + + // zero rolling flow average buffer + for ( i = 0; i < SIZE_OF_ROLLING_AVG; i++ ) + { + flowReadings[i] = 0.0; + } } /************************************************************************* @@ -213,11 +231,17 @@ { U16 bpRPM = getIntADCReading( INT_ADC_BLOOD_PUMP_SPEED ); U16 bpmA = getIntADCReading( INT_ADC_BLOOD_PUMP_MOTOR_CURRENT ); + F32 bpFlow = getFPGABloodFlow(); // TODO - change to avg. blood flow when available from FPGA - measuredBloodFlowRate.data = getFPGABloodFlow(); adcBloodPumpSpeedRPM.data = (F32)(SIGN_FROM_12_BIT_VALUE(bpRPM)) * BP_SPEED_ADC_TO_RPM_FACTOR; adcBloodPumpCurrentmA.data = (F32)(SIGN_FROM_12_BIT_VALUE(bpmA)) * BP_CURRENT_ADC_TO_MA_FACTOR; + flowReadingsTotal -= flowReadings[flowReadingsIdx]; + flowReadings[flowReadingsIdx] = bpFlow; + flowReadingsTotal += bpFlow; + flowReadingsIdx = INC_WRAP( flowReadingsIdx, 0, SIZE_OF_ROLLING_AVG-1 ); + measuredBloodFlowRate.data = flowReadingsTotal / (F32)SIZE_OF_ROLLING_AVG; + // publish blood flow data on interval if ( ++bloodFlowDataPublicationTimerCounter > getPublishBloodFlowDataInterval() ) { @@ -226,10 +250,10 @@ F32 measSpd = getMeasuredBloodPumpSpeed(); F32 measCurr = getMeasuredBloodPumpCurrent(); #ifdef DEBUG_ENABLED - F32 tmp = getFPGADialysateFlow(); + S32 pwm = (S32)(100.0*bloodPumpPWMDutyCyclePctSet); char debugFlowStr[256]; - sprintf( debugFlowStr, "Target Flow:%5d, Meas. Flow:%5d, Speed:%5d RPM, Current:%5d mA, PWM%:%5d \n", flowStPt, (S32)measFlow, (S32)measSpd, (S32)measCurr, (S32)bloodPumpPWMDutyCyclePctSet ); + sprintf( debugFlowStr, "Target Flow:%5d, Meas. Flow:%5d, Speed:%5d RPM, Current:%5d mA, PWM:%5d \n", flowStPt, (S32)measFlow, (S32)measSpd, (S32)measCurr, pwm ); sendDebugData( (U08*)debugFlowStr, strlen(debugFlowStr) ); #endif broadcastBloodFlowData( flowStPt, measFlow, measSpd, measCurr ); @@ -398,12 +422,21 @@ if ( ++bpControlTimerCounter >= BP_CONTROL_INTERVAL ) { // compute P term - bpFlowError = tgtFlow - actFlow; + if ( MOTOR_DIR_FORWARD == bloodPumpDirectionSet ) + { + bpFlowError = tgtFlow - actFlow; + } + else + { + bpFlowError = (tgtFlow * -1.0) - (actFlow * -1.0); + } pTerm = bpFlowError * BP_P_COEFFICIENT; + pTerm = RANGE( pTerm, BP_MIN_PWM_DC_DELTA, BP_MAX_PWM_DC_DELTA ); // compute I term bpFlowErrorSum += bpFlowError; - iTerm = RANGE( bpFlowErrorSum, BP_MAX_ERROR_SUM * -1.0, BP_MAX_ERROR_SUM ); + iTerm = RANGE( bpFlowErrorSum, BP_MIN_ERROR_SUM, BP_MAX_ERROR_SUM ); iTerm *= BP_I_COEFFICIENT; + iTerm = RANGE( iTerm, BP_MIN_PWM_DC_DELTA, BP_MAX_PWM_DC_DELTA ); // compute new PWM duty cycle % for blood pump motor newPWM = bloodPumpPWMDutyCyclePctSet + pTerm + iTerm; newPWM = RANGE( newPWM, MIN_BLOOD_PUMP_PWM_DUTY_CYCLE, MAX_BLOOD_PUMP_PWM_DUTY_CYCLE );