Index: firmware/App/Controllers/Heaters.c =================================================================== diff -u -r2e89a75592087ba15cae7070a92173e9f1efa8fe -r51c295e1dc413d3774dae303e7f98b2f4c86bae4 --- firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision 2e89a75592087ba15cae7070a92173e9f1efa8fe) +++ firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision 51c295e1dc413d3774dae303e7f98b2f4c86bae4) @@ -17,6 +17,7 @@ #include // Used for mathematical operations +#include "Conductivity.h" #include "FpgaDD.h" #include "Heaters.h" #include "Level.h" @@ -50,6 +51,7 @@ #define HEATERS_DUTY_CYCLE_CONVERSION_FACTOR 100.0F ///< Heaters duty cycle 0: OFF, 100: 100% duty cycle. #define HEATERS_ZERO_EFFICIENCY 0.0F ///< Zero heater efficiency #define HEATER_CNTL_TRANSFER_DELTA_TEMP_C 0.50F ///< AC heater delta temperature to transfer control from open to close loop +#define MAX_ADJ_DELTA_TEMP_C 3.0F ///< Maximum adjusted delta temperature to add/remove from calculated target temperature #define D5_HEAT_TX_INIT_FEED_FORWARD 0.0F ///< Initial Feed forward term for heater control //#define D5_HEAT_TX_P_COEFFICIENT 0.050F ///< P Term for AC primary heater control during treatment mode. @@ -79,6 +81,7 @@ #define D5_HEAT_CONTROL_INTERVAL_COUNT ( D5_HEAT_CONTROL_INTERVAL_MS / TASK_GENERAL_INTERVAL ) ///< Primary heater control interval count. #define D45_HEAT_CONTROL_INTERVAL_MS ( 1 * MS_PER_SECOND ) ///< Trimmer heater control interval in milli seconds #define D45_HEAT_CONTROL_INTERVAL_COUNT ( D45_HEAT_CONTROL_INTERVAL_MS / TASK_GENERAL_INTERVAL ) ///< Trimmer heater control interval count. +#define D5_TARGET_TEMP_ADJUST_INTERVAL_MS ( 10 * SEC_PER_MIN * MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Adjust primary target temperature #define PRIMARY_HEATER_MAX_PWR_WATTS 1400.0F ///< AC Primary Heater Max Power consumeption in Watts #define TX_PRIMARY_HEATER_MAX_PWR_WATTS 700.0F ///< Estimated power to be supplied to the primary heater during treatement mode #define HEAT_PRIMARY_HEATER_MAX_PWR_WATTS 980.0F ///< Estimated power to be supplied to the primary heater during heat disinfect mode @@ -121,6 +124,9 @@ static OVERRIDE_F32_T pwmPeriod[ NUM_OF_DD_HEATERS ]; ///< Total PWM period ( ON state + Off State of PWM) static U32 controlInterval[ NUM_OF_DD_HEATERS ]; ///< Heater control interval time. static U32 dataPublicationTimerCounter; ///< Data publication timer counter. +static U32 primaryTargetTempAdjCounter; ///< Primary target temperature adjustment counter. +static BOOL isTargetTempAdjusted; ///< Flag indicating that target temperature is adjusted +static U32 adjustedPrimaryTargetTemp; ///< Adjusted primary target temperature 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 @@ -137,6 +143,7 @@ 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 void updatePrimaryHeaterTargetTemp( void ); static F32 calculateDutyCycle( F32 flowrate, F32 deltaTemp, F32 power, F32 efficiency, F32 min, F32 max ); static void setHeaterControl( DD_HEATERS_T heater ); @@ -187,6 +194,9 @@ heatersStatus[ D45_HEAT ].controlIntervalCounter = 0; startupHeaterControl = TRUE; lastDialTargetTemperatureSet = 0.0F; + primaryTargetTempAdjCounter = 0; + adjustedPrimaryTargetTemp = 0.0F; + isTargetTempAdjusted = FALSE; for ( heater = DD_HEATERS_FIRST; heater < NUM_OF_DD_HEATERS; heater++ ) { @@ -341,12 +351,62 @@ { // Set flag to recalculate the feedforward signals startupHeaterControl = TRUE; + isTargetTempAdjusted = FALSE; } } } /*********************************************************************//** * @brief + * The signaltoResetPrimaryHeaterAdjustedTargetTemp function resets the flag to + * update/adjust the primary heater target dialysate temperature + * @details \b Inputs: none + * @details \b Outputs: isTargetTempAdjusted + * @param heater: heater ID to update the heater control. + * @return none + *************************************************************************/ +void signaltoResetPrimaryHeaterAdjustedTargetTemp( void ) +{ + isTargetTempAdjusted = FALSE; +} + +/*********************************************************************//** + * @brief + * The updatePrimaryHeaterTargetTemp function adjusts the previosuly calcualted + * target dialysate temperature + * @details \b Inputs: Set Target Temperature, D28 Temp + * @details \b Outputs: Adjusted target temperature + * @return none + *************************************************************************/ +static void updatePrimaryHeaterTargetTemp( void ) +{ + if ( ++primaryTargetTempAdjCounter >= D5_TARGET_TEMP_ADJUST_INTERVAL_MS ) + { + F32 targetTempfromTD = getTDTargetDialysateTemperature(); + F32 measuredTempAtDialyzer = getConductivityTemperatureValue( D27_COND ); + F32 calcTargetTemp = getHeaterTargetTemperature( D5_HEAT ); + F32 deltaTempC = targetTempfromTD - measuredTempAtDialyzer; + F32 capDeltaTempC = MIN( fabs(deltaTempC), MAX_ADJ_DELTA_TEMP_C ); + + if ( deltaTempC > HEATERS_ZERO_DELTA_TEMP_C ) + { + adjustedPrimaryTargetTemp = calcTargetTemp + capDeltaTempC; + } + else + { + adjustedPrimaryTargetTemp = calcTargetTemp - capDeltaTempC; + } + + adjustedPrimaryTargetTemp = MIN(adjustedPrimaryTargetTemp, ( calcTargetTemp + MAX_ADJ_DELTA_TEMP_C ) ); + adjustedPrimaryTargetTemp = MAX(adjustedPrimaryTargetTemp, ( calcTargetTemp - MAX_ADJ_DELTA_TEMP_C ) ); + + isTargetTempAdjusted = TRUE; + primaryTargetTempAdjCounter = 0; + } +} + +/*********************************************************************//** + * @brief * The startHeater function starts the given heater by setting the flag. * @details \b Inputs: heatersStatus * @details \b Outputs: startHeaterSignal @@ -630,6 +690,12 @@ F32 measuredTemperature = 0.0F; F32 ctrl = 0.0F; + // Update primary heater target temperature at defined interval + if ( D5_HEAT == heater ) + { + updatePrimaryHeaterTargetTemp(); + } + if ( ++heatersStatus[ heater ].controlIntervalCounter >= controlInterval[ heater ] ) { if ( D5_HEAT == heater ) @@ -640,19 +706,25 @@ if ( TRUE == startupHeaterControl ) { - startupHeaterControl = FALSE; F32 deltaTempC = targetTemperature - inletTemperature; F32 capDeltaTempC = MAX( deltaTempC, HEATERS_ZERO_DELTA_TEMP_C ); F32 flowrate = getTDDialysateFlowrate() / LITER_IN_ML ; F32 feedforward = calculateDutyCycle( flowrate, capDeltaTempC, PRIMARY_HEATER_MAX_PWR_WATTS, AC_HEATER_EFFICIENCY, HEATERS_MIN_DUTY_CYCLE, AC_HEATER_TX_MAX_DUTY_CYCLE ); + startupHeaterControl = FALSE; control[ heater ].data = feedforward; resetPIController( PI_CONTROLLER_ID_D5_HEAT, HEATERS_MIN_DUTY_CYCLE, feedforward ); } else { - F32 deltaTempC = fabs( targetTemperature - measuredTemperature ); + F32 deltaTempC = 0.0F; + if ( TRUE == isTargetTempAdjusted ) + { + targetTemperature = adjustedPrimaryTargetTemp; + } + deltaTempC = fabs( targetTemperature - measuredTemperature ); + if ( deltaTempC >= D5_HEATER_DEADBAND_CONTROL ) { ctrl = runPIController( PI_CONTROLLER_ID_D5_HEAT, targetTemperature, measuredTemperature ); @@ -861,13 +933,10 @@ data.d45_HeaterTargetTemp = getHeaterTargetTemperature( D45_HEAT ); data.d5_HeaterState = heatersStatus[ D5_HEAT ].state; data.d45_HeaterState = heatersStatus[ D45_HEAT ].state; -#ifndef __HEATERS_DEBUG__ - data.d5_HeaterControlCounter = heatersStatus[ D5_HEAT ].controlIntervalCounter; - data.d45_HeaterControlCounter = heatersStatus[ D45_HEAT ].controlIntervalCounter; -#else - data.d5_HeaterControlCounter = (U32)convertDC; - data.d45_HeaterControlCounter = (U32)getHeaterPWMPeriod( D5_HEAT ); -#endif + data.d5_dutyCycleCnt = convertDC; + data.d5_PWMPeriod = getHeaterPWMPeriod( D5_HEAT ); + data.d5_adjsutedTargetTemp = adjustedPrimaryTargetTemp; + data.d5_targetTempFromTD = getTDTargetDialysateTemperature(); #ifdef __HEATERS_DEBUG__ data.dbg1 = pIControlSignal[ 0 ]; data.dbg2 = pIControlSignal[ 1 ];