Index: firmware/App/Controllers/Heaters.c =================================================================== diff -u -re803f3e6d135641015dc78e2aeac0a5489c9492c -rd31e9b40e9d56df8fa3551bbba63f6bec3a72811 --- firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision e803f3e6d135641015dc78e2aeac0a5489c9492c) +++ firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision d31e9b40e9d56df8fa3551bbba63f6bec3a72811) @@ -1,17 +1,17 @@ /************************************************************************** * -* Copyright (c) 2024-2024 Diality Inc. - All Rights Reserved. +* Copyright (c) 2024-2026 Diality Inc. - All Rights Reserved. * * THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN * WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. * * @file Heaters.c * * @author (last) Vinayakam Mani -* @date (last) 07-Oct-2024 +* @date (last) 03-Mar-2026 * * @author (original) Vinayakam Mani -* @date (original) 07-Oct-2024 +* @date (original) 11-Oct-2024 * ***************************************************************************/ @@ -23,6 +23,7 @@ #include "Level.h" #include "MessageSupport.h" #include "Messaging.h" +#include "ModeGenDialysate.h" //#include "NVDataMgmt.h" #include "OperationModes.h" #include "PersistentAlarm.h" @@ -41,6 +42,7 @@ */ // ********** private definitions ********** + #define AC_HEATER_TX_MAX_DUTY_CYCLE 0.50F ///< AC Heater treatment mode max duty cycle (50% of 1400W : 700W ) #define AC_HEATER_HEAT_MAX_DUTY_CYCLE 0.70F ///< AC Heater heat disinfect mode max duty cycle (70% of 1400W : 980W ) #define AC_HEATER_MAX_DUTY_CYCLE 1.0F ///< AC Heater max duty cycle (100.0%) or ON state @@ -53,14 +55,10 @@ #define HEATER_CNTL_TRANSFER_DELTA_TEMP_C 0.50F ///< AC heater delta temperature to transfer control from open to close loop #define ADJ_DELTA_TEMP_STEP 2.0F ///< Adjust target temperature based on D28 feedback per cycle. #define MAX_ADJ_DELTA_TEMP_C 7.0F ///< Maximum adjusted delta temperature to add/remove from calculated target temperature - #define D5_HEAT_TX_INIT_FEED_FORWARD 0.0F ///< Initial Feed forward term for heater control -//#define D5_HEAT_TX_P_COEFFICIENT 0.050F ///< P Term for AC primary heater control during treatment mode. -//#define D5_HEAT_TX_I_COEFFICIENT 0.015F ///< I Term for AC primary heater control during treatment mode. +#define D5_HEAT_TX_P_COEFFICIENT 0.017F ///< P Term for AC primary heater control during treatment mode. +#define D5_HEAT_TX_I_COEFFICIENT 0.002F ///< I Term for AC primary heater control during treatment mode. -#define D5_HEAT_TX_P_COEFFICIENT 0.035F ///< P Term for AC primary heater control during treatment mode. -#define D5_HEAT_TX_I_COEFFICIENT 0.004F ///< I Term for AC primary heater control during treatment mode. - #define D45_HEAT_P_COEFFICIENT 0.20F ///< P Term for trimmer heater control. #define D45_HEAT_I_COEFFICIENT 0.05F ///< I Term for trimmer heater control. #define D45_HEAT_TX_INIT_FEED_FORWARD 0.0F ///< Initial Feed forward term for heater control @@ -76,26 +74,42 @@ #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 D5_HEATER_DEADBAND_CONTROL 0.1F ///< Heater deadband range for conrtol. +#define D5_HEATER_DEADBAND_CONTROL 0.1F ///< Heater dead band range for control. +#define D5_HEATER_PWM_ADJ_SLOPE_FACTOR 0.00005F ///< AC heater close loop PWM adjustment slope factor +#define D5_HEATER_PWM_INTERCEPT_FACTOR 0.0055F ///< AC heater close loop PWM adjustment intercept factor -//#define D5_HEAT_CONTROL_INTERVAL_MS 30000 /// Primary heater control interval in milli seconds #define D5_HEAT_CONTROL_INTERVAL_MS 3000 /// Primary heater control interval in milli seconds #define D5_HEAT_CONTROL_INTERVAL_COUNT ( D5_HEAT_CONTROL_INTERVAL_MS / TASK_GENERAL_INTERVAL ) ///< Primary heater control interval count. #define D45_HEAT_CONTROL_INTERVAL_MS ( 1 * MS_PER_SECOND ) ///< Trimmer heater control interval in milli seconds #define D45_HEAT_CONTROL_INTERVAL_COUNT ( D45_HEAT_CONTROL_INTERVAL_MS / TASK_GENERAL_INTERVAL ) ///< Trimmer heater control interval count. -#define D5_TARGET_TEMP_ADJUST_INTERVAL_MS ( 3 * SEC_PER_MIN * MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Adjust primary target temperature -#define PRIMARY_HEATER_MAX_PWR_WATTS 1400.0F ///< AC Primary Heater Max Power consumeption in Watts -#define TX_PRIMARY_HEATER_MAX_PWR_WATTS 700.0F ///< Estimated power to be supplied to the primary heater during treatement mode +#define D5_TARGET_TEMP_ADJUST_LOW_QD_INTERVAL ( 3 * SEC_PER_MIN * MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Adjust primary target temperature - outer loop control interval for low Qd. +#define D5_TARGET_TEMP_ADJUST_HIGH_QD_INTERVAL ( 1 * SEC_PER_MIN * MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Adjust primary target temperature - outer loop control interval for high Qd. +#define PRIMARY_HEATER_MAX_PWR_WATTS 1400.0F ///< AC Primary Heater Max Power consumption in Watts +#define TX_PRIMARY_HEATER_MAX_PWR_WATTS 700.0F ///< Estimated power to be supplied to the primary heater during treatment mode #define HEAT_PRIMARY_HEATER_MAX_PWR_WATTS 980.0F ///< Estimated power to be supplied to the primary heater during heat disinfect mode #define MAX_INLET_FLOW_LPM ( 600.0F / 1000.0F ) ///< Maximum inlet flow to hydraulics chamber from FP #define LITER_IN_ML 1000.0F ///< Liter in milliliter units #define TRIMMER_HEATER_MAX_PWR_WATTS 120.0F ///< Maximum power supplied to trimmer heater -#define AC_HEATER_PWM_PERIOD 10000 ///< PWM period 100 ms( in 10us resoultion), 1/10Hz = 1000000us/10us = 10000. +#define AC_HEATER_PWM_PERIOD 10000 ///< PWM period 100ms( in 10us resolution), 1/10Hz = 1000000us/10us = 10000. #define AC_HEATER_EFFICIENCY 0.90F ///< Approximated AC heater efficiency to be used in energy calcualtions. #define DC_HEATER_EFFICIENCY 1.0F ///< DC heater efficiency #define D5_HEAT_CONTROL_INTERVAL_START_COUNT ( D5_HEAT_CONTROL_INTERVAL_COUNT - 10 ) ///< AC heater control interval start count to jump feedforward control from open loop. +#define RINSE_PUMP_EST_FLOWRATE 110 ///< Estimated rinse pump flow rate #define DATA_PUBLISH_COUNTER_START_COUNT 70 ///< Data publish counter start count. +#define AC_HEAT_EFFICIENCY_LOW 0.1F ///< Lower allowable range for heater efficiency adjustment +#define AC_HEAT_EFFICIENCY_HIGH 10.0F ///< higher allowable range for heater efficiency adjustment +#define AC_HEAT_PWM_ADJUST_PERCENT 0.5F ///< AC heater PWM gain adjustment percentage for close loop control +#define AC_HEAT_PWM_ADJ_MIN -0.10F ///< Minimum PWM value that can adjust the calculated Feed forward value +#define AC_HEAT_PWM_ADJ_MAX 0.10F ///< Maximum PWM value that can adjust the calculated Feed forward value +#define AC_HEAT_PWM_MIN_MAX_FACTOR 2.0F ///< factor used to calculate range values for PWM adjustment +#define D5_HEAT_OUT_TX_P_COEFFICIENT 0.5F ///< P Term for AC primary heater outer loop control during treatment mode. +#define D5_HEAT_OUT_TX_I_COEFFICIENT 0.40F ///< I Term for AC primary heater outer loop control during treatment mode. +#define D5_HEAT_OUT_MIN_DELTA_TEMP 0.0F ///< Minimum Delta temperature that can be adjusted for D5 control +#define D5_HEAT_OUT_MAX_DELTA_TEMP 50.0 ///< Maximum Delta temperature that can be adjusted for D5 control +#define D5_HEAT_OUT_DEADBAND_CONTROL 0.1F ///< Heater outer loop dead band range for control. +#define HIGH_DIAL_FLOW_RATE 300.0F ///< Decide outer loop heater control based on the dialysate flow rate + //static const F32 HEATERS_VOLTAGE_TOLERANCE_V = HEATERS_MAX_OPERATING_VOLTAGE_V * HEATERS_MAX_VOLTAGE_OUT_OF_RANGE_TOL; ///< Heaters voltage tolerance in volts. /// Heaters data structure @@ -120,26 +134,33 @@ F32 temperature; ///< Temperature range ( 10.0 to 90.0 deg ) } HEATER_START_CMD_PAYLOAD_T; +// ********** private data ********** + static HEATER_STATUS_T heatersStatus[ NUM_OF_DD_HEATERS ]; ///< Heaters status. static OVERRIDE_F32_T targetTempC[ NUM_OF_DD_HEATERS ]; ///< Heater target temperature. -static OVERRIDE_F32_T control[ NUM_OF_DD_HEATERS ]; ///< Heater control ( Primary : On/Off, Trimmer : Dutycycle). +static OVERRIDE_F32_T control[ NUM_OF_DD_HEATERS ]; ///< Heater control ( Primary : On/Off, Trimmer : Duty cycle). static OVERRIDE_F32_T pwmPeriod[ NUM_OF_DD_HEATERS ]; ///< Total PWM period ( ON state + Off State of PWM) static U32 controlInterval[ NUM_OF_DD_HEATERS ]; ///< Heater control interval time. static U32 dataPublicationTimerCounter; ///< Data publication timer counter. static U32 primaryTargetTempAdjCounter; ///< Primary target temperature adjustment counter. static BOOL isTargetTempAdjusted; ///< Flag indicating that target temperature is adjusted -static U32 adjustedPrimaryTargetTemp; ///< Adjusted primary target temperature +static F32 adjustedPrimaryTargetTemp; ///< Adjusted primary target temperature static BOOL isDialyzerTempFeedbackEnabled; ///< Flag indicating enable/disable the dilayser temp ( D28) based feedback adjustment static const F32 WATER_SPECIFIC_HEAT_DIVIDED_BY_MINUTES = 4184.0F / (F32)SEC_PER_MIN; ///< Water specific heat in J/KgC / 60. static OVERRIDE_U32_T heatersDataPublishInterval = { HEATERS_DATA_PUBLISH_INTERVAL, HEATERS_DATA_PUBLISH_INTERVAL, 0, 0 }; ///< Heaters data publish time interval. static F32 convertDC; ///< AC Heater converted duty cycle -static F32 lastDialTargetTemperatureSet; ///< last dialysate target temperature set for heater control -static BOOL startupHeaterControl; ///< First time control with the energy equation. +static F32 d5Efficiency; ///< AC heater efficiency factor. +static F32 adjustD5PWM; ///< AC heater close loop PWM adjustment +static F32 capAdjustD5PWM; ///< AC heater PWM adjustment after range check +static F32 lastDialTargetTemperatureSet[ NUM_OF_DD_HEATERS ]; ///< last dialysate target temperature set for heater control +static F32 d5FeedForward; ///< AC heater feed forward calculated value +static U32 d5OuterLoopControlInterval; ///< AC heater outer loop control valve //For testing #ifdef __HEATERS_DEBUG__ static F32 pIControlSignal[ NUM_OF_CONTROLLER_SIGNAL ]; #endif + // ********** private function prototypes ********** static HEATERS_STATE_T handleHeaterStateOff( DD_HEATERS_T heater ); @@ -191,14 +212,19 @@ convertDC = 0.0F; controlInterval[ D5_HEAT ] = D5_HEAT_CONTROL_INTERVAL_COUNT; controlInterval[ D45_HEAT ] = D45_HEAT_CONTROL_INTERVAL_COUNT; + d5OuterLoopControlInterval = D5_TARGET_TEMP_ADJUST_HIGH_QD_INTERVAL; // Assign counter close to the target period heatersStatus[ D5_HEAT ].controlIntervalCounter = D5_HEAT_CONTROL_INTERVAL_START_COUNT; heatersStatus[ D45_HEAT ].controlIntervalCounter = 0; - startupHeaterControl = TRUE; - lastDialTargetTemperatureSet = 0.0F; + lastDialTargetTemperatureSet[ D5_HEAT ] = 0.0F; + lastDialTargetTemperatureSet[ D45_HEAT ] = 0.0F; primaryTargetTempAdjCounter = 0; adjustedPrimaryTargetTemp = 0.0F; + d5Efficiency = AC_HEATER_EFFICIENCY; + adjustD5PWM = 0.0F; + capAdjustD5PWM = 0.0F; + d5FeedForward = 0.0F; isTargetTempAdjusted = FALSE; isDialyzerTempFeedbackEnabled = TRUE; @@ -227,6 +253,9 @@ initializePIController( PI_CONTROLLER_ID_D5_HEAT, HEATERS_MIN_DUTY_CYCLE, D5_HEAT_TX_P_COEFFICIENT, D5_HEAT_TX_I_COEFFICIENT, HEATERS_MIN_DUTY_CYCLE, AC_HEATER_TX_MAX_DUTY_CYCLE, TRUE, D5_HEAT_TX_INIT_FEED_FORWARD ); + initializePIController( PI_CONTROLLER_ID_D5_HEAT_OUTER_LOOP, D5_HEAT_OUT_MIN_DELTA_TEMP, D5_HEAT_OUT_TX_P_COEFFICIENT, D5_HEAT_OUT_TX_I_COEFFICIENT, + D5_HEAT_OUT_MIN_DELTA_TEMP, D5_HEAT_OUT_MAX_DELTA_TEMP, TRUE, D5_HEAT_TX_INIT_FEED_FORWARD ); + // Initialize the trimmer heater PI controller initializePIController( PI_CONTROLLER_ID_D45_HEAT, HEATERS_MIN_DUTY_CYCLE, D45_HEAT_P_COEFFICIENT, D45_HEAT_I_COEFFICIENT, HEATERS_MIN_DUTY_CYCLE, DC_HEATER_MAX_DUTY_CYCLE, FALSE, D45_HEAT_TX_INIT_FEED_FORWARD ); @@ -269,18 +298,12 @@ // Check if the requested temperature is within the allowed range if ( ( ( targetTemperature >= HEATER_TARGET_TEMPERATURE_MIN ) && ( targetTemperature <= HEATER_TARGET_TEMPERATURE_MAX ) ) && - ( lastDialTargetTemperatureSet != targetTemperature ) ) + ( lastDialTargetTemperatureSet[ heater ] != targetTemperature ) ) { targetTempC[ heater ].data = targetTemperature; heatersStatus[ heater ].hasTargetTempChanged = TRUE; result = TRUE; - lastDialTargetTemperatureSet = targetTemperature; - - if ( D5_HEAT == heater ) - { - startupHeaterControl = TRUE; - } - + lastDialTargetTemperatureSet[ heater ] = targetTemperature; } } else @@ -366,9 +389,11 @@ // check heater state if ( HEATER_EXEC_STATE_CONTROL_TO_TARGET == heatersStatus[ heater ].state ) { - // Set flag to recalculate the feedforward signals - startupHeaterControl = TRUE; + // Reset the adjusted temperature target isTargetTempAdjusted = FALSE; + + // Reset the AC heater PWM adjustment + adjustD5PWM = HEATERS_MIN_DUTY_CYCLE; } } } @@ -397,15 +422,21 @@ *************************************************************************/ static void updatePrimaryHeaterTargetTemp( void ) { - if ( ++primaryTargetTempAdjCounter >= D5_TARGET_TEMP_ADJUST_INTERVAL_MS ) + if ( ++primaryTargetTempAdjCounter >= d5OuterLoopControlInterval ) { F32 targetTempfromTD = getTDTargetDialysateTemperature(); - F32 measuredTempAtDialyzer = getConductivityTemperatureValue( D27_COND ); +#ifdef __TEENSY_CONDUCTIVITY_DRIVER__ + F32 measuredTempAtDialyzer = getTeensyConductivityTemperatureValue( D27_COND ); +#else + F32 measuredTempAtDialyzer = getFilteredConductivitySensorTemperature( D27_COND ); +#endif F32 calcTargetTemp = getHeaterTargetTemperature( D5_HEAT ); F32 dialysateFlowrate = getTDDialysateFlowrate(); F32 deltaTempC = targetTempfromTD - measuredTempAtDialyzer; F32 capDeltaTempC = MIN( fabs(deltaTempC), ADJ_DELTA_TEMP_STEP ); - + F32 ctrl = 0.0F; + F32 updatedTarget = 0.0F; +#if 0 //Assign the initial calcualted temp for adjsutment if ( FALSE == isTargetTempAdjusted ) { @@ -438,6 +469,23 @@ isTargetTempAdjusted = TRUE; primaryTargetTempAdjCounter = 0; +#else + if ( FALSE == isTargetTempAdjusted ) + { + isTargetTempAdjusted = TRUE; + adjustedPrimaryTargetTemp = calcTargetTemp; + resetPIController( PI_CONTROLLER_ID_D5_HEAT_OUTER_LOOP, calcTargetTemp, HEATERS_MIN_DUTY_CYCLE ); + } + else if ( fabs(deltaTempC) >= D5_HEAT_OUT_DEADBAND_CONTROL ) + { + updatedTarget = calculateUpdatedD28TargetDialysateTemp(); + setHeaterTargetTemperature( D5_HEAT, updatedTarget ); + ctrl = runPIController( PI_CONTROLLER_ID_D5_HEAT_OUTER_LOOP, getHeaterTargetTemperature( D5_HEAT ), measuredTempAtDialyzer ); + adjustedPrimaryTargetTemp = ctrl; + } + + primaryTargetTempAdjCounter = 0; +#endif } } @@ -488,7 +536,6 @@ if ( D5_HEAT == heater ) { heatersStatus[ D5_HEAT ].controlIntervalCounter = D5_HEAT_CONTROL_INTERVAL_START_COUNT; - startupHeaterControl = TRUE; } else { @@ -648,6 +695,7 @@ F32 ctrl = 0.0F; DD_OP_MODE_T opMode = getCurrentOperationMode(); F32 measuredTemperature = 0.0F; + F32 feedforward = 0.0F; F32 targetTemperature = getHeaterTargetTemperature( heater ); if ( D5_HEAT == heater ) @@ -661,6 +709,10 @@ if ( capDeltaTempC >= HEATER_CNTL_TRANSFER_DELTA_TEMP_C ) { + // Reset PI Controllers with + resetPIController( PI_CONTROLLER_ID_D5_HEAT, HEATERS_MIN_DUTY_CYCLE, feedforward ); + resetPIController( PI_CONTROLLER_ID_D5_HEAT_OUTER_LOOP, targetTemperature, HEATERS_MIN_DUTY_CYCLE ); + // Transfer Control to target when delta temp is minimal. state = HEATER_EXEC_STATE_CONTROL_TO_TARGET; } @@ -722,10 +774,14 @@ { HEATERS_STATE_T state = HEATER_EXEC_STATE_CONTROL_TO_TARGET; F32 targetTemperature = getHeaterTargetTemperature( heater ); - F32 inletTemperature = 0.0F; F32 measuredTemperature = 0.0F; F32 ctrl = 0.0F; - +#if 0 + F32 d5_eff = 0.0F; + F32 d5_p_gain = 0.0F; + F32 d5_final_FF = 0.0F; + F32 d5_cap_final_FF = 0.0F; +#endif // Update primary heater target temperature at defined interval if ( D5_HEAT == heater ) { @@ -736,45 +792,73 @@ { if ( D5_HEAT == heater ) { - measuredTemperature = getD4AverageTemperature(); // Inlet temperature post heat exchanger - inletTemperature = getTemperatureValue( X6_TEMP ); + F32 inletTemperature = getD78AverageTemperature(); + F32 deltaTempC = targetTemperature - inletTemperature; + F32 capDeltaTempC = MAX( deltaTempC, HEATERS_ZERO_DELTA_TEMP_C ); + F32 flowrate = ( getTDDialysateFlowrate() + RINSE_PUMP_EST_FLOWRATE ) / LITER_IN_ML ; + d5FeedForward = calculateDutyCycle( flowrate, capDeltaTempC, PRIMARY_HEATER_MAX_PWR_WATTS, d5Efficiency, + HEATERS_MIN_DUTY_CYCLE, AC_HEATER_TX_MAX_DUTY_CYCLE ); - if ( TRUE == startupHeaterControl ) + //Update the calculated feed forward value + setPIControllerFeedForward( PI_CONTROLLER_ID_D5_HEAT, d5FeedForward ); + + // decide outer loop control interval based on the Qd + flowrate = getTDDialysateFlowrate(); + d5OuterLoopControlInterval = ( flowrate >= HIGH_DIAL_FLOW_RATE ? D5_TARGET_TEMP_ADJUST_HIGH_QD_INTERVAL : D5_TARGET_TEMP_ADJUST_LOW_QD_INTERVAL ); + + // If D28 feedback control is enabled and adjusted temp calculation is done + // then update the target temperature. + if ( ( TRUE == isTargetTempAdjusted ) && ( TRUE == isDialyzerTempFeedbackEnabled ) ) { - F32 deltaTempC = targetTemperature - inletTemperature; - F32 capDeltaTempC = MAX( deltaTempC, HEATERS_ZERO_DELTA_TEMP_C ); - F32 flowrate = getTDDialysateFlowrate() / LITER_IN_ML ; - F32 feedforward = calculateDutyCycle( flowrate, capDeltaTempC, PRIMARY_HEATER_MAX_PWR_WATTS, AC_HEATER_EFFICIENCY, - HEATERS_MIN_DUTY_CYCLE, AC_HEATER_TX_MAX_DUTY_CYCLE ); - startupHeaterControl = FALSE; - control[ heater ].data = feedforward; - resetPIController( PI_CONTROLLER_ID_D5_HEAT, HEATERS_MIN_DUTY_CYCLE, feedforward ); + targetTemperature = adjustedPrimaryTargetTemp; } - else +#if 1 + measuredTemperature = getD4AverageTemperature(); + deltaTempC = fabs( targetTemperature - measuredTemperature ); + + if ( deltaTempC >= D5_HEATER_DEADBAND_CONTROL ) { - F32 deltaTempC = 0.0F; + ctrl = runPIController( PI_CONTROLLER_ID_D5_HEAT, targetTemperature, measuredTemperature ); + control[ heater ].data = ctrl; + } +#else + measuredTemperature = getD4AverageTemperature(); + deltaTempC = targetTemperature - measuredTemperature; + capDeltaTempC = fabs(deltaTempC); + d5_p_gain = ( D5_HEATER_PWM_ADJ_SLOPE_FACTOR * getTDDialysateFlowrate() ) + D5_HEATER_PWM_INTERCEPT_FACTOR; - // If D28 feedback control is enabled and adjusted temp calculation is done - // then update the target temperature. - if ( ( TRUE == isTargetTempAdjusted ) && ( TRUE == isDialyzerTempFeedbackEnabled ) ) + if ( d5FeedForward > NEARLY_ZERO ) + { + if ( capDeltaTempC >= D5_HEATER_DEADBAND_CONTROL ) { - targetTemperature = adjustedPrimaryTargetTemp; - } - deltaTempC = fabs( targetTemperature - measuredTemperature ); + F32 minAdjPWM = -(d5_p_gain * AC_HEAT_PWM_MIN_MAX_FACTOR); + F32 maxAdjPWM = d5_p_gain * AC_HEAT_PWM_MIN_MAX_FACTOR; - if ( deltaTempC >= D5_HEATER_DEADBAND_CONTROL ) - { - ctrl = runPIController( PI_CONTROLLER_ID_D5_HEAT, targetTemperature, measuredTemperature ); - control[ heater ].data = ctrl; + // Compute the PWM adjustment with 50% gain adjustment + adjustD5PWM += ( d5_p_gain * AC_HEAT_PWM_ADJUST_PERCENT * deltaTempC ); + adjustD5PWM = RANGE(adjustD5PWM, minAdjPWM, maxAdjPWM ); } } + else + { + //When feed forward produces zero PWM, no adjustment is needed + adjustD5PWM = HEATERS_MIN_DUTY_CYCLE; + } + + // Update the feed forward PWM with the close loop adjustment + d5_final_FF = d5FeedForward + adjustD5PWM; + d5_cap_final_FF = RANGE(d5_final_FF,HEATERS_MIN_DUTY_CYCLE,AC_HEATER_TX_MAX_DUTY_CYCLE ); + + // assign the feed forward control + control[ heater ].data = d5_cap_final_FF; +#endif #ifdef __HEATERS_DEBUG__ U32 i; for ( i = 0; i < NUM_OF_CONTROLLER_SIGNAL; i++ ) { - pIControlSignal[ i ] = getPIControllerSignals( PI_CONTROLLER_ID_D5_HEAT, (PI_CONTROLLER_SIGNALS_ID)i ); + pIControlSignal[ i ] = getPIControllerSignals( PI_CONTROLLER_ID_D5_HEAT_OUTER_LOOP, (PI_CONTROLLER_SIGNALS_ID)i ); } #endif } @@ -842,6 +926,9 @@ F32 control = getHeaterControl( heater ); F32 period = getHeaterPWMPeriod ( heater ); + //Make sure PWM control is enabled all time + setFPGAD5HeaterPWMEnableControl( TRUE ); + if ( D5_HEAT == heater ) { //Convert duty cycle into LowState and multiply by period @@ -971,7 +1058,7 @@ data.d45_HeaterTargetTemp = getHeaterTargetTemperature( D45_HEAT ); data.d5_HeaterState = heatersStatus[ D5_HEAT ].state; data.d45_HeaterState = heatersStatus[ D45_HEAT ].state; - data.d5_dutyCycleCnt = convertDC; + data.d5_feedforward = d5FeedForward * HEATERS_DUTY_CYCLE_CONVERSION_FACTOR; data.d5_PWMPeriod = getHeaterPWMPeriod( D5_HEAT ); data.d5_adjsutedTargetTemp = adjustedPrimaryTargetTemp; data.d5_targetTempFromTD = getTDTargetDialysateTemperature(); @@ -986,7 +1073,6 @@ data.dbg8 = pIControlSignal[ 7 ]; data.dbg9 = pIControlSignal[ 8 ]; #endif - dataPublicationTimerCounter = 0; broadcastData( MSG_ID_DD_HEATERS_DATA, COMM_BUFFER_OUT_CAN_DD_BROADCAST, (U08*)&data, sizeof( HEATERS_DATA_T ) );