Index: firmware/App/Controllers/PermeateTank.c =================================================================== diff -u -r61b54ff1d0ff5120a8f3654ff1acf4628f442ffd -r846073b88a25474464d43b4c0e8f300b52021f96 --- firmware/App/Controllers/PermeateTank.c (.../PermeateTank.c) (revision 61b54ff1d0ff5120a8f3654ff1acf4628f442ffd) +++ firmware/App/Controllers/PermeateTank.c (.../PermeateTank.c) (revision 846073b88a25474464d43b4c0e8f300b52021f96) @@ -36,7 +36,6 @@ #define PERMEATE_TANK_PUBLISH_COUNTER_START_COUNT 9 ///< Publishing counter offset #define PERMEATE_TANK_FULL_SWITCH_MS ( 1 * MS_PER_SECOND ) ///< State switch timeout in full state (in ms) - // ********** private data ********** static PERMEATE_TANK_STATE_T permeateTankControllerState; ///< Current state of permeate controller state machine. @@ -46,7 +45,6 @@ static BOOL pendingStopPermeateTankController; ///< Flag indicates an air trap controller stop request is pending. static U32 tankFullDelayTime; ///< Time stamp to track delay before valve switch. - // ********** private function prototypes ********** static PERMEATE_TANK_STATE_T handlePermeateTankManualControlState( void ); Index: firmware/App/Controllers/ROPump.c =================================================================== diff -u -rb9084c526c8ab28a605f4d2640288e2fc80796ff -r846073b88a25474464d43b4c0e8f300b52021f96 --- firmware/App/Controllers/ROPump.c (.../ROPump.c) (revision b9084c526c8ab28a605f4d2640288e2fc80796ff) +++ firmware/App/Controllers/ROPump.c (.../ROPump.c) (revision 846073b88a25474464d43b4c0e8f300b52021f96) @@ -74,6 +74,8 @@ static F32 roPumpDutyCyclePctSet; ///< Currently set RO pump PWM duty cycle. static OVERRIDE_F32_T roPumpOpenLoopTargetDutyCycle; ///< Target RO pump open loop PWM. static BOOL roPumpStartControl; ///< boolean to determine when closed loop flow control starts +static U32 roPumpClosedLoopStartTimeMS; ///< Timeout timer for RO pump to reach minimum target flow +static BOOL reachedMinimumFlow; ///< Flag indicating RO pump reached minimum target flow // ********** private function prototypes ********** @@ -108,8 +110,6 @@ initializePIController( PI_CONTROLLER_ID_RO_PUMP_PRES, MIN_FLUID_PUMP_DUTY_CYCLE_PCT, ROP_PRESSURE_CONTROL_P_COEFFICIENT, ROP_PRESSURE_CONTROL_I_COEFFICIENT, MIN_FLUID_PUMP_DUTY_CYCLE_PCT, MAX_FLUID_PUMP_DUTY_CYCLE_PCT, FALSE, 0 ); - initPersistentAlarm( ALARM_ID_FP_PERMEATE_FLOW_RATE_BELOW_TARGET, FP_FLOW_RATE_BELOW_TARGET_CLEAR_MS, FP_FLOW_RATE_BELOW_TARGET_TIMEOUT_MS ); - roPumpState = RO_PUMP_OFF_STATE; isROPumpOn = FALSE; stopPumpRequest = FALSE; @@ -133,6 +133,8 @@ roPumpOpenLoopTargetDutyCycle.ovData = 0.0; roPumpOpenLoopTargetDutyCycle.ovInitData = 0.0; roPumpOpenLoopTargetDutyCycle.override = OVERRIDE_RESET; + roPumpClosedLoopStartTimeMS = 0; + reachedMinimumFlow = FALSE; stopROPump(); } @@ -284,10 +286,8 @@ static RO_PUMP_STATE_T handleROPumpControlToTargetFlowState( void ) { RO_PUMP_STATE_T state = RO_PUMP_CONTROL_TO_TARGET_FLOW_STATE; - F32 nexttgtflow = 0.0; - F32 currentFlowRate = 0.0; - F32 adjustedFlowRate = 0.0; - BOOL isFlowRateLow = FALSE; + F32 currentFlowRate = 0.0F; + F32 minRequiredFlowRate = 0.0F; // Check if need to switch control modes if ( getTargetROPumpPressure() > 0.0F ) @@ -311,10 +311,10 @@ else if ( ++roControlTimerCounter >= ROP_CONTROL_INTERVAL ) { currentFlowRate = getFilteredFlow( P16_FLOW ); - adjustedFlowRate = (F32)getTargetROPumpFlowRateMLPM() * ROP_MIN_FLOW_TO_CONTROL_PCT; + minRequiredFlowRate = (F32)getTargetROPumpFlowRateMLPM() * ROP_MIN_FLOW_TO_CONTROL_PCT; // P16 flow seems to lag in current Leahi HW. We will wait till we hit a % of target flow before we start changing control. - if( ( TRUE == roPumpStartControl ) || ( currentFlowRate >= ( adjustedFlowRate ) ) ) + if( ( TRUE == roPumpStartControl ) || ( currentFlowRate >= ( minRequiredFlowRate ) ) ) { roPumpDutyCyclePctSet = runPIController( PI_CONTROLLER_ID_RO_PUMP_FLOW, (F32)getTargetROPumpFlowRateMLPM(), currentFlowRate ); roPumpDutyCyclePctSet = MIN( roPumpDutyCyclePctSet, ( MAX_FLUID_PUMP_PWM_DUTY_CYCLE * MAX_FLUID_PUMP_DUTY_CYCLE_PCT ) ); @@ -327,10 +327,18 @@ } roControlTimerCounter = 0; - //is flow rate less than 75% of the target flow rate - // wait for 10 seconds for timeout - isFlowRateLow = ( ( currentFlowRate < ( adjustedFlowRate ) ) ? TRUE : FALSE); - checkPersistentAlarm( ALARM_ID_FP_PERMEATE_FLOW_RATE_BELOW_TARGET, isFlowRateLow, currentFlowRate, adjustedFlowRate); + //is flow rate less than 75% of the target flow rate wait for 10 seconds for timeout + if ( ( minRequiredFlowRate > currentFlowRate ) && ( reachedMinimumFlow == FALSE ) ) + { + if ( TRUE == didTimeout( roPumpClosedLoopStartTimeMS, FP_FLOW_RATE_BELOW_TARGET_TIMEOUT_MS ) ) + { + SET_ALARM_WITH_2_U32_DATA( ALARM_ID_FP_PERMEATE_FLOW_RATE_BELOW_TARGET, FP_FLOW_RATE_BELOW_TARGET_TIMEOUT_MS, currentFlowRate ) + } + } + else + { + reachedMinimumFlow = TRUE; + } } return state; @@ -416,6 +424,7 @@ // Get the initial guess of the duty cycle roPumpDutyCyclePctSet = roPumpFlowToPWM( getTargetROPumpFlowRateMLPM() ); roControlTimerCounter = 0; + roPumpClosedLoopStartTimeMS = getMSTimerCount(); isROPumpOn = TRUE; result = TRUE; } Index: firmware/App/Modes/FPModes/ModeGenPermeate.c =================================================================== diff -u -r9b06dafd96aca26795e2aeb05c21a5824b3db97a -r846073b88a25474464d43b4c0e8f300b52021f96 --- firmware/App/Modes/FPModes/ModeGenPermeate.c (.../ModeGenPermeate.c) (revision 9b06dafd96aca26795e2aeb05c21a5824b3db97a) +++ firmware/App/Modes/FPModes/ModeGenPermeate.c (.../ModeGenPermeate.c) (revision 846073b88a25474464d43b4c0e8f300b52021f96) @@ -29,6 +29,7 @@ #include "PIControllers.h" #include "ROPump.h" #include "TaskGeneral.h" +#include "TDInterface.h" #include "Timers.h" #include "Valves.h" #include "WaterQualityMonitor.h" @@ -46,6 +47,7 @@ #define PUMP_REST_TIMEOUT_MS ( 3 * MS_PER_SECOND ) ///< Duraion for open loop control at the start of tank fill/full state ( in ms ) #define RO_REJECTION_WAIT_TIME_MS ( 8 * MS_PER_SECOND ) ///< RO rejection alarm wait time. 5 seconds for RR to stabilize and 3 seconds for calculating rolling average ( in ms ) #define MIN_SAMPLES_NEEDED_FOR_DUTY_CYCLE_AVG 10 ///< Minimum number for samples needed for calculating the average duty cycle +#define MIN_RO_PUMP_DUTY_CYCLE 0.5 ///< Minimum RO pump duty cycle to start in fill/full state #define PERMEATE_FLOW_OUT_OF_RANGE_TIMEOUT_MS ( 12 * MS_PER_SECOND ) ///< Permeate flow low tolerance out of range timeout #define PERMEATE_TANK_EMPTY_LEVEL_VOL_ML 0 ///< Permeate tank volume in empty level ( in ml ) #define PERMEATE_TANK_LOW_LEVEL_VOL_ML 957 ///< Permeate tank volume in low level ( in ml ) @@ -248,14 +250,11 @@ *************************************************************************/ static F32 getTankFullAlarmTimeout( void ) { - F32 expectedDeprimeTime = 0.0F; - F32 expectedTankFullTime = 0.0F; - F32 ddConsumptionRate = getTDDialysateFlowrate() + RINSE_PUMP_TARGET_FLOW; + F32 ddConsumptionRate = getTDDialysateFlowrate() + RINSE_PUMP_TARGET_FLOW; + F32 expectedTankFullTime = ( ( PERMEATE_TANK_HIGH_LEVEL_VOL_ML - PERMEATE_TANK_LOW_LEVEL_VOL_ML ) / ddConsumptionRate ) * SEC_PER_MIN; + F32 expectedDeprimeTime = ( ( PERMEATE_TANK_LOW_LEVEL_VOL_ML - PERMEATE_TANK_EMPTY_LEVEL_VOL_ML ) / ddConsumptionRate ) * SEC_PER_MIN; + tankFullAlarmTimeout = expectedTankFullTime + expectedDeprimeTime; - expectedTankFullTime = ( ( PERMEATE_TANK_HIGH_LEVEL_VOL_ML - PERMEATE_TANK_LOW_LEVEL_VOL_ML ) / ddConsumptionRate ) * SEC_PER_MIN; - expectedDeprimeTime = ( ( PERMEATE_TANK_LOW_LEVEL_VOL_ML - PERMEATE_TANK_EMPTY_LEVEL_VOL_ML ) / ddConsumptionRate ) * SEC_PER_MIN; - tankFullAlarmTimeout = expectedTankFullTime + expectedDeprimeTime; - return tankFullAlarmTimeout; } @@ -268,14 +267,11 @@ *************************************************************************/ static F32 getTankFillAlarmTimeout( void ) { - F32 expectedOverfillTime = 0.0F; - F32 expectedTankFillTime = 0.0F; - F32 ddConsumptionRate = getTDDialysateFlowrate() + RINSE_PUMP_TARGET_FLOW; + F32 ddConsumptionRate = getTDDialysateFlowrate() + RINSE_PUMP_TARGET_FLOW; + F32 expectedTankFillTime = ( ( PERMEATE_TANK_HIGH_LEVEL_VOL_ML - PERMEATE_TANK_LOW_LEVEL_VOL_ML ) / ddConsumptionRate ) * SEC_PER_MIN; + F32 expectedOverfillTime = ( ( PERMEATE_TANK_FULL_LEVEL_VOL_ML - PERMEATE_TANK_HIGH_LEVEL_VOL_ML ) / ddConsumptionRate ) * SEC_PER_MIN; + tankFillAlarmTimeout = ( expectedTankFillTime + ( expectedOverfillTime / 2 ) ); - expectedTankFillTime = ( ( PERMEATE_TANK_HIGH_LEVEL_VOL_ML - PERMEATE_TANK_LOW_LEVEL_VOL_ML ) / ddConsumptionRate ) * SEC_PER_MIN; - expectedOverfillTime = ( ( PERMEATE_TANK_FULL_LEVEL_VOL_ML - PERMEATE_TANK_HIGH_LEVEL_VOL_ML ) / ddConsumptionRate ) * SEC_PER_MIN; - tankFillAlarmTimeout = ( expectedTankFillTime + ( expectedOverfillTime / 2 ) ); - return tankFillAlarmTimeout; } @@ -297,6 +293,8 @@ { case FP_GENP_TANK_FILL_STATE: initDutyCycle = isFillAvgValid ? prevFillAvgDutyCycle : getCurrentROPumpDutyCyclePCT(); + // set the duty cycle to minimum of 0.5 if the value is zero + initDutyCycle = initDutyCycle == 0.0F ? MIN_RO_PUMP_DUTY_CYCLE : initDutyCycle; setROPumpTargetDutyCycle( initDutyCycle, TRUE ); timeInState = getMSTimerCount(); tankFillAlarmTimer = getMSTimerCount(); @@ -308,6 +306,8 @@ case FP_GENP_TANK_FULL_STATE: initDutyCycle = isFullAvgValid ? prevFullAvgDutyCycle : getCurrentROPumpDutyCyclePCT(); + // set the duty cycle to minimum of 0.5 if the value is zero + initDutyCycle = initDutyCycle == 0.0F ? MIN_RO_PUMP_DUTY_CYCLE : initDutyCycle; setROPumpTargetDutyCycle( initDutyCycle, TRUE ); timeInState = getMSTimerCount(); tankFullAlarmTimer = getMSTimerCount(); Index: firmware/App/Monitors/Level.h =================================================================== diff -u -r3417933e6edf61a914c428e2fa944b3b349272a4 -r846073b88a25474464d43b4c0e8f300b52021f96 --- firmware/App/Monitors/Level.h (.../Level.h) (revision 3417933e6edf61a914c428e2fa944b3b349272a4) +++ firmware/App/Monitors/Level.h (.../Level.h) (revision 846073b88a25474464d43b4c0e8f300b52021f96) @@ -53,8 +53,8 @@ typedef enum level_States { LEVEL_STATE_LOW = 0, ///< Low level - LEVEL_STATE_HIGH, ///< High level LEVEL_STATE_MEDIUM, ///< Medium level + LEVEL_STATE_HIGH, ///< High level LEVEL_STATE_ILLEGAL, ///< Illegal level NUM_OF_LEVELS_STATES ///< Number of level states } LEVEL_STATE_T; Index: firmware/App/Monitors/WaterQualityMonitor.c =================================================================== diff -u -r97e213fb0ea379165bd2ffeb45b942bf206feabb -r846073b88a25474464d43b4c0e8f300b52021f96 --- firmware/App/Monitors/WaterQualityMonitor.c (.../WaterQualityMonitor.c) (revision 97e213fb0ea379165bd2ffeb45b942bf206feabb) +++ firmware/App/Monitors/WaterQualityMonitor.c (.../WaterQualityMonitor.c) (revision 846073b88a25474464d43b4c0e8f300b52021f96) @@ -70,7 +70,7 @@ #define RO_PUMP_DUTY_CYCLE_WARNING_CLEAR_MS ( 1 * MS_PER_SECOND ) ///< Persistence period for duty cycle warning range clear in milliseconds. // pump manufacturer's data for pump current draw based on pump speed and outlet pressure If 58 PSI ≤ P13 < 120 PSI, -// the currently set P12 duty cycle (% PWM) must be < 0.0065(x^2) - 1.9859(x)+193.23, where x = measured P13 pressure in PSI +// the currently set P12 duty cycle (% PWM) must be < 0.0065(x^2) - 1.9859(x) + 193.23, where x = measured P13 pressure in PSI #define QUADRATIC_COEFFICIENT 0.0065F ///< X2 quadratic coefficient #define LINEAR_COEFFICIENT 1.9895F ///< X linear coefficient #define CONSTANT_TERM 193.23F ///< Constant term @@ -229,10 +229,10 @@ F32 currentDutyCyclePct = getCurrentROPumpDutyCyclePCT(); BOOL isFdutyCycleOfRange = FALSE; // TODO verify the calculated dutycycle unit - // If 58 PSI ≤ P13 < 120 PSI, the currently set P12 duty cycle (% PWM) must be < 0.0065(x^2) - 1.9859(x)+193.23, where x = measured P13 pressure in PSI + // If 58 PSI ≤ P13 < 120 PSI, the currently set P12 duty cycle (% PWM) must be < 0.0065(x^2) - 1.9859(x) + 193.23, where x = measured P13 pressure in PSI F32 calculatedDutyCyclePct = ( ( QUADRATIC_COEFFICIENT * ( pressureP13 * pressureP13 ) ) - ( LINEAR_COEFFICIENT * ( pressureP13 ) ) ) + CONSTANT_TERM; - if ( ( pressureP13 >= MAX_INLET_RO_PUMP_PRESSURE_WARNING_LOW_PSIG ) && ( pressureP13 < MAX_INLET_RO_PUMP_PRESSURE_WARNING_HIGH_PSIG) ) + if ( ( pressureP13 >= MAX_INLET_RO_PUMP_PRESSURE_WARNING_LOW_PSIG ) && ( pressureP13 < MAX_INLET_RO_PUMP_PRESSURE_WARNING_HIGH_PSIG ) ) { isFdutyCycleOfRange = currentDutyCyclePct > calculatedDutyCyclePct; checkPersistentAlarm( ALARM_ID_FP_POWER_BUDGET_OUT_OF_RANGE, isFdutyCycleOfRange, calculatedDutyCyclePct, getCurrentROPumpDutyCyclePCT() ); Index: firmware/App/Monitors/WaterQualityMonitor.h =================================================================== diff -u -r2475e55c224cbd841d61b76f1618451efe6be1f5 -r846073b88a25474464d43b4c0e8f300b52021f96 --- firmware/App/Monitors/WaterQualityMonitor.h (.../WaterQualityMonitor.h) (revision 2475e55c224cbd841d61b76f1618451efe6be1f5) +++ firmware/App/Monitors/WaterQualityMonitor.h (.../WaterQualityMonitor.h) (revision 846073b88a25474464d43b4c0e8f300b52021f96) @@ -46,5 +46,6 @@ void checkRORejectionRatio( void ); void checkPermeateHighFlow( void ); void checkPermeateLowFlow( void ); +void checkRODutyCycle( void ); #endif