Index: firmware/App/Services/Reservoirs.c =================================================================== diff -u -r5e3a46112ebab361a33b9f7cadb619eb12b44c0f -rb4f8e2229eb0a08cdce5fdd2e0a14ca25d792946 --- firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision 5e3a46112ebab361a33b9f7cadb619eb12b44c0f) +++ firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision b4f8e2229eb0a08cdce5fdd2e0a14ca25d792946) @@ -1,14 +1,14 @@ /************************************************************************** * -* Copyright (c) 2020-2022 Diality Inc. - All Rights Reserved. +* Copyright (c) 2020-2023 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 Reservoirs.c * * @author (last) Dara Navaei -* @date (last) 03-Nov-2022 +* @date (last) 07-Mar-2023 * * @author (original) Sean * @date (original) 18-Mar-2020 @@ -48,7 +48,7 @@ #define DEFAULT_DRAIN_VOLUME_ML 0 ///< Default drain volume in mL. #define MAX_DRAIN_VOLUME_ML MAX_RESERVOIR_VOLUME_ML ///< Maximum drain volume in mL. -#define MIN_DRAIN_INLET_PSI_EMPTY -3.0F ///< Minimum drain inlet pressure (in PSI) to indicate reservoir is empty while drain pump on. +#define MIN_DRAIN_INLET_PSI_EMPTY -4.5F ///< Minimum drain inlet pressure (in PSI) to indicate reservoir is empty while drain pump on. #define RESERVOIR_DATA_PUB_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< interval (ms/task time) at which the reservoir data is published on the CAN bus. #define MAX_REDUNDANT_LOAD_CELL_DIFF 50.0F ///< Maximum difference in redundant load cells when determining if fill completed. #define MAX_DRAIN_RPM_MLP 2400.0F ///< Maximum drain RPM in mL/min. @@ -73,6 +73,7 @@ F32 tempRsrvr0ActualTrimmer; ///< Temperature actual reservoir in C. F32 tempFillMixAvgTrimmer; ///< Temperature fill mix average trimmer in C. F32 tempRsrvrEndFillTrimmer; ///< Temperature reservoir end fill trimmer in C. + BOOL usePriTargetTempEquation; ///< Use primary heater target temperature enquation flag. } HEATERS_TEMPERATURE_CALC_DATA_T; /// Reservoirs previous status @@ -624,6 +625,7 @@ heatersTempCalc.timeReservoirFillMS = params.timeReservoirFillMS; heatersTempCalc.tempTargetTrimmer = params.trimmerTargetTemperature; heatersTempCalc.flowTargetDialysateLPM = params.dialysateFlowLPM; + heatersTempCalc.usePriTargetTempEquation = params.usePriTargetTempEquation; // Check if this is the first time that the dialysate heating parameters are set in DG if ( TRUE == isThisTheFirstCycle ) @@ -643,41 +645,54 @@ *************************************************************************/ F32 getPrimaryHeaterTargetTemperature( void ) { - // TODO once the equations are solidified, add the equations as comments to the lines - F32 tempTarget = 0.0; - F32 priTargetTemp = 0.0; + F32 tempTargetC = heatersTempCalc.tempTargetTrimmer; + F32 priTargetTempC = 0.0F; F32 targetFillVolML = getTargetFillVolumeML(); - F32 UFTimeConstant = 0.0; + F32 UFTimeConstant = 0.0F; F32 tempLastFill = getLastFillTemperature(); F32 UFTauCPerMS = heatingConstsCalRecord.ultrafilterTempTauCPerMin / ( SEC_PER_MIN * MS_PER_SECOND ); F32 RsrvrTauCPerMS = heatingConstsCalRecord.reservoirTempTauCPerMin / ( SEC_PER_MIN * MS_PER_SECOND ); F32 targetROFlowLPM = getTargetROPumpFlowRateLPM(); - F32 tgtAicdFlowLPM = getConcentratePumpTargetFlowMLPM( CONCENTRATEPUMPS_CP1_ACID ) / ML_PER_LITER; + F32 tgtAcidFlowLPM = getConcentratePumpTargetFlowMLPM( CONCENTRATEPUMPS_CP1_ACID ) / ML_PER_LITER; F32 tgtBicarbFlowLPM = getConcentratePumpTargetFlowMLPM( CONCENTRATEPUMPS_CP2_BICARB ) / ML_PER_LITER; - F32 tgtTotalFlowLPM = targetROFlowLPM + tgtAicdFlowLPM + tgtBicarbFlowLPM; + F32 tgtTotalFlowLPM = targetROFlowLPM + tgtAcidFlowLPM + tgtBicarbFlowLPM; - if ( FALSE == isThisTheFirstFill() ) + if ( TRUE == heatersTempCalc.usePriTargetTempEquation ) { - F32 tempTargetNumerator; - F32 targetTempDenominator; - F32 tempReservoirUse; + if ( FALSE == isThisTheFirstFill() ) + { + F32 tempTargetNumerator; + F32 tempTargetDenominator; + F32 tempReservoirUse; - tempReservoirUse = heatersTempCalc.tempTargetTrimmer + RESERVOIR_EXTRA_TEMPERATURE; - heatersTempCalc.tempReservoirEndFill = tempReservoirUse - ( heatersTempCalc.timeReservoirFill2SwitchMS * RsrvrTauCPerMS ); - heatersTempCalc.tempReservoir0 = heatersTempCalc.tempReservoirEndFill - ( ( heatersTempCalc.timeReservoirFillMS * HALF ) * RsrvrTauCPerMS ); + /* + * 1. T_rsrvr_use = T_target + * 2. T_rsrvr_end_fill = T_rsrvr_use - (t_rsrvr_fill_2_switch * Tau_rsrvr) + * 3. T_rsrvr_0 = T_rsrvr_end_fill - (t_rsrvr_fill/2 * Tau_rsrvr) + * 4. T_UF_fill = T_last_fill + [(t_rsrvr_cycle - t_rsrvr_fill) * Tau_UF] + * 5. T_numerator = T_rsrvr_0 - [(V_UF / V_fill) * T_UF_fill] + * 6. T_denominator = (V_fill - V_UF) / V_fill + * 7. T_mix_target = T_numerator / T_denominator + * 8. T_primary_target = T_mix_target * (Q_total / Q_RO) - (Q_acid / Q_RO) * T_acid - (Q_bicarb / Q_RO) * T_bicarb + */ - heatersTempCalc.timeUFDecayMS = (F32)heatersTempCalc.timeReservoirCycleMS - heatersTempCalc.timeReservoirFillMS; - UFTimeConstant = heatersTempCalc.timeUFDecayMS * UFTauCPerMS; - heatersTempCalc.tempUFFill = tempLastFill + UFTimeConstant; + tempReservoirUse = heatersTempCalc.tempTargetTrimmer; + heatersTempCalc.tempReservoirEndFill = tempReservoirUse - ( heatersTempCalc.timeReservoirFill2SwitchMS * RsrvrTauCPerMS ); + heatersTempCalc.tempReservoir0 = heatersTempCalc.tempReservoirEndFill - ( ( heatersTempCalc.timeReservoirFillMS * HALF ) * RsrvrTauCPerMS ); - tempTargetNumerator = heatersTempCalc.tempReservoir0 - ( ( heatingConstsCalRecord.ultrafilterVolmL / targetFillVolML ) * heatersTempCalc.tempUFFill ); - targetTempDenominator = ( ( targetFillVolML - heatingConstsCalRecord.ultrafilterVolmL ) / targetFillVolML ); - tempTarget = tempTargetNumerator / targetTempDenominator; + heatersTempCalc.timeUFDecayMS = (F32)heatersTempCalc.timeReservoirCycleMS - heatersTempCalc.timeReservoirFillMS; + UFTimeConstant = heatersTempCalc.timeUFDecayMS * UFTauCPerMS; + heatersTempCalc.tempUFFill = tempLastFill + UFTimeConstant; + + tempTargetNumerator = heatersTempCalc.tempReservoir0 - ( ( heatingConstsCalRecord.ultrafilterVolmL / targetFillVolML ) * heatersTempCalc.tempUFFill ); + tempTargetDenominator = ( ( targetFillVolML - heatingConstsCalRecord.ultrafilterVolmL ) / targetFillVolML ); + tempTargetC = tempTargetNumerator / tempTargetDenominator; + } + else + { + tempTargetC = heatersTempCalc.tempTargetTrimmer + RESERVOIR_EXTRA_TEMPERATURE; + } } - else - { - tempTarget = heatersTempCalc.tempTargetTrimmer + RESERVOIR_EXTRA_TEMPERATURE; - } if ( targetROFlowLPM > 0 ) { @@ -689,17 +704,17 @@ // the target temperature is calculated by estimating the temperature of the dialysates and volume that is being mixed into the RO water F32 acidTemperature = acidConcentrateCalRecord.acidConcentrate[ CAL_DATA_ACID_CONCENTRATE_1 ].acidBottleTemperature; F32 bicarbTemperature = bicarbConcentrateCalRecord.bicarbConcentrate[ CAL_DATA_BICARB_CONCENTRATE_1 ].bicarbBottleTemperature; - priTargetTemp = ( tempTarget * ( tgtTotalFlowLPM / targetROFlowLPM ) ) - ( acidTemperature * ( tgtAicdFlowLPM / targetROFlowLPM ) ) - + priTargetTempC = ( tempTargetC * ( tgtTotalFlowLPM / targetROFlowLPM ) ) - ( acidTemperature * ( tgtAcidFlowLPM / targetROFlowLPM ) ) - ( bicarbTemperature * ( tgtBicarbFlowLPM / targetROFlowLPM ) ); } else #endif { - priTargetTemp = tempTarget; + priTargetTempC = tempTargetC; } } - return priTargetTemp; + return priTargetTempC; } /*********************************************************************//** @@ -925,7 +940,7 @@ // Set the start time to 0 for the next drain and update the current load cell reading to the previous value reservoirWeightUnchangeStartTime[ reservoirId ] = 0; reservoirPreviousStatus[ reservoirId ].previousReservoirWeightG = getLoadCellSmallFilteredWeight( associatedLoadCell[ reservoirId ] ); - reservoirPreviousStatus[ reservoirId ].previousDrainFlowML = 0.0; + reservoirPreviousStatus[ reservoirId ].previousDrainFlowML = 0.0F; }