Index: firmware/App/Controllers/Heaters.c =================================================================== diff -u -rf38051e1882be3e774f10ba924343a6ce1334890 -r2468e56fbecd26da713bc78535bd727f4b105fe1 --- firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision f38051e1882be3e774f10ba924343a6ce1334890) +++ firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision 2468e56fbecd26da713bc78535bd727f4b105fe1) @@ -57,7 +57,6 @@ #define MAXIMUM_TARGET_TEMPERATURE 90.0 ///< Maximum allowed target temperature for the heaters. #define MAXIMUM_IDLE_DRAIN_TARGET_TEMPERATURE 58.0 ///< Maximum allowed target temperature for the idle and drain modes. -#define HEATERS_RAMP_STATE_CHECK_INTERVAL_COUNT 20U // TODO remove ///< Heaters ramp check interval count. #define HEATERS_CONTROL_STATE_CHECK_INTERVAL_COUNT ( ( 10 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Temperature sensors interval count. #define HEATERS_ON_WITH_NO_FLOW_TIMEOUT_COUNT ( ( 3 * MS_PER_SECOND ) / TASK_PRIORITY_INTERVAL ) ///< Heaters are on but there is no sufficient flow timeout in counts. #define HEATERS_MAX_ALLOWED_INTERNAL_TEMPERATURE_C 170.0 ///< Heaters max allowed internal temperature in C. @@ -70,13 +69,8 @@ #define HEATERS_MIN_RAMP_TIME_MS ( 6 * MS_PER_SECOND ) ///< Heaters minimum time that they have to stay in the ramp state in milliseconds. #define TEMPERATURES_MOVING_AVG_SIZE 3U ///< Heaters ramp state temperatures moving average size. -#define PRIMARY_HEATERS_THERMAL_POWER_TO_VOLTAGE_SLOPE 0.395 // TODO remove ///< Primary heaters thermal power to voltage slope. -#define PRIMARY_HEATERS_THERMAL_POWER_TO_VOLTAGE_INTERCEPT 0.21 // TODO remove ///< Primary heaters thermal power to voltage intercept. +#define DELTA_TEMPERATURE_TIME_COSNTANT_C 8.6 ///< Delta temperature calculated from time constant. -#define DELTA_DUTY_CYCLE_GAIN 0.1 ///< Delta duty cycle gain. -#define DELTA_TEMPERATURE_GAIN 1.27 ///< Delta temperature gain. -#define HEATERS_CONTROL_TO_TARGET_DUTY_CYCLE_CAP 0.09 ///< Heaters control to target duty cycle cap. - static const F32 WATER_SPECIFIC_HEAT_DIVIDED_BY_MINUTES = 4184 / SEC_PER_MIN; ///< Water specific heat in J/KgC / 60. static const F32 PRIMARY_HEATERS_MAXIMUM_POWER_WATTS = 475 + 237.5; ///< Primary heaters maximum power (main primary = 475W and small primary = 237.5W). @@ -103,6 +97,7 @@ 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; PI_CONTROLLER_ID_T controllerID; ///< Heater PI controller ID TODO remove this? U32 tempOutOfRangeTimer; ///< Heater temperature out of range timer TODO remove once the mechanical thermal cutoff was implemented @@ -133,6 +128,7 @@ static void checkTrimmerHeaterTempSensors( void ); static void monitorHeatersVoltage( void ); static void checkHeaterOnStatus( DG_HEATERS_T heater ); +static void getHeatersEfficiencyFromRTCRAM(); /*********************************************************************//** * @brief @@ -165,6 +161,7 @@ heatersStatus[ heater ].targetROFlow = 0.0; heatersStatus[ heater ].controllerID = ( DG_PRIMARY_HEATER == heater ? 4 : PI_CONTROLLER_ID_TRIMMER_HEATER ); // TODO remove or refactor? heatersStatus[ heater ].hasTargetTempChanged = FALSE; + heatersStatus[ heater ].heaterEfficiency = 1.0; // Assuming 100% efficiency until it is updated } // Initialize the PI controller for the trimmer heater @@ -445,128 +442,29 @@ HEATERS_STATE_T state = HEATER_EXEC_STATE_RAMP_TO_TARGET; F32 inletTemperature = getTemperatureValue( (U32)TEMPSENSORS_HEAT_DISINFECT ); F32 targetFlow = 0.0; - F32 targetTemperature = heatersStatus[ heater ].originalTargetTemp; F32 dutyCycle = 0.0; + F32 targetTemperature = heatersStatus[ heater ].originalTargetTemp; + F32 heaterEfficiency = heatersStatus[ heater ].heaterEfficiency; if ( DG_MODE_FILL == getCurrentOperationMode() ) { // Get the previous fill's average flow rate - targetFlow = getAverageFillFlowRate(); - dutyCycle = calculatePrimaryHeaterDutyCycle( targetTemperature, inletTemperature, targetFlow ); + targetFlow = getAvgFillFlowRate(); + dutyCycle = calculatePrimaryHeaterDutyCycle( targetTemperature, inletTemperature, targetFlow ); + // Multiply the duty cycle to the heater efficiency + dutyCycle *= heaterEfficiency; } else if ( ( DG_MODE_GENE == getCurrentOperationMode() ) || ( DG_MODE_DRAI == getCurrentOperationMode() ) ) { + targetTemperature += DELTA_TEMPERATURE_TIME_COSNTANT_C; + // Use target flow rate during Idle and drain targetFlow = getTargetROPumpFlowRate(); + dutyCycle = calculatePrimaryHeaterDutyCycle( targetTemperature, inletTemperature, targetFlow ); } + setHeaterDutyCycle( heater, dutyCycle ); + state = HEATER_EXEC_STATE_CONTROL_TO_TARGET; - - // TODO For testing only remove - //dutyCycle = calculatePrimaryHeaterDutyCycle( 39.0, inletTemperature, 0.8 ); - //heatersStatus[ heater ].targetTemp = heatersStatus[ heater ].originalTargetTemp; - // TODO for testing only remove - - - /*if ( heatersStatus[ heater ].initialDutyCycle - 0.0 < NEARLY_ZERO ) - { - if ( ++heatersStatus[ heater ].controlTimerCounter > HEATERS_RAMP_STATE_CHECK_INTERVAL_COUNT ) - { - U32 i; - F32 slope; - F32 deltaTemperature; - F32 deltaDutyCycle; - F32 revDeltaDutyCycle; - - // Update the temperature data array as well as the next index - U32 currentIndex = heatersStatus[ heater ].previousTempsIndex; - heatersStatus[ heater ].previousTemps[ currentIndex ] = feedbackTemperature; - heatersStatus[ heater ].previousTempsIndex = INC_WRAP( currentIndex, 0, TEMPERATURES_MOVING_AVG_SIZE - 1 ); - - // If the target temperature changed, set it the flag to FALSE. In the ramp state, the target temperature - // change is addressed automatically - if ( TRUE == heatersStatus[ heater ].hasTargetTempChanged ) - { - heatersStatus[ heater ].hasTargetTempChanged = FALSE; // TODO do we need this? - } - - // Calculate the running sum of the temperatures - for ( i = 0; i < TEMPERATURES_MOVING_AVG_SIZE; i++ ) - { - slope += heatersStatus[ heater ].previousTemps[ i ]; - } - - // TODO add comments - if ( ( ( DG_MODE_DRAI == getCurrentOperationMode() ) || ( DG_MODE_GENE == getCurrentOperationMode() ) ) ) - { - targetTemperature = MAXIMUM_IDLE_DRAIN_TARGET_TEMPERATURE; - } - else if ( ( DG_MODE_FILL == getCurrentOperationMode() ) ) - { - targetFlow = getTargetROPumpFlowRate(); // TODO change this to the moving average flow from fill - } - - slope = slope / (F32)TEMPERATURES_MOVING_AVG_SIZE; - dutyCycle = calculateHeaterDutyCycle( targetTemperature, inletTemperature, targetFlow ); - deltaDutyCycle = ( feedbackTemperature <= targetTemperature ? HEATERS_MAX_DUTY_CYCLE - dutyCycle : dutyCycle ); - - revDeltaDutyCycle = ( deltaDutyCycle - 0.0 < NEARLY_ZERO ? 0.0 : 1.0 / deltaDutyCycle ); - revDeltaDutyCycle = ( revDeltaDutyCycle * DELTA_DUTY_CYCLE_GAIN < HEATERS_MAX_DUTY_CYCLE ? - revDeltaDutyCycle * DELTA_DUTY_CYCLE_GAIN : HEATERS_MAX_DUTY_CYCLE ); - deltaTemperature = ( ( atanf( slope ) * DELTA_TEMPERATURE_GAIN ) / targetFlow ) + revDeltaDutyCycle; - - if ( fabs( targetTemperature - feedbackTemperature ) < deltaTemperature ) - { - if ( TRUE == didTimeout( heatersStatus[ heater ].rampStateStartTime, HEATERS_MIN_RAMP_TIME_MS ) ) - { - isItHandOffTime = TRUE; - } - } - else if ( feedbackTemperature > targetTemperature ) - { - isItHandOffTime = TRUE; - } - - if ( ( TRUE == isItHandOffTime ) && ( DG_MODE_FILL == getCurrentOperationMode() ) ) - { - heatersStatus[ heater ].targetTemp = heatersStatus[ heater ].originalTargetTemp; - } - - heatersStatus[ heater ].controlTimerCounter = 0; - } - } - else - { - if ( ( DG_MODE_FILL == getCurrentOperationMode() ) ) - { - dutyCycle = calculateHeaterDutyCycle( targetTemperature, inletTemperature, targetFlow ); - heatersStatus[ heater ].targetTemp = targetTemperature; - isItHandOffTime = TRUE; - } - else if ( ( ( DG_MODE_DRAI == getCurrentOperationMode() ) || ( DG_MODE_GENE == getCurrentOperationMode() ) ) ) - { - F32 highTempDutyCycle = calculateHeaterDutyCycle( MAXIMUM_IDLE_DRAIN_TARGET_TEMPERATURE, inletTemperature, targetFlow ); - - dutyCycle = ( dutyCycle < highTempDutyCycle ? dutyCycle : highTempDutyCycle ); - - targetTemperature = ( pow( ( dutyCycle + PRIMARY_HEATERS_THERMAL_POWER_TO_VOLTAGE_INTERCEPT ) / PRIMARY_HEATERS_THERMAL_POWER_TO_VOLTAGE_SLOPE, 2 ) - / targetFlow ) + feedbackTemperature; - - targetTemperature = ( targetTemperature > MAXIMUM_IDLE_DRAIN_TARGET_TEMPERATURE ? MAXIMUM_IDLE_DRAIN_TARGET_TEMPERATURE : targetTemperature ); - heatersStatus[ heater ].targetTemp = targetTemperature; - - isItHandOffTime = TRUE; - } - }*/ - - if ( TRUE /*== isItHandOffTime*/ ) - { - setHeaterDutyCycle( heater, dutyCycle ); - - //heatersStatus[ heater ].initialDutyCycle = dutyCycle; //TODO do we need this? - - state = HEATER_EXEC_STATE_CONTROL_TO_TARGET; - } - if ( FALSE == heatersStatus[ heater ].isHeaterOn ) { setHeaterDutyCycle( heater, HEATERS_MIN_DUTY_CYCLE ); @@ -587,45 +485,15 @@ *************************************************************************/ static HEATERS_STATE_T handleHeaterStateControlToTarget( DG_HEATERS_T heater ) { - F32 dutyCycle; - HEATERS_STATE_T state = HEATER_EXEC_STATE_CONTROL_TO_TARGET; - F32 targetFlow = getTargetROPumpFlowRate(); - BOOL hasFlowChanged = ( fabs( targetFlow - heatersStatus[ heater ].targetROFlow ) > NEARLY_ZERO ? TRUE : FALSE ); - F32 feedbackTemperature = getTemperatureValue( (U32)heatersStatus[ heater ].feedbackSensor ); - F32 targetTemperature = heatersStatus[ heater ].targetTemp; + // TODO do we need any control to maintain the temperature? + if ( TRUE == haveHeaterControlConditionsChanged( heater ) ) { state = HEATER_EXEC_STATE_RAMP_TO_TARGET; } - // Check if it is the control time - /*else if ( ++heatersStatus[ heater ].controlTimerCounter > HEATERS_CONTROL_STATE_CHECK_INTERVAL_COUNT ) - { - dutyCycle = heatersStatus[ heater ].dutycycle; - dutyCycle += ( targetTemperature - feedbackTemperature ) * PRIMARY_HEATER_P_COEFFICIENT * getMeasuredROFlowRate(); - - F32 deltaDutyCycle = dutyCycle - heatersStatus[ heater ].initialDutyCycle; - - if ( ( fabs( deltaDutyCycle ) > HEATERS_CONTROL_TO_TARGET_DUTY_CYCLE_CAP ) && ( deltaDutyCycle < 0.0 ) ) - { - dutyCycle = heatersStatus[ heater ].initialDutyCycle - HEATERS_CONTROL_TO_TARGET_DUTY_CYCLE_CAP; - } - else if ( deltaDutyCycle > HEATERS_CONTROL_TO_TARGET_DUTY_CYCLE_CAP ) - { - dutyCycle = heatersStatus[ heater ].initialDutyCycle + HEATERS_CONTROL_TO_TARGET_DUTY_CYCLE_CAP; - } - - // Cap the duty cycle ranges in case they exceeded the limit - dutyCycle = ( dutyCycle > HEATERS_MAX_DUTY_CYCLE ? HEATERS_MAX_DUTY_CYCLE : dutyCycle ); - dutyCycle = ( dutyCycle < HEATERS_MIN_DUTY_CYCLE ? HEATERS_MIN_DUTY_CYCLE : dutyCycle ); - - setHeaterDutyCycle( heater, dutyCycle ); - - heatersStatus[ heater ].controlTimerCounter = 0; - }*/ - // Check if the heater is requested to be off if ( FALSE == heatersStatus[ heater ].isHeaterOn ) { @@ -696,8 +564,6 @@ *************************************************************************/ static BOOL haveHeaterControlConditionsChanged( DG_HEATERS_T heater ) { - F32 dutyCycle; - BOOL status = FALSE; F32 targetFlow = getTargetROPumpFlowRate(); BOOL hasFlowChanged = ( fabs( targetFlow - heatersStatus[ heater ].targetROFlow ) > NEARLY_ZERO ? TRUE : FALSE ); @@ -710,45 +576,8 @@ // Moving back from control to target to ramp. heatersStatus[ heater ].targetROFlow = targetFlow; heatersStatus[ heater ].hasTargetTempChanged = FALSE; - - // If the new target flow is less than the measured current flow, it means the new target flow is faster so it needs more heat power - //dutyCycle = ( getMeasuredROFlowRate() < heatersStatus[ heater ].targetROFlow ? HEATERS_MAX_DUTY_CYCLE : HEATERS_MIN_DUTY_CYCLE ); - - // Go back to ramp state - //setHeaterDutyCycle( heater, dutyCycle ); - - //setHeaterDutyCycle( heater, 100.00 ); } - /*if ( DG_PRIMARY_HEATER == heater ) - { - // Check if the mode is drain or the mode is gen idle - if ( ( DG_MODE_DRAI == getCurrentOperationMode() ) || ( DG_MODE_GENE == getCurrentOperationMode() ) ) - { - // If the operation mode is not the same as the current operation mode - if ( operationMode != getCurrentOperationMode() ) - { - // Add an offset to the dialysate temperature - operationMode = getCurrentOperationMode(); - //heatersStatus[ heater ].targetTemp = heatersStatus[ heater ].originalTargetTemp + DRAIN_AND_IDLE_MODE_TARGET_TEMPERATURE_OFFSET; - } - } - else if ( ( DG_MODE_FILL == getCurrentOperationMode() ) && ( operationMode != getCurrentOperationMode() ) ) - { - // If the mode is fill and the operation mode has changed, set the temperature back to the original temperature - operationMode = getCurrentOperationMode(); - heatersStatus[ heater ].targetTemp = heatersStatus[ heater ].originalTargetTemp; - } - - if ( ( getCurrentOperationMode() != DG_MODE_DRAI ) || ( getCurrentOperationMode() != DG_MODE_GENE ) ) - { - if ( TRUE == ( fabs( heatersStatus[ heater ].targetTemp - heatersStatus[ heater ].originalTargetTemp ) > NEARLY_ZERO ) - { - - } - } - }*/ - return status; }