Index: firmware/App/Controllers/Heaters.c =================================================================== diff -u -raf83481e7313ed6b624e1a8ed8996a906177ad6d -r2c4dfa08ac8ead07939b4f6aba3b0073e0997706 --- firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision af83481e7313ed6b624e1a8ed8996a906177ad6d) +++ firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision 2c4dfa08ac8ead07939b4f6aba3b0073e0997706) @@ -69,13 +69,16 @@ #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 ///< Primary heaters thermal power to voltage slope. -#define PRIMARY_HEATERS_THERMAL_POWER_TO_VOLTAGE_INTERCEPT 0.21 ///< Primary heaters thermal power to voltage intercept. +#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_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). + typedef enum Heaters_Exec_States { HEATER_EXEC_STATE_NOT_RUNNING = 0, ///< Heater exec state not running. @@ -99,6 +102,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. + BOOL isThisFirstFill; ///< Heater the first fill flag indicator. PI_CONTROLLER_ID_T controllerID; ///< Heater PI controller ID TODO remove this? @@ -119,7 +123,7 @@ static HEATERS_STATE_T handleHeaterStateControlToTarget( DG_HEATERS_T heater ); static void setHeaterDutyCycle( DG_HEATERS_T heater, F32 pwm ); -static F32 calculateHeaterDutyCycle( F32 targetTemperature, F32 currentTemperature, F32 flow ); +static F32 calculatePrimaryHeaterDutyCycle( F32 targetTemperature, F32 currentTemperature, F32 flow ); static BOOL haveHeaterControlConditionsChanged( DG_HEATERS_T heater ); static void setMainPrimaryHeaterPWM( F32 pwm ); @@ -162,6 +166,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 ].isThisFirstFill = TRUE; } // Initialize the PI controller for the trimmer heater @@ -422,12 +427,6 @@ heatersStatus[ heater ].startHeaterSignal = FALSE; heatersStatus[ heater ].targetROFlow = getTargetROPumpFlowRate(); - // TODO for testing remove - heatersStatus[ heater ].targetTemp = heatersStatus[ heater ].originalTargetTemp; - F32 dutyCycle = calculateHeaterDutyCycle( 39.0, getTemperatureValue( (U32)TEMPSENSORS_HEAT_DISINFECT ), 0.8 ); - setHeaterDutyCycle( heater, dutyCycle ); - // TODo for testing remove - /*f ( ( DG_MODE_DRAI == getCurrentOperationMode() ) || ( DG_MODE_GENE == getCurrentOperationMode() ) ) { heatersStatus[ heater ].targetTemp = MAXIMUM_IDLE_DRAIN_TARGET_TEMPERATURE; @@ -470,27 +469,34 @@ *************************************************************************/ static HEATERS_STATE_T handleHeaterStateRampToTarget( DG_HEATERS_T heater ) { + F32 dutyCycle; + HEATERS_STATE_T state = HEATER_EXEC_STATE_RAMP_TO_TARGET; - TEMPERATURE_SENSORS_T sensor = heatersStatus[ heater ].feedbackSensor; - F32 inletTemperature = getTemperatureValue( (U32)TEMPSENSORS_HEAT_DISINFECT ); - F32 feedbackTemperature = getTemperatureValue( (U32)sensor ); - F32 targetFlow = getTargetROPumpFlowRate(); - // Continuously get the target temperature in case it was changed dynamically - F32 targetTemperature = heatersStatus[ heater ].originalTargetTemp; - BOOL hasFlowChanged = ( fabs( targetFlow - heatersStatus[ heater ].targetROFlow ) > NEARLY_ZERO ? TRUE : FALSE ); - F32 dutyCycle = heatersStatus[ heater ].dutycycle; - // Set the hand off flag to false - BOOL isItHandOffTime = FALSE; + F32 inletTemperature = getTemperatureValue( (U32)TEMPSENSORS_HEAT_DISINFECT ); + F32 feedbackTemperature = getTemperatureValue( (U32)heatersStatus[ heater ].feedbackSensor ); + F32 targetFlow = getTargetROPumpFlowRate(); + BOOL isItHandOffTime = FALSE; - // TODO remve this code if ( DG_MODE_FILL == getCurrentOperationMode() ) { - dutyCycle = calculateHeaterDutyCycle( 39.0, inletTemperature, 0.8 ); - heatersStatus[ heater ].targetTemp = heatersStatus[ heater ].originalTargetTemp; + F32 flow; + F32 targetTemperature = heatersStatus[ heater ].originalTargetTemp; + + if ( TRUE == heatersStatus[ heater ].isThisFirstFill ) + { + flow = targetFlow; + heatersStatus[ heater ].isThisFirstFill = FALSE; + } + + //dutyCycle = calculatePrimaryHeaterDutyCycle( 39.0, inletTemperature, 0.8 ); + //heatersStatus[ heater ].targetTemp = heatersStatus[ heater ].originalTargetTemp; } + // TODO For testing only remove + dutyCycle = calculatePrimaryHeaterDutyCycle( 39.0, inletTemperature, 0.8 ); + heatersStatus[ heater ].targetTemp = heatersStatus[ heater ].originalTargetTemp; + // TODO for testing only remove isItHandOffTime = TRUE; - // TODO remove this code /*if ( heatersStatus[ heater ].initialDutyCycle - 0.0 < NEARLY_ZERO ) @@ -586,7 +592,7 @@ if ( TRUE == isItHandOffTime ) { - //setHeaterDutyCycle( heater, dutyCycle ); + setHeaterDutyCycle( heater, dutyCycle ); //heatersStatus[ heater ].initialDutyCycle = dutyCycle; //TODO do we need this? @@ -688,23 +694,21 @@ /*********************************************************************//** * @brief - * The calculateHeaterDutyCycle function calculates a heater's duty cycle - * by providing the + * The calculatePrimaryHeaterDutyCycle function calculates the primary + * 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 * @return calculated duty cycle *************************************************************************/ -static F32 calculateHeaterDutyCycle( F32 targetTemperature, F32 currentTemperature, F32 flow ) +static F32 calculatePrimaryHeaterDutyCycle( F32 targetTemperature, F32 currentTemperature, F32 flow ) { - // The power is proportional to square root of deltaT x flow - F32 power = sqrt( fabs( targetTemperature - currentTemperature ) * flow ); + // Duty cycle = ( 69.73 * flow rate * deltaT / primary heater maximum power ) ^ 1/2 + F32 dutyCycle = sqrt( ( WATER_SPECIFIC_HEAT_DIVIDED_BY_MINUTES * + fabs( targetTemperature - currentTemperature ) * flow ) / PRIMARY_HEATERS_MAXIMUM_POWER_WATTS ); - // PWM = ( power * A - B ) - F32 dutyCycle = ( ( power * PRIMARY_HEATERS_THERMAL_POWER_TO_VOLTAGE_SLOPE ) - PRIMARY_HEATERS_THERMAL_POWER_TO_VOLTAGE_INTERCEPT ); - // Check the boundaries of the calculated duty cycle dutyCycle = ( dutyCycle > HEATERS_MAX_DUTY_CYCLE ? HEATERS_MAX_DUTY_CYCLE : dutyCycle ); dutyCycle = ( dutyCycle < HEATERS_MIN_DUTY_CYCLE ? HEATERS_MIN_DUTY_CYCLE : dutyCycle );