Index: firmware/App/Controllers/Heaters.c =================================================================== diff -u -rc52b833962efeed9be0616e3981d8a67ce6ae2d7 -rf14371c9c14b461a50d7b08336e2e5fbed16f360 --- firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision c52b833962efeed9be0616e3981d8a67ce6ae2d7) +++ firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision f14371c9c14b461a50d7b08336e2e5fbed16f360) @@ -40,33 +40,17 @@ */ // ********** private definitions ********** -#ifndef __ALPHA_AO_VER__ #define AC_HEATER_TX_MAX_DUTY_CYCLE 0.50F ///< AC Heater Treatement mode max duty cycle (50% of 1400W : 700W ) or ON state #define AC_HEATER_HEAT_MAX_DUTY_CYCLE 0.70F ///< AC Heater heat disinfect mode max duty cycle (70% of 1400W : 980W ) or ON state #define AC_HEATER_MAX_DUTY_CYCLE 1.0F ///< AC Heater max duty cycle (100.0%) or ON state #define DC_HEATER_MAX_DUTY_CYCLE 1.0F ///< DC Heater max duty cycle (100%) or ON state #define HEATERS_MIN_DUTY_CYCLE 0.0F ///< Heaters minimum duty cycle (0.00%) or OFF state -#else -#define HEATERS_MAX_DUTY_CYCLE 1.0F ///< Heaters max duty cycle (100%) or ON state -#define HEATERS_MIN_DUTY_CYCLE 0.0F ///< Heaters minimum duty cycle (0.00%) or OFF state -#define D5_HEAT_ON 1.0F ///< Primary heater ON control -#define HEATERS_DISINFECT_DUTY_CYCLE 0.80F ///< Heaters disinfect cycle. -#define HEATERS_DISINFECT_TRANSFER_DUTY_CYCLE 0.60F ///< Heaters disinfect transfer duty cycle. -#endif #define HEATERS_DISINFECT_TEMPERATURE_DRIFT_C 3.0F ///< Heaters disinfect temperature drift in C. #define HEATERS_ZERO_DELTA_TEMP_C 0.0F ///< Heaters zero delta temperature in C. #define HEATERS_DUTY_CYCLE_CONVERSION_FACTOR 100.0F ///< Heaters duty cycle 0: OFF, 100: 100% duty cycle. -#define D45_HEAT_GAIN 10.0F ///< Trimmer heater gain for testing. -//Testing : PI Controller Gain without FF -//#define D5_HEAT_TX_P_COEFFICIENT 0.20F ///< P Term for AC primary heater control during treatment mode. -//#define D5_HEAT_TX_I_COEFFICIENT 0.002F ///< I Term for AC primary heater control during treatment mode. +#define HEATERS_ZERO_EFFICIENCY 0.0F ///< Zero heater efficiency -//Testing : PI Controller gain with FF -//#define D5_HEAT_TX_P_COEFFICIENT 0.04F ///< P Term for AC primary heater control during treatment mode. -//#define D5_HEAT_TX_I_COEFFICIENT 0.0007F ///< I Term for AC primary heater control during treatment mode. #define D5_HEAT_TX_INIT_FEED_FORWARD 0.0F ///< Initial Feed forward term for heater control - -// PI controller gain with initial Open loop and FF later #define D5_HEAT_TX_P_COEFFICIENT 0.015F ///< P Term for AC primary heater control during treatment mode. #define D5_HEAT_TX_I_COEFFICIENT 0.0021F ///< I Term for AC primary heater control during treatment mode. @@ -75,9 +59,6 @@ #define D45_HEAT_TX_INIT_FEED_FORWARD 0.0F ///< Initial Feed forward term for heater control #define HEATERS_DATA_PUBLISH_INTERVAL ( MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Heaters data publish interval. -//Testing -//#define HEATERS_DATA_PUBLISH_INTERVAL ( 250 / TASK_PRIORITY_INTERVAL ) ///< Heaters data publish interval. - #define HEATER_TEMP_CONTROL_TRANSFER 1.0F ///< Primary Heater temperature difference to switch to control function #define HEATER_TARGET_TEMPERATURE_MIN 10.0F ///< Minimum allowed target temperature for the heaters. #define HEATER_TARGET_TEMPERATURE_MAX 90.0F ///< Maximum allowed target temperature for the heaters. @@ -98,8 +79,9 @@ #define MAX_INLET_FLOW_LPM ( 600.0F / 1000.0F ) ///< Maximum inlet flow to hydraulics chamber from FP #define LITER_IN_ML 1000.0F ///< Liter in milliliter units #define TRIMMER_HEATER_MAX_PWR_WATTS 120.0F ///< Maximum power supplied to trimmer heater -#define AC_HEATER_PWM_PERIOD 10000 ///< PWM period for 60Hz AC ( in 10us resoultion), 1/10Hz = 1000000us/10us = 10000. +#define AC_HEATER_PWM_PERIOD 10000 ///< PWM period 100 ms( in 10us resoultion), 1/10Hz = 1000000us/10us = 10000. #define AC_HEATER_EFFICIENCY 0.90F ///< Approximated AC heater efficiency to be used in energy calcualtions. +#define DC_HEATER_EFFICIENCY 1.0F ///< DC heater efficiency #define DATA_PUBLISH_COUNTER_START_COUNT 70 ///< Data publish counter start count. @@ -136,7 +118,6 @@ static const F32 WATER_SPECIFIC_HEAT_DIVIDED_BY_MINUTES = 4184.0F / (F32)SEC_PER_MIN; ///< Water specific heat in J/KgC / 60. static OVERRIDE_U32_T heatersDataPublishInterval = { HEATERS_DATA_PUBLISH_INTERVAL, HEATERS_DATA_PUBLISH_INTERVAL, 0, 0 }; ///< Heaters data publish time interval. static F32 convertDC; ///< AC Heater converted duty cycle -static F32 heaterEfficiency[ NUM_OF_DD_HEATERS ]; ///< AC Heater efficiency to be used in energy calculations. static BOOL startupHeaterControl; ///< First time control with the energy equation. //For testing @@ -146,9 +127,10 @@ // ********** private function prototypes ********** static HEATERS_STATE_T handleHeaterStateOff( DD_HEATERS_T heater ); -static HEATERS_STATE_T handleHeaterStateInitialControlSetup( DD_HEATERS_T heater ); +static HEATERS_STATE_T handleHeaterStateRampToTarget( DD_HEATERS_T heater ); static HEATERS_STATE_T handleHeaterStateControlToTarget( DD_HEATERS_T heater ); static HEATERS_STATE_T handleHeaterStateControlToDisinfectTarget( DD_HEATERS_T heater ); +static F32 calculateDutyCycle( F32 flowrate, F32 deltaTemp, F32 power, F32 efficiency, F32 min, F32 max ); static void setHeaterControl( DD_HEATERS_T heater ); static F32 getHeaterControl( DD_HEATERS_T heater ); @@ -166,13 +148,13 @@ void initHeaters( void ) { DD_HEATERS_T heater; - dataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; - #ifdef __HEATERS_DEBUG__ U32 i; #endif -#ifndef __ALPHA_AO_VER__ + // Assign start count + dataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; + //Enable PWM based heater control setFPGAD5HeaterPWMEnableControl( TRUE ); @@ -190,19 +172,14 @@ //Initialize Converted Duty cycle convertDC = 0.0F; - controlInterval[ D5_HEAT ] = D5_HEAT_CONTROL_INTERVAL_COUNT; controlInterval[ D45_HEAT ] = D45_HEAT_CONTROL_INTERVAL_COUNT; // Assign counter close to the target period heatersStatus[ D5_HEAT ].controlIntervalCounter = 590; heatersStatus[ D45_HEAT ].controlIntervalCounter = 0; + startupHeaterControl = TRUE; - heaterEfficiency[ D5_HEAT ] = AC_HEATER_EFFICIENCY; - startupHeaterControl = TRUE; - -#endif - for ( heater = DD_HEATERS_FIRST; heater < NUM_OF_DD_HEATERS; heater++ ) { targetTempC[ heater ].data = 0.0F; @@ -332,14 +309,14 @@ /*********************************************************************//** * @brief - * The signalHeaterControl function updates heater control based on - * the latest treatment paratmeter change + * The signalHeaterControlOnQDUpdate function updates heater control based on + * the latest treatment paratmeter (Dialysate Flow rate) change * @details \b Inputs: heatersStatus * @details \b Outputs: none * @param heater: heater ID to update the heater control. * @return none *************************************************************************/ -void signalHeaterControl( DD_HEATERS_T heater ) +void signalHeaterControlOnQDUpdate( DD_HEATERS_T heater ) { if ( D5_HEAT == heater ) { @@ -390,10 +367,13 @@ { if( heater < NUM_OF_DD_HEATERS ) { - heatersStatus[ heater ].startHeaterSignal = FALSE; - heatersStatus[ heater ].heaterOnState = FALSE; - control[ heater ].data = HEATERS_MIN_DUTY_CYCLE; - heatersStatus[ heater ].state = HEATER_EXEC_STATE_OFF; + heatersStatus[ heater ].startHeaterSignal = FALSE; + heatersStatus[ heater ].heaterOnState = FALSE; + control[ heater ].data = HEATERS_MIN_DUTY_CYCLE; + heatersStatus[ heater ].state = HEATER_EXEC_STATE_OFF; + heatersStatus[ D5_HEAT ].controlIntervalCounter = 590; + heatersStatus[ D45_HEAT ].controlIntervalCounter = 0; + startupHeaterControl = TRUE; // update duty cycle setHeaterControl( heater ); @@ -425,8 +405,8 @@ heatersStatus[ heater ].state = handleHeaterStateOff( heater ); break; - case HEATER_EXEC_STATE_INITIAL_SETUP: - heatersStatus[ heater ].state = handleHeaterStateInitialControlSetup( heater ); + case HEATER_EXEC_STATE_RAMP_TO_TARGET: + heatersStatus[ heater ].state = handleHeaterStateRampToTarget( heater ); break; case HEATER_EXEC_STATE_CONTROL_TO_TARGET: @@ -527,24 +507,24 @@ heatersStatus[ heater ].startHeaterSignal = FALSE; // proceed to setup state - state = HEATER_EXEC_STATE_INITIAL_SETUP; + state = HEATER_EXEC_STATE_RAMP_TO_TARGET; } return state; } /*********************************************************************//** * @brief - * The handleHeaterStateInitialControlSetup function handles the given heaters' + * The handleHeaterStateRampToTarget function handles the given heaters' * control while they are ramping to target temperature. * @details \b Inputs: heaterStatus * @details \b Outputs: heaterStatus * @param heater: The heater Id to handle the initial setup control for heater. * @return next state of the state machine *************************************************************************/ -static HEATERS_STATE_T handleHeaterStateInitialControlSetup( DD_HEATERS_T heater ) +static HEATERS_STATE_T handleHeaterStateRampToTarget( DD_HEATERS_T heater ) { - HEATERS_STATE_T state = HEATER_EXEC_STATE_INITIAL_SETUP; + HEATERS_STATE_T state = HEATER_EXEC_STATE_RAMP_TO_TARGET; F32 ctrl = 0.0F; DD_OP_MODE_T opMode = getCurrentOperationMode(); F32 measuredTemperature = 0.0F; @@ -556,7 +536,6 @@ if ( DD_MODE_HEAT != opMode ) { -#ifndef __ALPHA_AO_VER__ F32 deltaTempC = targetTemperature - measuredTemperature; F32 capDeltaTempC = MAX( deltaTempC, HEATERS_ZERO_DELTA_TEMP_C ); @@ -570,11 +549,6 @@ // Start Open loop control with max power control[ heater ].data = AC_HEATER_TX_MAX_DUTY_CYCLE; } -#else - // Assign initial value - control[ heater ].data = D5_HEAT_ON; - state = HEATER_EXEC_STATE_CONTROL_TO_TARGET; -#endif } else { @@ -588,20 +562,15 @@ if ( DD_MODE_HEAT != opMode ) { -#ifndef __ALPHA_AO_VER__ F32 deltaTempC = targetTemperature - measuredTemperature; F32 capDeltaTempC = MAX( deltaTempC, HEATERS_ZERO_DELTA_TEMP_C ); F32 flowrate = getTDDialysateFlowrate() / LITER_IN_ML ; - F32 dutyCycle = ( WATER_SPECIFIC_HEAT_DIVIDED_BY_MINUTES * capDeltaTempC * flowrate ) / TRIMMER_HEATER_MAX_PWR_WATTS; - dutyCycle = MIN( dutyCycle, DC_HEATER_MAX_DUTY_CYCLE ); - dutyCycle = MAX( dutyCycle, HEATERS_MIN_DUTY_CYCLE ); + F32 dutyCycle = calculateDutyCycle( flowrate, capDeltaTempC, TRIMMER_HEATER_MAX_PWR_WATTS, DC_HEATER_EFFICIENCY, + HEATERS_MIN_DUTY_CYCLE, DC_HEATER_MAX_DUTY_CYCLE ); control[ heater ].data = dutyCycle; resetPIController( PI_CONTROLLER_ID_D45_HEAT, dutyCycle, D45_HEAT_TX_INIT_FEED_FORWARD ); -#else - // Assign initial value - ctrl = ( ( targetTemperature / HEATER_TARGET_TEMPERATURE_MAX ) * HEATERS_DUTY_CYCLE_CONVERSION_FACTOR ) + FLOAT_TO_INT_ROUNDUP_OFFSET; -#endif + state = HEATER_EXEC_STATE_CONTROL_TO_TARGET; } else @@ -645,7 +614,6 @@ // Inlet temperature post heat exchanger inletTemperature = getTemperatureValue( X6_TEMP ); -#ifndef __ALPHA_AO_VER__ if ( TRUE == startupHeaterControl ) { startupHeaterControl = FALSE; @@ -654,31 +622,16 @@ F32 deltaTempC = 10.0F; // Hard code for testing, later remove it. F32 capDeltaTempC = MAX( deltaTempC, HEATERS_ZERO_DELTA_TEMP_C ); F32 flowrate = getTDDialysateFlowrate() / LITER_IN_ML ; - F32 feedforward = ( WATER_SPECIFIC_HEAT_DIVIDED_BY_MINUTES * capDeltaTempC * flowrate ) / PRIMARY_HEATER_MAX_PWR_WATTS; - feedforward = feedforward / heaterEfficiency[ D5_HEAT ]; - feedforward = MIN( feedforward, AC_HEATER_TX_MAX_DUTY_CYCLE ); - feedforward = MAX( feedforward, HEATERS_MIN_DUTY_CYCLE ); - - control[ heater ].data = feedforward; + F32 feedforward = calculateDutyCycle( flowrate, capDeltaTempC, PRIMARY_HEATER_MAX_PWR_WATTS, AC_HEATER_EFFICIENCY, + HEATERS_MIN_DUTY_CYCLE, AC_HEATER_TX_MAX_DUTY_CYCLE ); + control[ heater ].data = feedforward; resetPIController( PI_CONTROLLER_ID_D5_HEAT, HEATERS_MIN_DUTY_CYCLE, feedforward ); } else { ctrl = runPIController( PI_CONTROLLER_ID_D5_HEAT, targetTemperature, measuredTemperature ); control[ heater ].data = ctrl; } -#else - if ( measuredTemperature >= targetTemperature ) - { - // Turn off heater - control[ heater ].data = HEATERS_MIN_DUTY_CYCLE; - } - else - { - // Turn On heater - control[ heater ].data = D5_HEAT_ON; - } -#endif #ifdef __HEATERS_DEBUG__ U32 i; @@ -692,21 +645,8 @@ { measuredTemperature = getTemperatureValue( D50_TEMP ); -#ifndef __ALPHA_AO_VER__ ctrl = runPIController( PI_CONTROLLER_ID_D45_HEAT, targetTemperature, measuredTemperature ); control[ heater ].data = ctrl; -#else - if ( targetTemperature > 0.0F ) - { - ctrl = HEATERS_MAX_DUTY_CYCLE - ( measuredTemperature / targetTemperature ); - ctrl = ( ctrl < 0.0F ? HEATERS_MIN_DUTY_CYCLE: ctrl * D45_HEAT_GAIN ); - //Apply dutycycle limit - ctrl = MIN( ctrl, HEATERS_MAX_DUTY_CYCLE ); - ctrl = MAX( ctrl, HEATERS_MIN_DUTY_CYCLE ); - } - - control[ heater ].data = ( ctrl * HEATERS_DUTY_CYCLE_CONVERSION_FACTOR ) + FLOAT_TO_INT_ROUNDUP_OFFSET; -#endif #ifdef __HEATERS_DEBUG__ U32 i; @@ -767,17 +707,12 @@ if ( D5_HEAT == heater ) { -#ifndef __ALPHA_AO_VER__ //Convert duty cycle into LowState and multiply by period F32 duty = AC_HEATER_MAX_DUTY_CYCLE - control; convertDC = duty * period; setFPGAD5HeaterPWMPeriod( (U16)period ); setFPGAD5HeaterPWMLowState( (U16)convertDC ); -#else - BOOL heaterCntrl = (BOOL)control; - setFPGAD5HeaterOnOffControl( heaterCntrl ); -#endif } else { @@ -808,6 +743,37 @@ /*********************************************************************//** * @brief + * The calculateDutyCycle function calculates the heater's duty cycle + * based on the delta temperature, flowrate and power applied to the heater. + * @details \b Inputs: none + * @details \b Outputs: duty cycle + * @param flowrate: dialysate flowrate. + * @param deltaTemp: Temperature difference between actual and target. + * @param power: Power supplied to the heater + * @param efficiency: Heater efficeincy to compensate heatloss + * @param min: heaters minimum duty cycle + * @param max: heaters maximum duty cycle + * @return calcualted PWM duty cycle + *************************************************************************/ +static F32 calculateDutyCycle( F32 flowrate, F32 deltaTemp, F32 power, F32 efficiency, F32 min, F32 max ) +{ + F32 duty = ( WATER_SPECIFIC_HEAT_DIVIDED_BY_MINUTES * deltaTemp * flowrate ) / power; + + // Updated duty with efficiency + if ( HEATERS_ZERO_EFFICIENCY != efficiency ) + { + duty = duty / efficiency; + } + + // Apply min/max limits + duty = MIN( duty, max ); + duty = MAX( duty, min ); + + return duty; +} + +/*********************************************************************//** + * @brief * The monitorHeatersVoltage function monitors the heaters' voltages * @details \b Inputs: Voltage range * @details \b Outputs: none @@ -865,9 +831,7 @@ data.d5_HeaterDC = getHeaterControl( D5_HEAT ); data.d45_HeaterDC = getHeaterControl( D45_HEAT ); data.d5_HeaterTargetTemp = getHeaterTargetTemperature( D5_HEAT ); - //TODO : Testing - //data.d45_HeaterTargetTemp = getHeaterTargetTemperature( D45_HEAT ); - data.d45_HeaterTargetTemp = getTemperatureValue( D4_TEMP ); + data.d45_HeaterTargetTemp = getHeaterTargetTemperature( D45_HEAT ); data.d5_HeaterState = heatersStatus[ D5_HEAT ].state; data.d45_HeaterState = heatersStatus[ D45_HEAT ].state; #ifndef __HEATERS_DEBUG__