Index: firmware/App/Controllers/Heaters.c =================================================================== diff -u -r1aeab08c1baf6445514b81fe51fc60a3e536e782 -reeb4e9c7c8ca2bc41168353c3d30f311080972b2 --- firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision 1aeab08c1baf6445514b81fe51fc60a3e536e782) +++ firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision eeb4e9c7c8ca2bc41168353c3d30f311080972b2) @@ -27,7 +27,7 @@ #include "MessageSupport.h" #include "ModeFill.h" #include "OperationModes.h" -#include "PIControllers.h" +#include "Reservoirs.h" #include "ROPump.h" #include "SafetyShutdown.h" #include "SystemCommMessages.h" @@ -87,20 +87,21 @@ /// Heaters data structure typedef struct { - F32 targetTemp; ///< Heater target temperature. + F32 targetTemp; ///< Heater target temperature. HEATERS_STATE_T state; ///< Heater state. BOOL startHeaterSignal; ///< Heater start indication flag. BOOL isHeaterOn; ///< Heater on/off status flag. - F32 dutycycle; ///< Heater duty cycle. - F32 targetROFlow; ///< Heater target flow. - U32 heaterOnWithNoFlowTimer; // TODO remove ///< Heater on with no flow timer. + F32 dutycycle; ///< Heater duty cycle. + F32 targetROFlow; ///< Heater target flow. + U32 heaterOnWithNoFlowTimer; // TODO remove ///< Heater on with no flow timer. BOOL isFlowBelowMin; ///< Heater flow below minimum flag indicator. BOOL hasTargetTempChanged; ///< Heater target temperature change flag indicator. - F32 heaterEfficiency; ///< Heater efficiency during the run. + F32 heaterEfficiency; ///< Heater efficiency during the run. BOOL hasTargetBeenReached; ///< Heater flag to indicate whether the target temperature has been reached. U32 tempOutOfRangeTimer; ///< Heater temperature out of range timer TODO remove once the mechanical thermal cutoff was implemented BOOL isHeaterTempOutOfRange; ///< Heater temperature out of range flag indicator TODO remove once the mechanical thermal cutoff was implemented + F32 temporaryInterimTemperature; ///< TODO remove } HEATER_STATUS_T; static HEATER_STATUS_T heatersStatus[ NUM_OF_DG_HEATERS ]; ///< Heaters status. @@ -119,7 +120,8 @@ static HEATERS_STATE_T handleHeaterStateTrimmerControlToTarget( void ); static void setHeaterDutyCycle( DG_HEATERS_T heater, F32 pwm ); -static F32 calculatePrimaryHeaterDutyCycle( F32 targetTemperature, F32 currentTemperature, F32 flow, BOOL checkEfficiency ); +static F32 calculatePrimaryHeaterDutyCycle( F32 targetTemperature, F32 currentTemperature, F32 flow, BOOL checkEfficiency ); +static F32 calculateTrimmerHeaterDutyCycle( F32 targetTemperature, F32 currentTemperature, F32 flow, BOOL checkEfficiency ); static BOOL haveHeaterControlConditionsChanged( DG_HEATERS_T heater ); static void setMainPrimaryHeaterPWM( F32 pwm ); @@ -322,11 +324,12 @@ if ( TRUE == heaterCmdPtr->startHeater ) { - if ( ( MINIMUM_TARGET_TEMPERATURE <= heaterCmdPtr->targetTemp ) && ( heaterCmdPtr->targetTemp <= MAXIMUM_TARGET_TEMPERATURE ) ) + if ( ( heaterCmdPtr->targetTemp >= MINIMUM_TARGET_TEMPERATURE ) && ( heaterCmdPtr->targetTemp <= MAXIMUM_TARGET_TEMPERATURE ) ) { cmdResponse.rejected = FALSE; + + heatersStatus[ DG_TRIMMER_HEATER ].targetTemp = heaterCmdPtr->targetTemp; // TODo do we need to remove this since the trimmer heater is set in the reservoirs #ifndef DISABLE_HEATERS_AND_TEMPS - heatersStatus[ DG_TRIMMER_HEATER ].targetTemp = heaterCmdPtr->targetTemp; heatersStatus[ DG_TRIMMER_HEATER ].startHeaterSignal = TRUE; #endif } @@ -409,7 +412,6 @@ publishHeatersData(); } - /*********************************************************************//** * @brief * The resetHeatersEfficiency function resets the heaters efficiency upon @@ -464,23 +466,24 @@ F32 targetFlow = 0.0; F32 dutyCycle = 0.0; F32 targetTemperature = heatersStatus[ heater ].targetTemp; + DG_OP_MODE_T opMode = getCurrentOperationMode(); - if ( DG_MODE_FILL == getCurrentOperationMode() ) + if ( DG_MODE_FILL == opMode ) { // If the previous average fill flow rate is 0, use the nominal target RO flow from the RO pump targetFlow = ( getAvgFillFlowRate() - 0.0 > NEARLY_ZERO ? getAvgFillFlowRate() : getTargetROPumpFlowRate() ); dutyCycle = calculatePrimaryHeaterDutyCycle( targetTemperature, inletTemperature, targetFlow, TRUE ); state = HEATER_EXEC_STATE_PRIMARY_CONTROL_TO_TARGET; } - else if ( ( DG_MODE_GENE == getCurrentOperationMode() ) || ( DG_MODE_DRAI == getCurrentOperationMode() ) ) + else if ( ( DG_MODE_GENE == opMode ) || ( DG_MODE_DRAI == opMode ) ) { targetTemperature += DELTA_TEMPERATURE_TIME_COSNTANT_C; // Use target flow rate during Idle and drain targetFlow = getTargetROPumpFlowRate(); dutyCycle = calculatePrimaryHeaterDutyCycle( targetTemperature, inletTemperature, targetFlow, FALSE ); state = HEATER_EXEC_STATE_PRIMARY_CONTROL_TO_TARGET; } - else if ( ( DG_MODE_HEAT == getCurrentOperationMode() ) || ( DG_MODE_CHEM == getCurrentOperationMode() ) ) + else if ( ( DG_MODE_HEAT == opMode ) || ( DG_MODE_CHEM == opMode ) ) { // If the mode is any of the disinfects, especially heat, use the target flow rate instead of the avg. flow // Most of the times the heater should be running at 100% duty cycle since the target temperature is 81 C @@ -489,6 +492,10 @@ state = HEATER_EXEC_STATE_CONTROL_TO_DISINFECT_TARGET; } + // TODO remove + heatersStatus[ DG_PRIMARY_HEATER ].temporaryInterimTemperature = targetTemperature; + // TODO remove + setHeaterDutyCycle( heater, dutyCycle ); return state; @@ -568,8 +575,33 @@ *************************************************************************/ static HEATERS_STATE_T handleHeaterStateTrimmerRampToTarget( void ) { - HEATERS_STATE_T state = HEATER_EXEC_STATE_TRIMMER_RAMP_TO_TARGET; + HEATERS_STATE_T state = HEATER_EXEC_STATE_TRIMMER_RAMP_TO_TARGET; + DG_HEATERS_T heater = DG_TRIMMER_HEATER; + F32 currentTemperature = 0.0; + F32 targetFlow = getTargetDialysateFlowLPM(); + F32 dutyCycle = 0.0; + F32 targetTemperature = heatersStatus[ heater ].targetTemp; + DG_OP_MODE_T opMode = getCurrentOperationMode(); + if ( ( DG_MODE_FILL == opMode ) || ( DG_MODE_GENE == opMode ) || ( DG_MODE_DRAI == opMode ) ) + { + currentTemperature = getReservoirActualTemperature(); + dutyCycle = calculateTrimmerHeaterDutyCycle( targetTemperature, currentTemperature, targetFlow, TRUE ); + state = HEATER_EXEC_STATE_TRIMMER_CONTROL_TO_TARGET; + } + else if ( DG_MODE_HEAT == opMode ) + { + // If the mode is heat disinfect, use the target flow rate instead of the avg. flow + // Most of the times the heater should be running at 100% duty cycle since the target temperature is 81 C and + // it is far from the inlet temperature. + currentTemperature = getTemperatureValue( (U32)TEMPSENSORS_HEAT_DISINFECT ); + targetFlow = getTargetROPumpFlowRate(); + dutyCycle = calculateTrimmerHeaterDutyCycle( targetTemperature, currentTemperature, targetFlow, FALSE ); + state = HEATER_EXEC_STATE_CONTROL_TO_DISINFECT_TARGET; + } + + setHeaterDutyCycle( heater, dutyCycle ); + return state; } @@ -584,7 +616,12 @@ static HEATERS_STATE_T handleHeaterStateTrimmerControlToTarget( void ) { HEATERS_STATE_T state = HEATER_EXEC_STATE_TRIMMER_CONTROL_TO_TARGET; + DG_HEATERS_T heater = DG_TRIMMER_HEATER; + if ( TRUE == haveHeaterControlConditionsChanged( heater ) ) // TODO do we need this kind of check from trimmer?? + { + state = HEATER_EXEC_STATE_TRIMMER_RAMP_TO_TARGET; + } return state; } @@ -629,24 +666,28 @@ // Get the primary heater's efficiency and the last fill temperature from the ModeFill F32 heaterEfficiency = heatersStatus[ DG_PRIMARY_HEATER ].heaterEfficiency; - if ( TRUE == checkEfficiency ) + if ( TRUE == checkEfficiency ) // TODO ignore the efficiency for now until it is fixed { - F32 lastFillTemperature = getLastFillTemperature(); + /*F32 lastFillTemperature = getLastFillTemperature(); + F32 primaryTargetTemperature = heatersStatus[ DG_PRIMARY_HEATER ].targetTemp; // If the last fill temperature > target temperature, it means the primary heater overshot the duty cycle // so with its efficiency is toned down for the next fill cycle - // If the heater undershoots the duty cycle, the efficiency increases the duty cycle for the next fill cycle - if ( lastFillTemperature - targetTemperature > MAXIMUM_ALLOWED_TARGET_TEMPERATURE_DEVIATION_C ) + // If the heater under-shoots the duty cycle, the efficiency increases the duty cycle for the next fill cycle + if ( lastFillTemperature - primaryTargetTemperature > MAXIMUM_ALLOWED_TARGET_TEMPERATURE_DEVIATION_C ) { - heaterEfficiency -= ( lastFillTemperature - targetTemperature ) * PRIMARY_HEATER_DUTY_CYCLE_PER_TEMPERATURE_C; + heaterEfficiency -= ( lastFillTemperature - primaryTargetTemperature ) * PRIMARY_HEATER_DUTY_CYCLE_PER_TEMPERATURE_C; } - else if ( lastFillTemperature - targetTemperature <= MAXIMUM_ALLOWED_TARGET_TEMPERATURE_DEVIATION_C ) + else if ( lastFillTemperature - primaryTargetTemperature <= MAXIMUM_ALLOWED_TARGET_TEMPERATURE_DEVIATION_C ) { - heaterEfficiency += ( lastFillTemperature - targetTemperature ) * PRIMARY_HEATER_DUTY_CYCLE_PER_TEMPERATURE_C; + heaterEfficiency += ( primaryTargetTemperature - lastFillTemperature ) * PRIMARY_HEATER_DUTY_CYCLE_PER_TEMPERATURE_C; } + heaterEfficiency = heaterEfficiency <= 0.0 ? 0.0 : heaterEfficiency; + //heaterEfficiency = heaterEfficiency >= 1.0 ? 1.0 : heaterEfficiency; + // Update the heaters efficiency - heatersStatus[ DG_PRIMARY_HEATER ].heaterEfficiency = heaterEfficiency; + heatersStatus[ DG_PRIMARY_HEATER ].heaterEfficiency = heaterEfficiency; */ } // Duty cycle = ( 69.73 * flow rate * deltaT / primary heater maximum power ) ^ 1/2 @@ -663,6 +704,40 @@ /*********************************************************************//** * @brief + * The calculateTrimmerHeaterDutyCycle function calculates the trimmer + * heater's duty cycle. + * @details Inputs: none + * @details Outputs: none + * @param targetTemperature target temperature of the heater + * @oaram currentTemperature current inlet temperature of the heater + * @param flow current flow + * @param check efficiency flag to indicate whether to consider heater's + * efficiency + * @return calculated duty cycle + *************************************************************************/ +static F32 calculateTrimmerHeaterDutyCycle( F32 targetTemperature, F32 currentTemperature, F32 flow, BOOL checkEfficiency ) +{ + // Get the primary heater's efficiency and the last fill temperature from the ModeFill + F32 heaterEfficiency = heatersStatus[ DG_TRIMMER_HEATER ].heaterEfficiency; + F32 dutyCycle = 0.0; + + + if ( TRUE == checkEfficiency ) + { + // TODO Do we need to recalculate the efficiency? + } + + dutyCycle = flow * WATER_SPECIFIC_HEAT_DIVIDED_BY_MINUTES * ( targetTemperature - currentTemperature ) * heaterEfficiency; + + // Check the boundaries of the calculated duty cycle + dutyCycle = MIN( dutyCycle, HEATERS_MAX_DUTY_CYCLE ); + dutyCycle = MIN( dutyCycle, HEATERS_MIN_DUTY_CYCLE ); + + return dutyCycle; +} + +/*********************************************************************//** + * @brief * The haveHeaterControlConditionsChanged function checks whether the heater * control conditions have changed or not. If the control conditions have * changed it sets the changes the control parameters accordingly. @@ -674,7 +749,7 @@ static BOOL haveHeaterControlConditionsChanged( DG_HEATERS_T heater ) { BOOL status = FALSE; - F32 targetFlow = getTargetROPumpFlowRate(); + F32 targetFlow = ( DG_PRIMARY_HEATER == heater ? getTargetROPumpFlowRate() : getTargetDialysateFlowLPM() ); BOOL hasFlowChanged = ( fabs( targetFlow - heatersStatus[ heater ].targetROFlow ) > NEARLY_ZERO ? TRUE : FALSE ); // Check if the target flow has changed or the target temperature has changed. @@ -754,6 +829,10 @@ data.trimmerHeaterState = heatersStatus[ DG_TRIMMER_HEATER ].state; data.primaryEfficiency = heatersStatus[ DG_PRIMARY_HEATER ].heaterEfficiency * 100; + data.dialysateTargetLPM = getTargetDialysateFlowLPM(); + data.interimTargetTemp = heatersStatus[ DG_PRIMARY_HEATER ].temporaryInterimTemperature; + data.targetHeaterFlowLPM = heatersStatus[ DG_PRIMARY_HEATER ].targetROFlow; + broadcastData( MSG_ID_DG_HEATERS_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&data, sizeof( HEATERS_DATA_T ) ); dataPublicationTimerCounter = 0; @@ -786,8 +865,9 @@ SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_PRIMARY_HEATER_CJ_TEMP_OUT_OF_RANGE, primaryHeaterInternalTemp ); } - /*/ If any of the temperatures are above the range - /if ( ( FALSE == isPrimaryHeaterTempOutOfRange ) && ( TRUE == isTempOut ) ) +#ifndef IGNORE_HEATERS_MONITOR + // If any of the temperatures are above the range + if ( ( FALSE == isPrimaryHeaterTempOutOfRange ) && ( TRUE == isTempOut ) ) { stopPrimaryHeater(); isPrimaryHeaterTempOutOfRange = TRUE; @@ -799,7 +879,8 @@ { isPrimaryHeaterTempOutOfRange = FALSE; activateSafetyShutdown(); - }*/ + } +#endif } /*********************************************************************//** @@ -828,9 +909,10 @@ SET_ALARM_WITH_1_U32_DATA( ALARM_ID_DG_TRIMMER_HEATER_CJ_TEMP_OUT_OF_RANGE, trimmerHeaterColdJunctionTemp ); } +#ifndef IGNORE_HEATERS_MONITOR // If it is above the range for the first time, stop the trimmer heater // and set the variables - /*if ( ( FALSE == isTrimmerHeaterTempOutOfRange ) && ( TRUE == isTempOut ) ) + if ( ( FALSE == isTrimmerHeaterTempOutOfRange ) && ( TRUE == isTempOut ) ) { stopTrimmerHeater(); isTrimmerHeaterTempOutOfRange = TRUE; @@ -841,7 +923,8 @@ ( TRUE == didTimeout( trimmerHeaterTempOutTimer, HEATERS_MAX_ALLOWED_INTERNAL_TEMPERATURE_TIMEOUT_MS ) ) ) { activateSafetyShutdown(); - }*/ + } +#endif } /*********************************************************************//**