Index: firmware/App/Controllers/Heaters.c =================================================================== diff -u -rd332a26f463cc5d209be77e562952f70775cf913 -r033c0a8a34377fdc9a4d681877f7be1e103857f0 --- firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision d332a26f463cc5d209be77e562952f70775cf913) +++ firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision 033c0a8a34377fdc9a4d681877f7be1e103857f0) @@ -46,7 +46,6 @@ #define HEATERS_MIN_DUTY_CYCLE 0.00 ///< Primary and trimmer heaters minimum duty cycle (0.00%). #define PRIMARY_HEATER_P_COEFFICIENT 0.05 ///< Primary heaters proportional coefficient. -#define PRIMARY_HEATER_I_COEFFICIENT 0.00 // TODO remove? ///< Primary heaters integral coefficient. #define TRIMMER_HEATER_P_COEFFICIENT 0.02 // TODO remove ///< Trimmer heater proportional coefficient. #define TRIMMER_HEATER_I_COEFFICIENT 0.001 // TODO remove ///< Trimmer heater integral coefficient. @@ -75,6 +74,7 @@ #define DELTA_DUTY_CYCLE_GAIN 0.1 ///< Delta duty cycle gain. #define DELTA_TEMPERATURE_GAIN 1.27 ///< Delta temperature gain. #define DRAIN_AND_IDLE_MODE_TARGET_TEMPERATURE_OFFSET 3.0 ///< Drain and Idle modes temperature offset from dialysate. +#define HEATERS_CONTROL_TO_TARGET_DUTY_CYCLE_CAP 0.09 ///< Heaters control to target duty cycle cap. typedef enum Heaters_Exec_States { @@ -164,18 +164,14 @@ heatersStatus[ heater ].dutycycle = 0.0; heatersStatus[ heater ].targetROFlow = 0.0; heatersStatus[ heater ].previousTempsIndex = 0; - heatersStatus[ heater ].controllerID = ( DG_PRIMARY_HEATER == heater ? PI_CONTROLLER_ID_PRIMARY_HEATER : PI_CONTROLLER_ID_TRIMMER_HEATER ); + heatersStatus[ heater ].controllerID = ( DG_PRIMARY_HEATER == heater ? 4 : PI_CONTROLLER_ID_TRIMMER_HEATER ); // TODO remove or refactor? heatersStatus[ heater ].initialDutyCycle = 0.0; heatersStatus[ heater ].hasTargetTempChanged = FALSE; // Set the array of the previous temperatures to 0.0 memset( &heatersStatus[ heater ].previousTemps, 0.0, sizeof( TEMPERATURES_MOVING_AVG_SIZE ) ); } - // Initialize the PI controller for the primary heaters - initializePIController( PI_CONTROLLER_ID_PRIMARY_HEATER, HEATERS_MIN_DUTY_CYCLE, PRIMARY_HEATER_P_COEFFICIENT, PRIMARY_HEATER_I_COEFFICIENT, - HEATERS_MIN_DUTY_CYCLE, HEATERS_MAX_DUTY_CYCLE ); // TODO remove - // Initialize the PI controller for the trimmer heater initializePIController( PI_CONTROLLER_ID_TRIMMER_HEATER, HEATERS_MIN_DUTY_CYCLE, TRIMMER_HEATER_P_COEFFICIENT, TRIMMER_HEATER_I_COEFFICIENT, HEATERS_MIN_DUTY_CYCLE, HEATERS_MAX_DUTY_CYCLE ); // TODO remove? @@ -483,21 +479,6 @@ F32 targetFlow = getTargetROPumpFlowRate(); BOOL hasFlowChanged = ( fabs( targetFlow - heatersStatus[ heater ].targetROFlow ) > NEARLY_ZERO ? TRUE : FALSE ); - // Check if the target flow has changed or the target temperature has changed. - /*if ( ( TRUE == hasFlowChanged ) || ( TRUE == heaterStatus[ heater ].hasTargetTempChanged ) ) - { - // Moving back from control to target to ramp. - heaterStatus[ heater ].rampStateStartTime = getMSTimerCount(); - heaterStatus[ heater ].targetROFlow = targetFlow; - heaterStatus[ 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() < heaterStatus[ heater ].targetROFlow ? HEATERS_MAX_DUTY_CYCLE : HEATERS_MIN_DUTY_CYCLE ); - - // Go back to ramp state - setHeaterDutyCycle( heater, dutyCycle ); - }*/ - haveHeaterControlConditionsChanged( heater ); if ( ++heatersStatus[ heater ].controlTimerCounter > HEATERS_RAMP_STATE_CHECK_INTERVAL_COUNT ) @@ -513,61 +494,76 @@ // Set the hand off flag to false BOOL isItHandOffTime = FALSE; - // Update the temperature data array as well as the next index - 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 ) + // TODO for testing only potentially remove + if ( ( DG_MODE_DRAI == getCurrentOperationMode() ) || ( DG_MODE_GENE == getCurrentOperationMode() ) ) { - heatersStatus[ heater ].hasTargetTempChanged = FALSE; + F32 inlet = getTemperatureValue( (U32)TEMPSENSORS_HEAT_DISINFECT ); + measuredFlow = getTargetROPumpFlowRate(); + F32 highTempDuty = calculateHeaterDutyCycle( 58.0, inlet, measuredFlow ); + dutyCycle = calculateHeaterDutyCycle( 39.0, inlet, 0.8 ); + dutyCycle = ( dutyCycle < highTempDuty ? dutyCycle : highTempDuty ); + isItHandOffTime = TRUE; } - - // Calculate the running sum of the temperatures - for ( i = 0; i < TEMPERATURES_MOVING_AVG_SIZE; i++ ) - { - slope += heatersStatus[ heater ].previousTemps[ i ]; - } - - // If the heater is the primary heater, - if ( DG_PRIMARY_HEATER == heater ) - { - inletTemperature = getTemperatureValue( (U32)TEMPSENSORS_HEAT_DISINFECT ); - } + // TODO for testing only remove else { - // TODO figure out the trimmer strategy - } + // Update the temperature data array as well as the next index + heatersStatus[ heater ].previousTemps[ currentIndex ] = feedbackTemperature; + heatersStatus[ heater ].previousTempsIndex = INC_WRAP( currentIndex, 0, TEMPERATURES_MOVING_AVG_SIZE - 1 ); - // TODO add comments - slope = slope / (F32)TEMPERATURES_MOVING_AVG_SIZE; - //measuredFlow = getMeasuredROFlowRate(); TODO uncomment - measuredFlow = getTargetROPumpFlowRate(); - dutyCycle = calculateHeaterDutyCycle( targetTemperature, inletTemperature, measuredFlow ); - deltaDutyCycle = ( feedbackTemperature <= targetTemperature ? HEATERS_MAX_DUTY_CYCLE - dutyCycle : dutyCycle ); + // 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; + } - revDeltaDutyCycle = ( deltaDutyCycle - 0.0 < NEARLY_ZERO ? 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 ) / measuredFlow ) + revDeltaDutyCycle; + // Calculate the running sum of the temperatures + for ( i = 0; i < TEMPERATURES_MOVING_AVG_SIZE; i++ ) + { + slope += heatersStatus[ heater ].previousTemps[ i ]; + } - if ( fabs( targetTemperature - feedbackTemperature ) < deltaTemperature ) - { - if ( TRUE == didTimeout( heatersStatus[ heater ].rampStateStartTime, HEATERS_MIN_RAMP_TIME_MS ) ) + // If the heater is the primary heater, + if ( DG_PRIMARY_HEATER == heater ) { + inletTemperature = getTemperatureValue( (U32)TEMPSENSORS_HEAT_DISINFECT ); + } + else + { + // TODO figure out the trimmer strategy + } + + // TODO add comments + slope = slope / (F32)TEMPERATURES_MOVING_AVG_SIZE; + //measuredFlow = getMeasuredROFlowRate(); TODO uncomment for testing only + measuredFlow = getTargetROPumpFlowRate(); + dutyCycle = calculateHeaterDutyCycle( targetTemperature, inletTemperature, measuredFlow ); + deltaDutyCycle = ( feedbackTemperature <= targetTemperature ? HEATERS_MAX_DUTY_CYCLE - dutyCycle : dutyCycle ); + + revDeltaDutyCycle = ( deltaDutyCycle - 0.0 < NEARLY_ZERO ? 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 ) / measuredFlow ) + 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; } } - else if ( feedbackTemperature > targetTemperature ) - { - isItHandOffTime = TRUE; - } + // TODO potentially remove the else + if ( TRUE == isItHandOffTime ) { setHeaterDutyCycle( heater, dutyCycle ); - resetPIController( heatersStatus[ heater ].controllerID, dutyCycle ); // TODO remove? heatersStatus[ heater ].initialDutyCycle = dutyCycle; @@ -600,36 +596,12 @@ { F32 dutyCycle; - HEATERS_STATE_T state = HEATER_EXEC_STATE_CONTROL_TO_TARGET; - + 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; - // Check if the target flow has changed or the target temperature has changed. - /*if ( ( TRUE == hasFlowChanged ) || ( TRUE == heaterStatus[ heater ].hasTargetTempChanged ) ) - { - // TODO for testing, remove - if ( DG_MODE_DRAI == getCurrentOperationMode() ) - { - BOOL Test = FALSE; - } - // TODO for testing, remove - - // Moving back from control to target to ramp. - heaterStatus[ heater ].rampStateStartTime = getMSTimerCount(); - heaterStatus[ heater ].targetROFlow = targetFlow; - heaterStatus[ 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() < heaterStatus[ heater ].targetROFlow ? HEATERS_MAX_DUTY_CYCLE : HEATERS_MIN_DUTY_CYCLE ); - - // Go back to ramp state - setHeaterDutyCycle( heater, dutyCycle ); - state = HEATER_EXEC_STATE_RAMP_TO_TARGET; - }*/ - if ( TRUE == haveHeaterControlConditionsChanged( heater ) ) { state = HEATER_EXEC_STATE_RAMP_TO_TARGET; @@ -643,13 +615,13 @@ F32 deltaDutyCycle = dutyCycle - heatersStatus[ heater ].initialDutyCycle; - if ( ( fabs( deltaDutyCycle ) > 0.09 ) && ( deltaDutyCycle < 0.0 ) ) + if ( ( fabs( deltaDutyCycle ) > HEATERS_CONTROL_TO_TARGET_DUTY_CYCLE_CAP ) && ( deltaDutyCycle < 0.0 ) ) { - dutyCycle = heatersStatus[ heater ].initialDutyCycle - 0.09; // TODO add a #define + dutyCycle = heatersStatus[ heater ].initialDutyCycle - HEATERS_CONTROL_TO_TARGET_DUTY_CYCLE_CAP; } - else if ( deltaDutyCycle > 0.09 ) + else if ( deltaDutyCycle > HEATERS_CONTROL_TO_TARGET_DUTY_CYCLE_CAP ) { - dutyCycle = heatersStatus[ heater ].initialDutyCycle + 0.09; + dutyCycle = heatersStatus[ heater ].initialDutyCycle + HEATERS_CONTROL_TO_TARGET_DUTY_CYCLE_CAP; } // Cap the duty cycle ranges in case they exceeded the limit @@ -758,16 +730,20 @@ 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; } @@ -781,8 +757,6 @@ }*/ } - - return status; }