Index: firmware/App/Services/Reservoirs.c =================================================================== diff -u -r353d01d31bc69d4d1901ff09097ee610bb1c9dbc -ra3960210792d0811093a6913e505d43eda1918ea --- firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision 353d01d31bc69d4d1901ff09097ee610bb1c9dbc) +++ firmware/App/Services/Reservoirs.c (.../Reservoirs.c) (revision a3960210792d0811093a6913e505d43eda1918ea) @@ -52,23 +52,25 @@ #define MAX_REDUNDANT_LOAD_CELL_DIFF 50.0 ///< Maximum difference in redundant load cells when determing if fill completed. -// TODO add doxygen comments +// TODO add doxygen comments yes for all of the new variables and align them #define RESERVOIR_TEMPERATURE_TAU_C_PER_MIN -0.512 ///< Reservoir temperature time constant C/min. #define ULTRAFILTER_TEMPERATURE_TAU_C_PER_MIN -0.512 ///< Ultrafilter temperature time constant C/min. #define ULTRAFILTER_VOLUME_ML 700 - // ********** private data ********** // TODO yes we should add all the doxygen comments soon // TODO add doxygen comments typedef struct { U32 timeReservoirCycleMS; + U32 timeReservoirFill2SwitchMS; F32 timeUFDecayMS; + F32 timeReservoirFillMS; F32 tempUFFill; - F32 tempRerservoirStartFill; - + F32 tempReservoirStartFill; + F32 tempReservoirEndFill; + F32 tempTargetTrimmer; } HEATERS_TEMPERATURE_CALC_DATA_T; static HEATERS_TEMPERATURE_CALC_DATA_T heatersTempCalc; @@ -91,14 +93,14 @@ static DG_RESERVOIR_VOLUME_RECORD_T reservoirsCalRecord; ///< DG reservoirs non-volatile record. static F32 targetFillFlowRateLPM; ///< Target fill flow rate in L/min. -static const F32 ULTRAFILTER_TAU_C_PER_MS = ULTRAFILTER_TEMPERATURE_TAU_C_PER_MIN * SEC_PER_MIN * MS_PER_SECOND; -static const F32 RESERVOIR_TAU_C_PER_MS = RESERVOIR_TEMPERATURE_TAU_C_PER_MIN * SEC_PER_MIN * MS_PER_SECOND; +// TODO add doxygen comments +static const F32 ULTRAFILTER_TAU_C_PER_MS = ULTRAFILTER_TEMPERATURE_TAU_C_PER_MIN / ( SEC_PER_MIN * MS_PER_SECOND ); +static const F32 RESERVOIR_TAU_C_PER_MS = RESERVOIR_TEMPERATURE_TAU_C_PER_MIN / ( SEC_PER_MIN * MS_PER_SECOND ); // ********** private function prototypes ********** static BOOL processCalibrationData( void ); static F32 getPrimaryHeaterTargetTemperature( void ); -static F32 getTrimmerHeaterTargetTemperature( void ); /*********************************************************************//** * @brief @@ -137,11 +139,17 @@ { RESERVOIR_DATA_T data; - data.activeReservoir = getU32OverrideValue( &activeReservoir ); - data.fillToVolumeMl = getU32OverrideValue( &fillVolumeTargetMl ); - data.drainToVolumeMl = getU32OverrideValue( &drainVolumeTargetMl ); + data.activeReservoir = getU32OverrideValue( &activeReservoir ); + data.fillToVolumeMl = getU32OverrideValue( &fillVolumeTargetMl ); + data.drainToVolumeMl = getU32OverrideValue( &drainVolumeTargetMl ); + data.timeReservoirCycleMS = heatersTempCalc.timeReservoirCycleMS; + data.timeReservoirFill2SwitchMS = heatersTempCalc.timeReservoirFill2SwitchMS; + data.timeUFDecayMS = heatersTempCalc.timeUFDecayMS; + data.tempUFFill = heatersTempCalc.tempUFFill; + data.tempReservoirStartFill = heatersTempCalc.tempReservoirStartFill; + data.tempReservoirEndFill = heatersTempCalc.tempReservoirEndFill; - broadcastData( MSG_ID_DG_RESERVOIR_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&data, sizeof( RESERVOIR_DATA_T ) ); + broadcastData( MSG_ID_DG_RESERVOIRS_DATA, COMM_BUFFER_OUT_CAN_DG_BROADCAST, (U08*)&data, sizeof( RESERVOIR_DATA_T ) ); reservoirDataPublicationTimerCounter = 0; } } @@ -463,6 +471,32 @@ /*********************************************************************//** * @brief + * The getReservoirActualTemperature function calculates the reservoir's + * actual temperature. + * @details Inputs: none + * @details Outputs: heatersTempCalc + * @return reservoir actual temperature + *************************************************************************/ +F32 getReservoirActualTemperature( void ) +{ + F32 reservoirTemp = 0.0; + F32 targetFillVolML = getTargetFillVolumeML(); + F32 timeHalfFillMS = ( getTargetFillFlowRateLPM() * ML_PER_LITER * 0.5 ) / targetFillVolML; + F32 fillLastTemp = getLastFillTemperature() < NEARLY_ZERO ? heatersTempCalc.tempTargetTrimmer : getLastFillTemperature(); + F32 fillAvgTemp = getAvgFillTemperature() < NEARLY_ZERO ? heatersTempCalc.tempTargetTrimmer : getAvgFillTemperature(); + + F32 ultrafilterPart = ( ULTRAFILTER_VOLUME_ML / targetFillVolML ) * heatersTempCalc.tempUFFill; + F32 fillPart = ( ( ( targetFillVolML - ULTRAFILTER_VOLUME_ML ) / targetFillVolML ) * fillAvgTemp ); + heatersTempCalc.tempReservoirStartFill = ultrafilterPart + fillPart; + + heatersTempCalc.tempReservoirEndFill = heatersTempCalc.tempReservoirStartFill + ( timeHalfFillMS * RESERVOIR_TAU_C_PER_MS ); + reservoirTemp = heatersTempCalc.tempReservoirEndFill + ( heatersTempCalc.timeReservoirFill2SwitchMS * RESERVOIR_TAU_C_PER_MS ); + + return reservoirTemp; +} + +/*********************************************************************//** + * @brief * The getReservoirWeight function returns the small filtered weight * of the reservoir's associated load cell. * @details Inputs: none @@ -515,9 +549,12 @@ * @details Outputs: heatersTemperatureCalcData * @return none *************************************************************************/ -void setHeatersTargetTemperature( TARGET_TEMPS_AND_TIME_PAYLOAD_T targets ) +void setHeatersTargetTemperature( DG_CMD_DIALYSATE_HEATING_PARAMS_T params ) { - heatersTempCalc.timeReservoirCycleMS = targets.activeReservoirCycleTimeMS; + heatersTempCalc.timeReservoirCycleMS = params.timeReservoirCycleMS; + heatersTempCalc.timeReservoirFill2SwitchMS = params.timeReservoirWait2SwitchMS; + heatersTempCalc.timeReservoirFillMS = params.timeReservoirFillMS; + heatersTempCalc.tempTargetTrimmer = params.trimmerTargetTemperature; setHeaterTargetTemperature( DG_PRIMARY_HEATER, getPrimaryHeaterTargetTemperature() ); } @@ -546,10 +583,10 @@ *************************************************************************/ BOOL hasTargetFillVolumeBeenReached( DG_RESERVOIR_ID_T reservoirId ) { - F32 const loadcellWeight1 = getLoadCellSmallFilteredWeight( associatedLoadCell[ reservoirId ] ); - F32 const loadcellWeight2 = getLoadCellSmallFilteredWeight( redundantLoadCell[ reservoirId ] ); - U32 const targetFillVolume = getU32OverrideValue( &fillVolumeTargetMl ); - BOOL const hasTargetReached = ( ( loadcellWeight1 >= targetFillVolume || loadcellWeight2 > ( targetFillVolume + MAX_REDUNDANT_LOAD_CELL_DIFF ) ) ? TRUE : FALSE ); + F32 loadcellWeight1 = getLoadCellSmallFilteredWeight( associatedLoadCell[ reservoirId ] ); + F32 loadcellWeight2 = getLoadCellSmallFilteredWeight( redundantLoadCell[ reservoirId ] ); + U32 targetFillVolume = getU32OverrideValue( &fillVolumeTargetMl ); + BOOL hasTargetReached = ( ( loadcellWeight1 >= targetFillVolume || loadcellWeight2 > ( targetFillVolume + MAX_REDUNDANT_LOAD_CELL_DIFF ) ) ? TRUE : FALSE ); // if redundant load cells too far apart at end of fill, alarm if ( loadcellWeight1 < targetFillVolume ) @@ -683,36 +720,34 @@ * heater target temperature and returns target temperature value. * @details Inputs: none * @details Outputs: heatersTempCalc - * @return TRUE if the calibration record is valid, otherwise FALSE + * @return primary heater target temperature *************************************************************************/ static F32 getPrimaryHeaterTargetTemperature( void ) { + // TODO once the equations are solidified, add the equations as comments to the lines F32 targetTemp = 0.0; F32 targetFillVolML = getTargetFillVolumeML(); - F32 timeFillMS = ( getTargetFillFlowRateLPM() * ML_PER_LITER ) / targetFillVolML; // TODO target flow can come from RO pump too + F32 timeFillMS = heatersTempCalc.timeReservoirFillMS; + F32 UFTimeConstant = 0.0; + F32 fillLastTemp = getLastFillTemperature() < NEARLY_ZERO ? heatersTempCalc.tempTargetTrimmer : getLastFillTemperature(); + F32 fillAvgTemp = getAvgFillTemperature() < NEARLY_ZERO ? heatersTempCalc.tempTargetTrimmer : getAvgFillTemperature(); - heatersTempCalc.timeUFDecayMS = (F32)heatersTempCalc.timeReservoirCycleMS - timeFillMS; - heatersTempCalc.tempUFFill = getLastFillTemperature() + ( heatersTempCalc.timeUFDecayMS * ULTRAFILTER_TAU_C_PER_MS ); + heatersTempCalc.timeUFDecayMS = (F32)heatersTempCalc.timeReservoirCycleMS - timeFillMS + (F32)heatersTempCalc.timeReservoirFill2SwitchMS; + UFTimeConstant = heatersTempCalc.timeUFDecayMS * ULTRAFILTER_TAU_C_PER_MS; + heatersTempCalc.tempUFFill = fillLastTemp + UFTimeConstant; - F32 ultrafilterPart = ( ULTRAFILTER_VOLUME_ML / targetFillVolML ) * heatersTempCalc.tempUFFill; - F32 fillPart = ( ( ( targetFillVolML - ULTRAFILTER_VOLUME_ML ) / targetFillVolML ) * getAvgFillTemperature() ); + F32 ultrafilterPart = ( ULTRAFILTER_VOLUME_ML / targetFillVolML ) * heatersTempCalc.tempUFFill; + F32 fillPart = ( ( ( targetFillVolML - ULTRAFILTER_VOLUME_ML ) / targetFillVolML ) * fillAvgTemp ); + heatersTempCalc.tempReservoirStartFill = ultrafilterPart + fillPart; - heatersTempCalc.tempRerservoirStartFill = ultrafilterPart + fillPart; + F32 targetTempNumerator = heatersTempCalc.tempReservoirStartFill - ( ( ULTRAFILTER_VOLUME_ML / targetFillVolML ) * UFTimeConstant ); + F32 targetTempDenominator = ( ( targetFillVolML - ULTRAFILTER_VOLUME_ML ) / targetFillVolML ); + targetTemp = targetTempNumerator / targetTempDenominator; return targetTemp; } -static F32 getTrimmerHeaterTargetTemperature( void ) -{ - F32 targetTemp = 0.0; - F32 targetFillVolML = getTargetFillVolumeML(); - F32 timeHalfFillMS = ( getTargetFillFlowRateLPM() * ML_PER_LITER * 0.5 ) / targetFillVolML; // TODO target flow can come from RO pump - - return targetTemp; -} - - /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/