Index: firmware/App/Controllers/Heaters.c =================================================================== diff -u -r38c28a43b71d21d72906b07e9d60107b84bffb37 -r224b86c0847207c168d38fa1713a1e9116642267 --- firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision 38c28a43b71d21d72906b07e9d60107b84bffb37) +++ firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision 224b86c0847207c168d38fa1713a1e9116642267) @@ -53,26 +53,19 @@ #define MINIMUM_TARGET_TEMPERATURE 10.0F ///< Minimum allowed target temperature for the heaters. #define MAXIMUM_TARGET_TEMPERATURE 90.0F ///< Maximum allowed target temperature for the heaters. -#define MAXIMUM_IDLE_DRAIN_TARGET_TEMPERATURE 58.0F ///< Maximum allowed target temperature for the idle and drain modes. -#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.0F ///< Heaters max allowed internal temperature in C. -#define HEATERS_MAX_ALLOWED_COLD_JUNCTION_TEMPERATURE_C 80.0F ///< Heaters max allowed cold junction temperature in C. -#define HEATERS_MAX_ALLOWED_INTERNAL_TEMPERATURE_TIMEOUT_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Heaters max allowed internal temperature timeout in milliseconds. #define HEATERS_ON_NO_FLOW_TIMEOUT_MS ( 1 * MS_PER_SECOND ) ///< Heaters on with no flow time out in milliseconds. #define HEATERS_MAX_OPERATING_VOLTAGE_V 24.0F ///< Heaters max operating voltage in volts. #define HEATERS_VOLTAGE_OUT_OF_RANGE_TIMEOUT_MS ( 2 * MS_PER_SECOND ) ///< Heaters voltage out of range time out in milliseconds. #define HEATERS_MAX_VOLTAGE_OUT_OF_RANGE_TOL 0.2F ///< Heaters max voltage out of range tolerance. -#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 TRIMMER_HEATER_MAX_POWER_W 66.5F ///< Trimmer heater maximum power in Watts. +#define TRIMMER_HEATER_CONTROL_CHECK_INTERVAL_COUNT ( ( 30 * MS_PER_SECOND ) / TASK_GENERAL_INTERVAL ) ///< Trimmer heater control interval count. #define DELTA_TEMPERATURE_TIME_COSNTANT_C 8.6F ///< Delta temperature calculated from time constant. -#define MAXIMUM_ALLOWED_TARGET_TEMPERATURE_DEVIATION_C 2.5F ///< Maximum allowed temperature deviation from target temperature in C. #define PRIMARY_HEATER_DUTY_CYCLE_PER_TEMPERATURE_C 0.03F ///< Primary heaters duty cycle per temperature in C. #define DATA_PUBLISH_COUNTER_START_COUNT 70 ///< Data publish counter start count. -static const F32 WATER_SPECIFIC_HEAT_DIVIDED_BY_MINUTES = 4184 / SEC_PER_MIN; ///< Water specific heat in J/KgC / 60. +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.5F; ///< Primary heaters maximum power (main primary = 475W and small primary = 237.5W). /// Heaters exec states @@ -105,6 +98,7 @@ static HEATER_STATUS_T heatersStatus[ NUM_OF_DG_HEATERS ]; ///< Heaters status. static U32 dataPublicationTimerCounter; ///< Data publication timer counter. +static U32 trimmerHeaterControlCounter; ///< Trimmer heater control counter. static OVERRIDE_U32_T heatersDataPublishInterval = { HEATERS_DATA_PUBLISH_INTERVAL, HEATERS_DATA_PUBLISH_INTERVAL, 0, 0 }; ///< Heaters data publish time interval. // ********** private function prototypes ********** @@ -132,13 +126,15 @@ * The initHeaters initializes the heaters driver. * @details Inputs: none * @details Outputs: voltageMonitorTimeCounter, heaterStatus, - * hasTreatmentInternalTempBeenSet, dataPublicationTimerCounter + * hasTreatmentInternalTempBeenSet, dataPublicationTimerCounter, + * trimmerHeaterControlCounter * @return none *************************************************************************/ void initHeaters( void ) { DG_HEATERS_T heater; dataPublicationTimerCounter = DATA_PUBLISH_COUNTER_START_COUNT; + trimmerHeaterControlCounter = 0; for ( heater = DG_PRIMARY_HEATER; heater < NUM_OF_DG_HEATERS; heater++ ) { @@ -544,8 +540,10 @@ } // Update the calculated target temperature - heatersStatus[ DG_TRIMMER_HEATER ].calculatedTemperature = currentTemperature; - heatersStatus[ DG_TRIMMER_HEATER ].inactiveRsrvr = getInactiveReservoir(); + heatersStatus[ heater ].calculatedTemperature = currentTemperature; + heatersStatus[ heater ].inactiveRsrvr = getInactiveReservoir(); + heatersStatus[ heater ].targetFlow = targetFlowLPM; + trimmerHeaterControlCounter = 0; setHeaterDutyCycle( heater, dutyCycle ); return state; @@ -554,9 +552,9 @@ /*********************************************************************//** * @brief * The handleHeaterStateTrimmerControlToTarget function handles the trimmer - * heater's control to target. - * @details Inputs: heaterStatus - * @details Outputs: heaterStatus + * heater's control to target state. + * @details Inputs: heaterStatus, trimmerHeaterControlCounter + * @details Outputs: heaterStatus, trimmerHeaterControlCounter * @return next state of the state machine *************************************************************************/ static HEATERS_STATE_T handleHeaterStateTrimmerControlToTarget( void ) @@ -569,6 +567,17 @@ { state = HEATER_EXEC_STATE_TRIMMER_RAMP_TO_TARGET; } + else if ( ++trimmerHeaterControlCounter > TRIMMER_HEATER_CONTROL_CHECK_INTERVAL_COUNT ) + { + // When the trimmer heater is on, its duty cycle is adjusted at the control interval. For this control check, + // dialysate inlet temperature sensor is used rather than the theoretical calculations. + F32 outletRedundantTemperature = getTemperatureValue( TEMPSENSORS_INLET_DIALYSATE ); // TODO Change to TRo in DVT + F32 targetTemperature = heatersStatus[ DG_TRIMMER_HEATER ].targetTemp; + F32 targetFlowLPM = heatersStatus[ DG_TRIMMER_HEATER ].targetFlow; + F32 dutyCycle = calculateTrimmerHeaterDutyCycle( targetTemperature, outletRedundantTemperature, targetFlowLPM, TRUE ); + trimmerHeaterControlCounter = 0; + setHeaterDutyCycle( DG_TRIMMER_HEATER, dutyCycle ); + } return state; } @@ -632,7 +641,7 @@ // 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 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 ) + if ( lastFillTemperature - primaryTargetTemperature < NEARLY_ZERO ) { heaterEfficiency -= ( lastFillTemperature - primaryTargetTemperature ) * PRIMARY_HEATER_DUTY_CYCLE_PER_TEMPERATURE_C; } @@ -641,7 +650,9 @@ heaterEfficiency += ( primaryTargetTemperature - lastFillTemperature ) * PRIMARY_HEATER_DUTY_CYCLE_PER_TEMPERATURE_C; } - heaterEfficiency = ( heaterEfficiency <= 0.0 ? 0.0 : heaterEfficiency ); + // If the efficiency is less than 0, set it to 0 but if the efficiency is greater than 100, it is not enforced + // to be 100 since the duty cycle range check will cap the duty cycle to 100 anyways. + heaterEfficiency = MAX( heaterEfficiency, 0.0 ); // Update the heaters efficiency heatersStatus[ DG_PRIMARY_HEATER ].heaterEfficiency = heaterEfficiency; @@ -654,8 +665,8 @@ fabs( targetTemperature - currentTemperature ) * flow ) / PRIMARY_HEATERS_MAXIMUM_POWER_WATTS ) * heaterEfficiency; // 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 ); + dutyCycle = MIN( dutyCycle, HEATERS_MAX_DUTY_CYCLE ); + dutyCycle = MAX( dutyCycle, HEATERS_MIN_DUTY_CYCLE ); return dutyCycle; } @@ -685,11 +696,13 @@ { if ( TRUE == checkEfficiency ) { - // TODO Do we need to recalculate the efficiency? + // TODO Do we need efficiency for the trimmer heater? } } - dutyCycle = ( flow * WATER_SPECIFIC_HEAT_DIVIDED_BY_MINUTES * ( targetTemperature - currentTemperature ) * heaterEfficiency ) / TRIMMER_HEATER_MAX_POWER_W; + // Duty cycle = ( 69.73 * flow rate * deltaT / primary heater maximum power ) and multiply the duty cycle to the heater efficiency + dutyCycle = ( ( flow * WATER_SPECIFIC_HEAT_DIVIDED_BY_MINUTES * + ( targetTemperature - currentTemperature ) * heaterEfficiency ) / TRIMMER_HEATER_MAX_POWER_W ) * heaterEfficiency; // Check the boundaries of the calculated duty cycle dutyCycle = MIN( dutyCycle, HEATERS_MAX_DUTY_CYCLE ); @@ -827,14 +840,7 @@ checkPersistentAlarm( ALARM_ID_DG_MAIN_PRIMARY_HEATER_VOLTAGE_OUT_OF_RANGE, isMainPriOut, mainPri, mainPriVoltageTol ); checkPersistentAlarm( ALARM_ID_DG_SMALL_PRIMARY_HEATER_VOLTAGE_OUT_OF_RANGE, isSmallPriOut, smallPri, smallPriVoltageTol ); - //checkPersistentAlarm( ALARM_ID_DG_TRIMMER_HEATER_VOLTAGE_OUT_OF_RANGE, isTrimmerOut, trimmer, trimmerVoltageTol ); // TODO check this voltage - - // TODO test code remove - if ( TRUE == isAlarmActive(ALARM_ID_DG_TRIMMER_HEATER_VOLTAGE_OUT_OF_RANGE)) - { - BOOL test = FALSE; - } - // TODO test code remove + checkPersistentAlarm( ALARM_ID_DG_TRIMMER_HEATER_VOLTAGE_OUT_OF_RANGE, isTrimmerOut, trimmer, trimmerVoltageTol ); }