Index: firmware/App/Controllers/Heaters.c =================================================================== diff -u -rd748813399d38ef5b71d760e327e368cc82d7a38 -r3ebcff44116a7853d2011c7b2f1eb38c1f37ba2a --- firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision d748813399d38ef5b71d760e327e368cc82d7a38) +++ firmware/App/Controllers/Heaters.c (.../Heaters.c) (revision 3ebcff44116a7853d2011c7b2f1eb38c1f37ba2a) @@ -54,7 +54,7 @@ #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 AC_HEATER_EFFICIENCY_ADJ 0.01F ///< AC heater efficiency adjustment factor ( 1%) #define D5_HEAT_TX_INIT_FEED_FORWARD 0.0F ///< Initial Feed forward term for heater control #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. @@ -74,25 +74,41 @@ #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 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 D5_TARGET_TEMP_ADJUST_INTERVAL_MS ( 1 * 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 consumption in Watts #define TX_PRIMARY_HEATER_MAX_PWR_WATTS 700.0F ///< Estimated power to be supplied to the primary heater during treatement 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. + + //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 @@ -121,7 +137,7 @@ 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. @@ -132,8 +148,11 @@ 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 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 BOOL startupHeaterControl; ///< First time control with the energy equation. +static F32 d5FeedForward; ///< AC heater feed forward calculated value //For testing #ifdef __HEATERS_DEBUG__ @@ -195,11 +214,14 @@ // 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[ 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; @@ -228,6 +250,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 ); @@ -276,11 +301,6 @@ heatersStatus[ heater ].hasTargetTempChanged = TRUE; result = TRUE; lastDialTargetTemperatureSet[ heater ] = targetTemperature; - - if ( D5_HEAT == heater ) - { - startupHeaterControl = TRUE; - } } } else @@ -366,9 +386,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; } } } @@ -409,7 +431,9 @@ F32 dialysateFlowrate = getTDDialysateFlowrate(); F32 deltaTempC = targetTempfromTD - measuredTempAtDialyzer; F32 capDeltaTempC = MIN( fabs(deltaTempC), ADJ_DELTA_TEMP_STEP ); + F32 ctrl = 0.0F; +#if 0 //Assign the initial calcualted temp for adjsutment if ( FALSE == isTargetTempAdjusted ) { @@ -442,6 +466,16 @@ isTargetTempAdjusted = TRUE; primaryTargetTempAdjCounter = 0; +#else + if ( fabs(deltaTempC) >= D5_HEAT_OUT_DEADBAND_CONTROL ) + { + ctrl = runPIController( PI_CONTROLLER_ID_D5_HEAT_OUTER_LOOP, targetTempfromTD, measuredTempAtDialyzer ); + adjustedPrimaryTargetTemp = ctrl; + } + + isTargetTempAdjusted = TRUE; + primaryTargetTempAdjCounter = 0; +#endif } } @@ -492,7 +526,6 @@ if ( D5_HEAT == heater ) { heatersStatus[ D5_HEAT ].controlIntervalCounter = D5_HEAT_CONTROL_INTERVAL_START_COUNT; - startupHeaterControl = TRUE; } else { @@ -652,6 +685,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 ) @@ -665,6 +699,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; } @@ -726,10 +764,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 ) { @@ -740,64 +782,103 @@ { if ( D5_HEAT == heater ) { - measuredTemperature = getD4AverageTemperature(); // Inlet temperature post heat exchanger - inletTemperature = getTemperatureValue( D78_TEMP ); - - if ( TRUE == startupHeaterControl ) + 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 1 + //Update the calculated feed forward value + setPIControllerFeedForward( PI_CONTROLLER_ID_D5_HEAT, d5FeedForward ); +#else + d5_p_gain = ( D5_HEATER_PWM_ADJ_SLOPE_FACTOR * getTDDialysateFlowrate() ) + D5_HEATER_PWM_INTERCEPT_FACTOR; +#endif + // 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); - // If D28 feedback control is enabled and adjusted temp calculation is done - // then update the target temperature. - if ( ( TRUE == isTargetTempAdjusted ) && ( TRUE == isDialyzerTempFeedbackEnabled ) ) +// // Adjusted efficiency used for next feed forward control +// if ( capDeltaTempC >= D5_HEATER_DEADBAND_CONTROL ) +// { +// if ( deltaTempC > NEARLY_ZERO ) +// { +// d5_eff = d5Efficiency - ( capDeltaTempC * AC_HEATER_EFFICIENCY_ADJ ); +// } +// else +// { +// d5_eff = d5Efficiency + ( capDeltaTempC * AC_HEATER_EFFICIENCY_ADJ ); +// } +// //Range check +// d5Efficiency = RANGE( d5_eff, AC_HEAT_EFFICIENCY_LOW, AC_HEAT_EFFICIENCY_HIGH ); +// } + 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 ); } } -//#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 ); -// } -//#endif - } - else - { - measuredTemperature = getD50AverageTemperature(); + else + { + //When feed forward produces zero PWM, no adjustment is needed + adjustD5PWM = HEATERS_MIN_DUTY_CYCLE; + } - ctrl = runPIController( PI_CONTROLLER_ID_D45_HEAT, targetTemperature, measuredTemperature ); - control[ heater ].data = ctrl; + // 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_D45_HEAT, (PI_CONTROLLER_SIGNALS_ID)i ); + pIControlSignal[ i ] = getPIControllerSignals( PI_CONTROLLER_ID_D5_HEAT_OUTER_LOOP, (PI_CONTROLLER_SIGNALS_ID)i ); } #endif } + else + { + measuredTemperature = getD50AverageTemperature(); + ctrl = runPIController( PI_CONTROLLER_ID_D45_HEAT, targetTemperature, measuredTemperature ); + control[ heater ].data = ctrl; +//#ifdef __HEATERS_DEBUG__ +// U32 i; +// +// for ( i = 0; i < NUM_OF_CONTROLLER_SIGNAL; i++ ) +// { +// pIControlSignal[ i ] = getPIControllerSignals( PI_CONTROLLER_ID_D45_HEAT, (PI_CONTROLLER_SIGNALS_ID)i ); +// } +//#endif + } + heatersStatus[ heater ].hasTargetTempChanged = FALSE; heatersStatus[ heater ].controlIntervalCounter = 0; @@ -975,10 +1056,13 @@ 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_dutyCycleCnt = convertDC; data.d5_PWMPeriod = getHeaterPWMPeriod( D5_HEAT ); + data.d5_dutyCycleCnt = d5FeedForward * HEATERS_DUTY_CYCLE_CONVERSION_FACTOR; + //data.d5_PWMPeriod = capAdjustD5PWM * HEATERS_DUTY_CYCLE_CONVERSION_FACTOR; data.d5_adjsutedTargetTemp = adjustedPrimaryTargetTemp; data.d5_targetTempFromTD = getTDTargetDialysateTemperature(); + data.d5_efficiency = d5Efficiency; #ifdef __HEATERS_DEBUG__ data.dbg1 = pIControlSignal[ 0 ]; data.dbg2 = pIControlSignal[ 1 ]; @@ -990,7 +1074,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 ) ); Index: firmware/App/Controllers/Heaters.h =================================================================== diff -u -r830213bc6dcc1a684610caf78c79d55f2cb41e93 -r3ebcff44116a7853d2011c7b2f1eb38c1f37ba2a --- firmware/App/Controllers/Heaters.h (.../Heaters.h) (revision 830213bc6dcc1a684610caf78c79d55f2cb41e93) +++ firmware/App/Controllers/Heaters.h (.../Heaters.h) (revision 3ebcff44116a7853d2011c7b2f1eb38c1f37ba2a) @@ -56,6 +56,7 @@ F32 d5_PWMPeriod; ///< Primary heater PWM period F32 d5_adjsutedTargetTemp; ///< Primary heater adjsuted target temperature F32 d5_targetTempFromTD; ///< User set target temperature + F32 d5_efficiency; ///< AC Heater efficiency #ifdef __HEATERS_DEBUG__ F32 dbg1; F32 dbg2; Index: firmware/App/DDCommon.h =================================================================== diff -u -r7d85bc16d7e6a209a28d0152c8cd7da5d5af1be2 -r3ebcff44116a7853d2011c7b2f1eb38c1f37ba2a --- firmware/App/DDCommon.h (.../DDCommon.h) (revision 7d85bc16d7e6a209a28d0152c8cd7da5d5af1be2) +++ firmware/App/DDCommon.h (.../DDCommon.h) (revision 3ebcff44116a7853d2011c7b2f1eb38c1f37ba2a) @@ -58,7 +58,7 @@ #define __TEENSY_CONDUCTIVITY_DRIVER__ 1 //Uncomment below to disable revised heater model -//#define __REVISED_HEATER_MODEL__ 1 +#define __REVISED_HEATER_MODEL__ 1 #include Index: firmware/App/Modes/ModeGenDialysate.c =================================================================== diff -u -rb3423232af3c7add435cf58646e8956f99e45ffd -r3ebcff44116a7853d2011c7b2f1eb38c1f37ba2a --- firmware/App/Modes/ModeGenDialysate.c (.../ModeGenDialysate.c) (revision b3423232af3c7add435cf58646e8956f99e45ffd) +++ firmware/App/Modes/ModeGenDialysate.c (.../ModeGenDialysate.c) (revision 3ebcff44116a7853d2011c7b2f1eb38c1f37ba2a) @@ -14,7 +14,7 @@ * @date (original) 06-Nov-2024 * ***************************************************************************/ -#include "math.h" +#include "math.h" // for 'exp' #include "BalancingChamber.h" #include "ConcentratePumps.h" @@ -63,16 +63,16 @@ #define LOW_DIAL_FLOW_RATE 150.0F ///< Dialysate flow rate lesser than 150 considered to be low Qds. #define ZERO_DIAL_FLOW_RATE 0.0F ///< Zero dialysate flow rate #define SPENT_CHAMBER_FILL_MAX_COUNT 10 ///< Total number of spent chamber fill allowed. -#define BICARB_CHAMBER_FILL_TIMEOUT ( 1 * MS_PER_SECOND ) ///< Bicarb chamber fill timeout. -#define B1B2_HEAT_DIS_FIRST_COEFF 0.00000000487858F ///< First coefficient for Heat loss dissipation calculation from D4 to D28(cubic equation). -#define B1B2_HEAT_DIS_SEC_COEFF 0.0000063124F ///< Second coefficient for Heat loss dissipation calculation from D4 to D28. -#define B1B2_HEAT_DIS_THIRD_COEFF 0.00258513F ///< Third coefficient for Heat loss dissipation calculation from D4 to D28. -#define B1B2_HEAT_DIS_FOURTH_COEFF 0.242013F ///< Fourth coefficient for Heat loss dissipation calculation from D4 to D28. -#define B3_HEAT_DIS_FIRST_COEFF 0.0000000067756F ///< First coefficient for Heat loss dissipation calculation from D28 to Dialyzer(cubic equation). -#define B3_HEAT_DIS_SEC_COEFF 0.0000085278F ///< Second coefficient for Heat loss dissipation calculation from D28 to Dialyzer. -#define B3_HEAT_DIS_THIRD_COEFF 0.0035126F ///< Third coefficient for Heat loss dissipation calculation from D28 to Dialyzer. -#define B3_HEAT_DIS_FOURTH_COEFF 0.63893F ///< Fourth coefficient for Heat loss dissipation calculation from D28 to Dialyzer. #define BICARB_CHAMBER_FILL_TIMEOUT ( 1 * MS_PER_SECOND ) ///< Bicarb chamber fill timeout. +#define B1B2_HEAT_DIS_FIRST_COEFF 0.00000000487858F ///< First coefficient for Heat loss dissipation calculation from D4 to D28(cubic equation). +#define B1B2_HEAT_DIS_SEC_COEFF 0.0000063124F ///< Second coefficient for Heat loss dissipation calculation from D4 to D28. +#define B1B2_HEAT_DIS_THIRD_COEFF 0.00258513F ///< Third coefficient for Heat loss dissipation calculation from D4 to D28. +#define B1B2_HEAT_DIS_FOURTH_COEFF 0.242013F ///< Fourth coefficient for Heat loss dissipation calculation from D4 to D28. +#define B3_HEAT_DIS_FIRST_COEFF 0.0000000067756F ///< First coefficient for Heat loss dissipation calculation from D28 to Dialyzer(cubic equation). +#define B3_HEAT_DIS_SEC_COEFF 0.0000085278F ///< Second coefficient for Heat loss dissipation calculation from D28 to Dialyzer. +#define B3_HEAT_DIS_THIRD_COEFF 0.0035126F ///< Third coefficient for Heat loss dissipation calculation from D28 to Dialyzer. +#define B3_HEAT_DIS_FOURTH_COEFF 0.63893F ///< Fourth coefficient for Heat loss dissipation calculation from D28 to Dialyzer. +#define BICARB_CHAMBER_FILL_TIMEOUT ( 1 * MS_PER_SECOND ) ///< Bicarb chamber fill timeout. //Testing #define DELAY_BC_SWITCHING_AT_START_UP ( 10 * MS_PER_SECOND ) ///< Provide a balancing chamber switching start up delay to stabilize pump speed etc., @@ -598,6 +598,7 @@ F32 targetTemp = getTDTargetDialysateTemperature(); F32 initialTempAtD28 = 0.0F; F32 initialTempAtD4 = 0.0F; + #ifndef __REVISED_HEATER_MODEL__ if ( dialFlowrate >= LOW_DIAL_FLOW_RATE ) { @@ -614,6 +615,9 @@ // Adjust the D4 target temperature targetHydChamberFluidTemp.data = getTDTargetDialysateTemperature() + deltaTemp; #else + // Heat loss model predicts the heat loss ( B1,B2 and B3) in the DD flow path and + // finds the delta temperature to be added with the target temperature + // to maintain the target temperature at dialyzer. //Lets calculate the B1,B2 and B3 heat dissipation factors heatDissipation_b3 = calculateHeatDissipationB3(); heatDissipation_b1b2 = calculateHeatDissipationB1andB2(); Index: firmware/App/Monitors/Temperature.c =================================================================== diff -u -rd748813399d38ef5b71d760e327e368cc82d7a38 -r3ebcff44116a7853d2011c7b2f1eb38c1f37ba2a --- firmware/App/Monitors/Temperature.c (.../Temperature.c) (revision d748813399d38ef5b71d760e327e368cc82d7a38) +++ firmware/App/Monitors/Temperature.c (.../Temperature.c) (revision 3ebcff44116a7853d2011c7b2f1eb38c1f37ba2a) @@ -48,6 +48,7 @@ #define D4_TEMP_MOVING_AVG_NUM_OF_SAMPLES 50 ///< D4 temperature sensor moving average number of samples. #define D50_TEMP_MOVING_AVG_NUM_OF_SAMPLES 50 ///< D50 temperature sensor moving average number of samples. #define D99_TEMP_MOVING_AVG_NUM_OF_SAMPLES 50 ///< D99 temperature sensor moving average number of samples +#define D78_TEMP_MOVING_AVG_NUM_OF_SAMPLES 50 ///< D99 temperature sensor moving average number of samples #define DATA_PUBLISH_COUNTER_START_COUNT 30 ///< Data publish counter start count. #define DIAL_TEMP_MOVING_AVG_NUM_OF_SAMPLES 30 ///< Dialysate temperature sensors moving average number of samples. #define D28_D30_DATA_COLLECTION_TIME_MS ( 1 * MS_PER_SECOND ) ///< Dialysate temperature sensors data collection time in milliseconds. @@ -112,6 +113,13 @@ static U32 d99TempCount; ///< D99 Number of samples in average buffer. static U32 d99TempSampleIntervalCounter; ///< D99 temperature sensor sample collection timer counter. +static F32 d78TempAvgC; ///< D78 temperature average in C. +static F32 d78TempRunningSumC; ///< D78 temperature running sum in C. +static F32 d78TempSamplesC[ D99_TEMP_MOVING_AVG_NUM_OF_SAMPLES ]; ///< D78 temperature samples array in C. +static U32 d78TempSamplesNextIndex; ///< D78 temperature sample next index number. +static U32 d78TempCount; ///< D78 Number of samples in average buffer. +static U32 d78TempSampleIntervalCounter; ///< D78 temperature sensor sample collection timer counter. + static U32 ddTempDataPublicationTimerCounter; ///< DD Temperature sensors data publish timer counter. static U32 fpTempDataPublicationTimerCounter; ///< FP Temperature sensors data publish timer counter. static OVERRIDE_U32_T ddTempSensorsPublishInterval; ///< DD Temperature sensors publish time interval override. @@ -151,9 +159,14 @@ d99TempAvgC = 0.0F; d99TempSamplesNextIndex = 0; d99TempCount = 0; + d78TempRunningSumC = 0.0F; + d78TempAvgC = 0.0F; + d78TempSamplesNextIndex = 0; + d78TempCount = 0; d4TempSampleIntervalCounter = 0; d50TempSampleIntervalCounter = 0; d99TempSampleIntervalCounter = 0; + d78TempSampleIntervalCounter = 0; tempDataCollectionTimeInterval = 0; tempDriftEventCheck = FALSE; @@ -301,15 +314,20 @@ * @brief * The filterTemperatureReadings function adds a new temperature sensor * sample to the filters. - * @details \b Inputs: D4, D50 and D99 Temperature + * @details \b Inputs: D4, D50,D78 and D99 Temperature * @details \b Outputs: d4TempSamplesC[], d4TempSamplesNextIndex, d4TempRunningSumC, * d4TempCount, d4TempAvgC, d50TempSamplesC, d50TempRunningSumC, d50TempSamplesNextIndex, * d50TempCount, d50TempAvgC, d99TempSamplesC, d99TempRunningSumC, d99TempSamplesNextIndex, - * d99TempCount, d99TempAvgC + * d99TempCount, d99TempAvgC, * @return none *************************************************************************/ static void filterTemperatureReadings( void ) { + F32 d4Temp = 0.0F; + F32 d50Temp = 0.0F; + F32 d99Temp = 0.0F; + F32 d78Temp = 0.0F; + // Moving average sample collection interval varies based on the dialysate flow rate if ( ++d4TempSampleIntervalCounter >= tempDataCollectionTimeInterval ) { @@ -319,7 +337,7 @@ d4TempRunningSumC -= d4TempSamplesC[ d4TempSamplesNextIndex ]; } - F32 d4Temp = getTemperatureValue( D4_TEMP ); + d4Temp = getTemperatureValue( D4_TEMP ); d4TempSamplesC[ d4TempSamplesNextIndex ] = d4Temp; d4TempRunningSumC += d4Temp; d4TempSamplesNextIndex = INC_WRAP( d4TempSamplesNextIndex, 0, D4_TEMP_MOVING_AVG_NUM_OF_SAMPLES - 1 ); @@ -336,7 +354,7 @@ d50TempRunningSumC -= d50TempSamplesC[ d50TempSamplesNextIndex ]; } - F32 d50Temp = getTemperatureValue( D50_TEMP ); + d50Temp = getTemperatureValue( D50_TEMP ); d50TempSamplesC[ d50TempSamplesNextIndex ] = d50Temp; d50TempRunningSumC += d50Temp; d50TempSamplesNextIndex = INC_WRAP( d50TempSamplesNextIndex, 0, D50_TEMP_MOVING_AVG_NUM_OF_SAMPLES - 1 ); @@ -356,14 +374,32 @@ d99TempRunningSumC -= d99TempSamplesC[ d99TempSamplesNextIndex ]; } - F32 d99Temp = getTemperatureValue( D99_TEMP ); + d99Temp = getTemperatureValue( D99_TEMP ); d99TempSamplesC[ d99TempSamplesNextIndex ] = d99Temp; d99TempRunningSumC += d99Temp; d99TempSamplesNextIndex = INC_WRAP( d99TempSamplesNextIndex, 0, D99_TEMP_MOVING_AVG_NUM_OF_SAMPLES - 1 ); d99TempCount = INC_CAP( d99TempCount, D99_TEMP_MOVING_AVG_NUM_OF_SAMPLES ); d99TempAvgC = d99TempRunningSumC / (F32)d99TempCount; } + // Moving average sample collection interval varies based on the dialysate flow rate + if ( ++d78TempSampleIntervalCounter >= tempDataCollectionTimeInterval ) + { + + // Filter D78 Temperature for fresh dialysate temperature + if ( d78TempCount >= D78_TEMP_MOVING_AVG_NUM_OF_SAMPLES ) + { + d78TempRunningSumC -= d78TempSamplesC[ d78TempSamplesNextIndex ]; + } + + d78Temp = getTemperatureValue( D78_TEMP ); + d78TempSamplesC[ d78TempSamplesNextIndex ] = d78Temp; + d78TempRunningSumC += d78Temp; + d78TempSamplesNextIndex = INC_WRAP( d78TempSamplesNextIndex, 0, D78_TEMP_MOVING_AVG_NUM_OF_SAMPLES - 1 ); + d78TempCount = INC_CAP( d78TempCount, D78_TEMP_MOVING_AVG_NUM_OF_SAMPLES ); + d78TempAvgC = d78TempRunningSumC / (F32)d78TempCount; + } + // dailysate temperature moving average filterDialTemperatureReadings(); } @@ -485,6 +521,19 @@ /*********************************************************************//** * @brief + * The getD78AverageTemperature function returns the average temperature + * for D78 temperature sensor. + * @details \b Inputs: none + * @details \b Outputs: none + * @return the D78 average temperature + *************************************************************************/ +F32 getD78AverageTemperature( void ) +{ + return d78TempAvgC; +} + +/*********************************************************************//** + * @brief * The getTempMovingAverageTimeInterval function calculates the temperature * interval used for sample collection based on the dialysate flow rate, * to find the average value. @@ -543,6 +592,7 @@ data.d99AvgTemp = getD99AverageTemperature(); data.d28AvgTemp = dialTempMovingAvgData[ DIAL_TEMP_D28 ].dialTempAvgC; data.d30AvgTemp = dialTempMovingAvgData[ DIAL_TEMP_D30 ].dialTempAvgC; + data.d78AvgTemp = getD78AverageTemperature(); data.d9PresTemp = getFilteredPressureSensorTemperature( D9_PRES ); data.d66PresTemp = getFilteredPressureSensorTemperature( D66_PRES ); data.d51PresTemp = getFilteredPressureSensorTemperature( D51_PRES ); Index: firmware/App/Monitors/Temperature.h =================================================================== diff -u -r2a85af53e9b2ee2cf79f832167c9723a886d1ab9 -r3ebcff44116a7853d2011c7b2f1eb38c1f37ba2a --- firmware/App/Monitors/Temperature.h (.../Temperature.h) (revision 2a85af53e9b2ee2cf79f832167c9723a886d1ab9) +++ firmware/App/Monitors/Temperature.h (.../Temperature.h) (revision 3ebcff44116a7853d2011c7b2f1eb38c1f37ba2a) @@ -50,6 +50,7 @@ F32 d99AvgTemp; ///< D99 moving average temperature value F32 d28AvgTemp; ///< D28 moving average temperature value F32 d30AvgTemp; ///< D30 moving average temperature value + F32 d78AvgTemp; ///< D78 moving average temperature value F32 d9PresTemp; ///< Hydraulics outlet pressure temperature F32 d66PresTemp; ///< Bicarb bag temperature F32 d51PresTemp; ///< Spent Dialysate temperature @@ -82,6 +83,7 @@ void execTemperatureSensors( void ); F32 getD4AverageTemperature( void ); F32 getD50AverageTemperature( void ); +F32 getD78AverageTemperature( void ); void checkDialysateTemperatureSensors( void ); BOOL testDDTemperatureSensorsDataPublishIntervalOverride( MESSAGE_T *message ); Index: firmware/App/Services/AlarmMgmtSWFaults.h =================================================================== diff -u -rd210786d6c7d75bb0b4d9e18efc40a01d85123fe -r3ebcff44116a7853d2011c7b2f1eb38c1f37ba2a --- firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision d210786d6c7d75bb0b4d9e18efc40a01d85123fe) +++ firmware/App/Services/AlarmMgmtSWFaults.h (.../AlarmMgmtSWFaults.h) (revision 3ebcff44116a7853d2011c7b2f1eb38c1f37ba2a) @@ -152,6 +152,7 @@ SW_FAULT_ID_DRY_BICART_FILL_INVALID_EXEC_STATE = 121, SW_FAULT_ID_BICARB_CHAMBER_FILL_INVALID_EXEC_STATE = 122, SW_FAULT_ID_DRY_BICART_DRAIN_INVALID_EXEC_STATE = 123, + SW_FAULT_ID_PI_CTRL_INVALID_FEED_FORWARD_LIMIT = 124, NUM_OF_SW_FAULT_IDS } DD_SW_FAULT_ID_T;