/************************************************************************** * * Copyright (c) 2024-2024 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 WaterQualityMonitor.c * * @author (last) Sean Nash * @date (last) 21-Nov-2024 * * @author (original) Sean Nash * @date (original) 21-Nov-2024 * ***************************************************************************/ #include "Conductivity.h" #include "Flow.h" #include "FPModeStandby.h" #include "FPOperationModes.h" #include "PersistentAlarm.h" #include "Pressure.h" #include "ROPump.h" #include "SystemCommDD.h" #include "TaskPriority.h" #include "Temperature.h" #include "WaterQualityMonitor.h" /** * @addtogroup WaterQualityMonitor * @{ */ // ********** private definitions ********** #define INLET_TEMPERATURE_LOW_THRESHOLD_C 5.0F ///< Minimum allowed Inlet temperature in C. #define INLET_TEMPERATURE_HIGH_THRESHOLD_C 30.0F ///< Maximum allowed Inlet temperature in C. #define INLET_TEMPERATURE_PERSISTENCE_TIMER_MS ( 5 * MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Persistence timer to trigger alarm in ms. #define INLET_TEMPERATURE_PERSISTENCE_CLEAR_MS ( 5 * MS_PER_SECOND / TASK_PRIORITY_INTERVAL ) ///< Persistence timer to clear alarm in ms. #define MAX_INLET_RO_PUMP_PRESSURE_WARNING_PSIG 120.0F ///< Maximum allowed Input pressure to the RO membrane. #define MIN_INLET_WATER_PRESSURE_WARNING_LOW_PSIG 25.0F ///< Minimum allowed Input warning low pressure value in psig for RO featured. #define MAX_INLET_WATER_PRESSURE_WARNING_HIGH_PSIG 40.0F ///< Maximum allowed Input warning high pressure value in psig for RO featured. #define MAX_INLET_WATER_PRESSURE_FAULT_HIGH_PSIG 75.0F ///< Maximum allowed Input fault high pressure value in psig for RO featured. #define MIN_INLET_WATER_PRESSURE_DEFEATURED_WARNING_LOW_PSIG 5.0F ///< Minimum allowed Input warning low pressure value in psig for RO Defeatured. #define MAX_INLET_WATER_PRESSURE_DEFEATURED_WARNING_HIGH_PSIG 10.0F ///< Maximum allowed Input warning high pressure value in psig for RO Defeatured. #define MAX_INLET_WATER_PRESSURE_DEFEATURED_FAULT_HIGH_PSIG 40.0F ///< Maximum allowed Input fault high pressure value in psig for RO Defeatured. #define MIN_PRESSURE_RELIEF_WARNING_LOW_PSIG 13.0F ///< Minimum pressure relief warning in psi #define MAX_PRESSURE_RELIEF_WARNING_HIGH_PSIG 17.0F ///< Maximum pressure relief warning in psi #define MAX_PERMEATE_FLOW_FAULT_THRESHOLD 1.25F ///< Maximum permeate flow threshold value in percentage. #define INLET_WATER_PRES_OUT_OF_RANGE_TIMEOUT_MS ( 5 * MS_PER_SECOND ) ///< Persistence period for pressure out of range error in milliseconds. #define INLET_WATER_PRES_OUT_OF_RANGE_CLEAR_MS ( 5 * MS_PER_SECOND ) ///< Persistence period for pressure out of range clear in milliseconds. #define INLET_WATER_PRES_RELIEF_OUT_OF_RANGE_TIMEOUT_MS ( 5 * MS_PER_SECOND ) ///< Persistence period for pressure out of range error in milliseconds. #define INLET_WATER_PRES_RELIEF_OUT_OF_RANGE_CLEAR_MS ( 5 * MS_PER_SECOND ) ///< Persistence period for pressure out of range clear in milliseconds. #define OUTLET_CONDUCTIVITY_HIGH_THRESHOLD_US 200.0F ///< Minimum allowed inlet conductivity in uS/cm. #define INLET_WATER_COND_OUT_OF_RANGE_TIMEOUT_MS ( 5 * MS_PER_SECOND ) ///< Persistence period for conductivity out of range error in milliseconds. #define INLET_WATER_COND_OUT_OF_RANGE_CLEAR_MS ( 5 * MS_PER_SECOND ) ///< Persistence period for conductivity out of range clear in milliseconds. #define INLET_CONDUCTIVITY_HIGH_THRESHOLD_US 2000.0F ///< Maximum allowed outlet conductivity in uS/cm. #define MIN_RO_REJECTION_RATIO_PCT 90.0F ///< Minimum RO rejection ration in percentage #define PERMEATE_FLOW_OUT_RANGE_PERSISTENCE_TIMEOUT_MS ( 5 * MS_PER_SECOND ) ///< Verify Water timer ( in ms ) #define PERMEATE_FLOW_OUT_RANGE_PERSISTENCE_CLEAR_MS 0 ///< Verify Water timer ( in ms ) #define PERMEATE_FLOW_FAULT_MIN_THRESHOLD 200.0F ///< Permeate flow low tolerance limit // ********** private data ********** // ********** private function prototypes ********** /*********************************************************************//** * @brief * The initWaterQualityMonitor function initializes the Water Quality Monitor unit. * @details \b Inputs: none * @details \b Outputs: Water Quality Monitor unit is initialized. * @return none *************************************************************************/ void initWaterQualityMonitor( void ) { // Pressure alarms initPersistentAlarm( ALARM_ID_FP_INLET_PRESSURE_OUT_LOW_RANGE, INLET_WATER_PRES_OUT_OF_RANGE_CLEAR_MS, INLET_WATER_PRES_OUT_OF_RANGE_TIMEOUT_MS ); initPersistentAlarm( ALARM_ID_FP_INLET_PRESSURE_OUT_HIGH_RANGE, INLET_WATER_PRES_OUT_OF_RANGE_CLEAR_MS, INLET_WATER_PRES_OUT_OF_RANGE_TIMEOUT_MS ); initPersistentAlarm( ALARM_ID_FP_PRESSURE_RELIEF_OUT_LOW_RANGE, INLET_WATER_PRES_RELIEF_OUT_OF_RANGE_CLEAR_MS, INLET_WATER_PRES_RELIEF_OUT_OF_RANGE_TIMEOUT_MS ); initPersistentAlarm( ALARM_ID_FP_PRESSURE_RELIEF_OUT_HIGH_RANGE, INLET_WATER_PRES_RELIEF_OUT_OF_RANGE_CLEAR_MS, INLET_WATER_PRES_RELIEF_OUT_OF_RANGE_TIMEOUT_MS ); initPersistentAlarm( ALARM_ID_FP_INLET_PRESSURE_REGULATOR_OUT_OF_RANGE, INLET_WATER_PRES_OUT_OF_RANGE_CLEAR_MS, INLET_WATER_PRES_OUT_OF_RANGE_TIMEOUT_MS ); // Temperature Alarms initPersistentAlarm( ALARM_ID_FP_INLET_TEMPERATURE_OUT_LOW_RANGE, INLET_TEMPERATURE_PERSISTENCE_CLEAR_MS, INLET_TEMPERATURE_PERSISTENCE_TIMER_MS ); initPersistentAlarm( ALARM_ID_FP_INLET_TEMPERATURE_OUT_HIGH_RANGE, INLET_TEMPERATURE_PERSISTENCE_CLEAR_MS, INLET_TEMPERATURE_PERSISTENCE_TIMER_MS ); // Conductivity Alarms initPersistentAlarm( ALARM_ID_FP_INLET_CONDUCTIVITY_OUT_HIGH_RANGE, INLET_WATER_COND_OUT_OF_RANGE_CLEAR_MS, INLET_WATER_COND_OUT_OF_RANGE_TIMEOUT_MS ); initPersistentAlarm( ALARM_ID_FP_RO_OUTLET_CONDUCTIVITY_HIGH_RANGE, INLET_WATER_COND_OUT_OF_RANGE_CLEAR_MS, INLET_WATER_COND_OUT_OF_RANGE_TIMEOUT_MS ); //Flow Alarms initPersistentAlarm( ALARM_ID_FP_PERMEATE_FLOW_OUT_HIGH_RANGE, PERMEATE_FLOW_OUT_RANGE_PERSISTENCE_CLEAR_MS, PERMEATE_FLOW_OUT_RANGE_PERSISTENCE_TIMEOUT_MS ); } sd /*********************************************************************//** * @brief * The checkInletPressures function checks the inlet water pressure * against the pressure threshold and alarm if the pressure is out of range. * @details \b Inputs: pressureM3 * @details \b Outputs: none * @details \b Alarms: ALARM_ID_FP_INLET_PRESSURE_OUT_LOW_RANGE when * M3 pressure goes beyond low pressure limit. * @details \b Alarms: ALARM_ID_FP_INLET_PRESSURE_OUT_HIGH_RANGE when * M3 pressure goes beyond high pressure limit * @details \b Alarms: ALARM_ID_FP_INLET_PRESSURE_CRITICAL_OUT_RANGE when * M3 pressure goes beyond fault high pressure limit * @return none *************************************************************************/ void checkInletPressures( void ) { F32 pressureM3 = getFilteredPressure( M3_PRES ); BOOL isPresOutOfLowRange = FALSE; BOOL isPresOutOfHighRange = FALSE; BOOL isPresOutOfHighRangeFault = FALSE; if ( TRUE == isFPDefeatured() ) { isPresOutOfLowRange = ( ( pressureM3 < MIN_INLET_WATER_PRESSURE_DEFEATURED_WARNING_LOW_PSIG ) ? TRUE : FALSE); isPresOutOfHighRange = ( ( ( pressureM3 > MAX_INLET_WATER_PRESSURE_DEFEATURED_WARNING_HIGH_PSIG ) && ( pressureM3 < MAX_INLET_WATER_PRESSURE_DEFEATURED_FAULT_HIGH_PSIG ) ) ? TRUE : FALSE); isPresOutOfHighRangeFault = ( ( pressureM3 > MAX_INLET_WATER_PRESSURE_DEFEATURED_FAULT_HIGH_PSIG ) ? TRUE : FALSE); checkPersistentAlarm( ALARM_ID_FP_INLET_PRESSURE_OUT_LOW_RANGE, isPresOutOfLowRange, pressureM3, MIN_INLET_WATER_PRESSURE_DEFEATURED_WARNING_LOW_PSIG ); checkPersistentAlarm( ALARM_ID_FP_INLET_PRESSURE_OUT_HIGH_RANGE, isPresOutOfHighRange, pressureM3, MAX_INLET_WATER_PRESSURE_DEFEATURED_WARNING_HIGH_PSIG ); checkPersistentAlarm( ALARM_ID_FP_INLET_PRESSURE_CRITICAL_OUT_RANGE, isPresOutOfHighRangeFault, pressureM3, MAX_INLET_WATER_PRESSURE_DEFEATURED_FAULT_HIGH_PSIG ); } else { isPresOutOfLowRange = ( ( pressureM3 < MIN_INLET_WATER_PRESSURE_WARNING_LOW_PSIG ) ? TRUE : FALSE); isPresOutOfHighRange = ( ( ( pressureM3 > MAX_INLET_WATER_PRESSURE_WARNING_HIGH_PSIG ) && ( pressureM3 < MAX_INLET_WATER_PRESSURE_FAULT_HIGH_PSIG ) ) ? TRUE : FALSE); isPresOutOfHighRangeFault = ( ( pressureM3 > MAX_INLET_WATER_PRESSURE_FAULT_HIGH_PSIG ) ? TRUE : FALSE); checkPersistentAlarm( ALARM_ID_FP_INLET_PRESSURE_OUT_LOW_RANGE, isPresOutOfLowRange, pressureM3, MIN_INLET_WATER_PRESSURE_WARNING_LOW_PSIG ); checkPersistentAlarm( ALARM_ID_FP_INLET_PRESSURE_OUT_HIGH_RANGE, isPresOutOfHighRange, pressureM3, MAX_INLET_WATER_PRESSURE_WARNING_HIGH_PSIG ); checkPersistentAlarm( ALARM_ID_FP_INLET_PRESSURE_CRITICAL_OUT_RANGE, isPresOutOfHighRangeFault, pressureM3, MAX_INLET_WATER_PRESSURE_FAULT_HIGH_PSIG ); } } /*********************************************************************//** * @brief * The checkPermeateHighFlow function checks the permeate flow rate from P16 * against the set target flow rate and alarm if the flow is out of range high. * @details \b Inputs: permeateFlow * @details \b Outputs: none * @details \b Alarms: ALARM_ID_FP_PERMEATE_FLOW_OUT_HIGH_RANGE when * P16 flow goes beyond threshold limit from set target flow. * @return none *************************************************************************/ void checkPermeateHighFlow( void ) { F32 permeateFlow = getFilteredFlow( P16_FLOW ); BOOL isFlowOutOfRange = FALSE; F32 maxAllowedPermeateFlow = (F32)getTargetROPumpFlowRateMLPM() * MAX_PERMEATE_FLOW_FAULT_THRESHOLD; isFlowOutOfRange = ( ( permeateFlow > maxAllowedPermeateFlow ) ? TRUE : FALSE); checkPersistentAlarm( ALARM_ID_FP_PERMEATE_FLOW_OUT_HIGH_RANGE, isFlowOutOfRange, permeateFlow, maxAllowedPermeateFlow ); } /*********************************************************************//** * @brief * The checkPermeateLowFlow function checks the permeate low flow rate from P16 * against the set target flow rate and alarm if the flow is out of range. * @details \b Inputs: permeateFlow * @details \b Outputs: none * @details \b Alarms: ALARM_ID_FP_PERMEATE_FLOW_OUT_LOW_RANGE when * P16 flow goes beyond threshold limit from set target flow. * @return none *************************************************************************/ void checkPermeateLowFlow( void ) { F32 permeateFlow = getFilteredFlow( P16_FLOW ); BOOL isFlowOutOfRange = FALSE; F32 minimumAllowedPermeateFlow = (F32)getTargetROPumpFlowRateMLPM() - PERMEATE_FLOW_FAULT_MIN_THRESHOLD; isFlowOutOfRange = ( ( permeateFlow < minimumAllowedPermeateFlow ) ? TRUE : FALSE); checkPersistentAlarm( ALARM_ID_FP_PERMEATE_FLOW_OUT_LOW_RANGE, isFlowOutOfRange, permeateFlow, minimumAllowedPermeateFlow); } /*********************************************************************//** * @brief * The checkROPressures function checks the RO membrane pressure * against the pressure threshold and alarm if the pressure is out of range. * @details \b Inputs: pressureP13 * @details \b Outputs: none * @details \b Alarms: ALARM_ID_FP_RO_INLET_PRESSURE_OUT_HIGH_RANGE when * P13 pressure goes beyond high pressure limit. * @return none *************************************************************************/ void checkROPressures( void ) { F32 pressureP13 = getPressure( P13_PRES ); if ( pressureP13 > MAX_INLET_RO_PUMP_PRESSURE_WARNING_PSIG ) { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_RO_INLET_PRESSURE_OUT_HIGH_RANGE, pressureP13, MAX_INLET_RO_PUMP_PRESSURE_WARNING_PSIG ) } } /*********************************************************************//** * @brief * The checkROPressures function checks the RO membrane outlet pressure * against the pressure threshold and alarm if the pressure is out of range. * @details \b Inputs: pressureP17 * @details \b Outputs: none * @details \b Alarms: ALARM_ID_FP_PRESSURE_RELIEF_OUT_LOW_RANGE when * P17 pressure goes beyond low pressure limit. * @details \b Alarms: ALARM_ID_FP_PRESSURE_RELIEF_OUT_HIGH_RANGE when * P17 pressure goes beyond high pressure limit. * @return none *************************************************************************/ void checkPressureRelief( void ) { F32 pressureP17 = getFilteredPressure( P17_PRES ); BOOL isPresReliefOutOfLowRange = FALSE; BOOL isPresReliefOutOfHighRange = FALSE; isPresReliefOutOfLowRange = ( ( pressureP17 < MIN_PRESSURE_RELIEF_WARNING_LOW_PSIG ) ? TRUE : FALSE); isPresReliefOutOfHighRange = ( ( pressureP17 > MAX_PRESSURE_RELIEF_WARNING_HIGH_PSIG ) ? TRUE : FALSE); checkPersistentAlarm( ALARM_ID_FP_PRESSURE_RELIEF_OUT_LOW_RANGE, isPresReliefOutOfLowRange, pressureP17, MIN_PRESSURE_RELIEF_WARNING_LOW_PSIG ); checkPersistentAlarm( ALARM_ID_FP_PRESSURE_RELIEF_OUT_HIGH_RANGE, isPresReliefOutOfHighRange, pressureP17, MAX_PRESSURE_RELIEF_WARNING_HIGH_PSIG ); } /*********************************************************************//** * @brief * The checkInletTemperatures function checks the inlet water temperature * against the temperature threshold and alarm if the temperature is out of range. * @details \b Inputs: temperatureP10, temperatureM3 * @details \b Outputs: none * @details \b Alarms: ALARM_ID_FP_INLET_TEMPERATURE_OUT_LOW_RANGE when * P10 or M3 temperature goes beyond low temperature limit. * @details \b Alarms: ALARM_ID_FP_INLET_TEMPERATURE_OUT_HIGH_RANGE when * P10 or M3 temperature goes beyond high temperature limit * @return none *************************************************************************/ void checkInletTemperatures( void ) { F32 temperatureP10 = getFilteredConductivitySensorTemperature( P9_COND ); F32 temperatureM3 = getFilteredPressureSensorTemperature( M3_PRES ); BOOL isTempOutOfLowRange = FALSE; BOOL isTempOutOfHighRange = FALSE; isTempOutOfLowRange = ( ( temperatureP10 < INLET_TEMPERATURE_LOW_THRESHOLD_C ) ? TRUE : FALSE); isTempOutOfHighRange = ( ( temperatureP10 > INLET_TEMPERATURE_HIGH_THRESHOLD_C ) ? TRUE : FALSE); checkPersistentAlarm( ALARM_ID_FP_INLET_TEMPERATURE_OUT_LOW_RANGE, isTempOutOfLowRange, temperatureP10, INLET_TEMPERATURE_LOW_THRESHOLD_C ); checkPersistentAlarm( ALARM_ID_FP_INLET_TEMPERATURE_OUT_HIGH_RANGE, isTempOutOfHighRange, temperatureP10, INLET_TEMPERATURE_HIGH_THRESHOLD_C ); isTempOutOfLowRange = ( ( temperatureM3 < INLET_TEMPERATURE_LOW_THRESHOLD_C ) ? TRUE : FALSE); isTempOutOfHighRange = ( ( temperatureM3 > INLET_TEMPERATURE_HIGH_THRESHOLD_C ) ? TRUE : FALSE); checkPersistentAlarm( ALARM_ID_FP_INLET_TEMPERATURE_OUT_LOW_RANGE, isTempOutOfLowRange, temperatureM3, INLET_TEMPERATURE_LOW_THRESHOLD_C ); checkPersistentAlarm( ALARM_ID_FP_INLET_TEMPERATURE_OUT_HIGH_RANGE, isTempOutOfHighRange, temperatureM3, INLET_TEMPERATURE_HIGH_THRESHOLD_C ); } /*********************************************************************//** * @brief * The checkInletConductivity function checks the inlet conductivity * against the conductivity threshold and alarm if the conductivity is out of range. * @details \b Inputs: conductivityP9 * @details \b Outputs: none * @details \b Alarms: ALARM_ID_FP_INLET_CONDUCTIVITY_OUT_HIGH_RANGE when * P9 pressure goes beyond high conductivity limit. * @return none *************************************************************************/ void checkInletConductivity( void ) { F32 conductivityP9 = getFilteredConductivity( P9_COND ); BOOL isConductivtyOutOfLowRange = FALSE; isConductivtyOutOfLowRange = ( ( conductivityP9 > INLET_CONDUCTIVITY_HIGH_THRESHOLD_US ) ? TRUE : FALSE); checkPersistentAlarm( ALARM_ID_FP_INLET_CONDUCTIVITY_OUT_HIGH_RANGE, isConductivtyOutOfLowRange, conductivityP9, INLET_CONDUCTIVITY_HIGH_THRESHOLD_US ); } /*********************************************************************//** * @brief * The checkInletConductivity function checks the inlet conductivity * against the conductivity threshold and alarm if the conductivity is out of range. * @details \b Inputs: conductivityP18 * @details \b Outputs: none * @details \b Alarms: ALARM_ID_FP_RO_OUTLET_CONDUCTIVITY_HIGH_RANGE when * P9 pressure goes beyond high conductivity limit. * @return none *************************************************************************/ void checkOutletConductivity( void ) { F32 conductivityP18 = getFilteredConductivity( P18_COND ); BOOL isConductivityOutOfLowRange = FALSE; isConductivityOutOfLowRange = ( ( conductivityP18 > OUTLET_CONDUCTIVITY_HIGH_THRESHOLD_US ) ? TRUE : FALSE); checkPersistentAlarm( ALARM_ID_FP_RO_OUTLET_CONDUCTIVITY_HIGH_RANGE, isConductivityOutOfLowRange, conductivityP18, OUTLET_CONDUCTIVITY_HIGH_THRESHOLD_US ); } /*********************************************************************//** * @brief * The checkRORejectionRatio function checks the RO rejection ratio * alarm if the rejection ratio is out of range. * @details \b Inputs: roRRAvg * @details \b Outputs: none * @details \b Alarms: ALARM_ID_FP_REJECTION_RATIO_LOW_RANGE when * RO rejection ratio goes below allowed rejection ratio limit. * @return none *************************************************************************/ void checkRORejectionRatio( void ) { F32 avgRORR = getRORRAverage(); // Alarm if the filtered average is less than allowed RO rejection limit if ( avgRORR < MIN_RO_REJECTION_RATIO_PCT ) { SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_REJECTION_RATIO_LOW_RANGE, avgRORR, MIN_RO_REJECTION_RATIO_PCT) } } /************************************************************************* * TEST SUPPORT FUNCTIONS *************************************************************************/ /**@}*/