Index: firmware/App/Modes/ModeGenPermeate.c =================================================================== diff -u -rba9341bc691b500d5ec3904fec1eb38279c5fbbd -rc0c217faf415f9acd61dcc9a13932fbc7088339e --- firmware/App/Modes/ModeGenPermeate.c (.../ModeGenPermeate.c) (revision ba9341bc691b500d5ec3904fec1eb38279c5fbbd) +++ firmware/App/Modes/ModeGenPermeate.c (.../ModeGenPermeate.c) (revision c0c217faf415f9acd61dcc9a13932fbc7088339e) @@ -25,10 +25,12 @@ #include "ModeGenPermeate.h" #include "ModePreGenPermeate.h" #include "PermeateTank.h" +#include "PIControllers.h" #include "ROPump.h" #include "TaskGeneral.h" #include "Timers.h" #include "Valves.h" +#include "WaterQualityMonitor.h" /** * @addtogroup FPGenPermeateMode @@ -39,13 +41,26 @@ #define PRE_GEN_PERMEATE_DATA_PUBLISH_INTERVAL ( MS_PER_SECOND / TASK_GENERAL_INTERVAL ) ///< Interval (ms/task time) at which the gen permeate mode data published. #define GEN_PERMEATE_BOOST_PUMP_TGT_PSI 25.0F ///< Pressure target in PSI for the boost pump during generate permeate mode. -#define GEN_PERMEATE_RO_PUMP_TGT_ML 700 ///< Flow target in ml/min for the ro pump during generate permeate mode. +#define GEN_PERMEATE_RO_PUMP_TGT_ML 750 ///< Flow target in ml/min for the ro pump during generate permeate mode. +#define PUMP_REST_TIMEOUT_MS ( 3 * MS_PER_SECOND ) ///< Verify Water timer ( in ms ) +#define RO_REJECTION_WAIT_TIME_MS ( 8 * MS_PER_SECOND ) ///< Verify Water timer ( in ms ) +#define MIN_SAMPLES_NEEDED_FOR_DUTY_CYCLE_AVG 10 ///< Minimum number for samples needed for calculating the average duty cycle // ********** private data ********** static FP_GENP_MODE_STATE_T genPermeateState; ///< Currently active generate Permeate state. static U32 genPermeateDataPublicationTimerCounter; ///< Used to schedule generate Permeate data publication to CAN bus. static OVERRIDE_U32_T genPermeateDataPublishInterval; ///< Generate permeate mode data publish interval. +static F32 fillDutySum; ///< Sum of duty cycle values for one fill cycle. +static U32 fillDutyCount; ///< Sample counts for one fill cycle. +static F32 prevFillAvgDutyCycle; ///< Average vale of duty cycle during previous fill state. +static BOOL isFillAvgValid; ///< Flag to check if the average fill duty cycle value is valid or not. +static F32 fullDutySum; ///< Sum of duty cycle values for one full cycle. +static U32 fullDutyCount; ///< Sample counts for one full cycle. +static F32 prevFullAvgDutyCycle; ///< Average vale of duty cycle during previous full state. +static BOOL isFullAvgValid; ///< Flag to check if the average full duty cycle value is valid or not. +static U32 timeInState; ///< Time to wait after reset before starting close loop control (temporary) +static BOOL stateTransitioned; ///< Flag to check if permeate tank state transitioned // ********** private function prototypes ********** @@ -54,6 +69,8 @@ static FP_GENP_MODE_STATE_T handleGenPTankFillState( void ); static void setModeGenPTransition( FP_GENP_MODE_STATE_T state ); static U32 getGenPermeateDataPublishInterval( void ); +static void updateDutyCycleAvg( FP_GENP_MODE_STATE_T state ); +static void calculateDutyCycleAvg( FP_GENP_MODE_STATE_T state ); /*********************************************************************//** * @brief @@ -70,6 +87,16 @@ genPermeateDataPublishInterval.ovInitData = 0; genPermeateDataPublishInterval.override = OVERRIDE_RESET; genPermeateDataPublicationTimerCounter = 0; + fillDutySum = 0.0F; + fillDutyCount = 0; + prevFillAvgDutyCycle = 0.0F; + isFillAvgValid = FALSE; + fullDutySum = 0.0F; + fullDutyCount = 0; + prevFullAvgDutyCycle = 0.0F; + isFullAvgValid = FALSE; + timeInState = 0; + stateTransitioned = FALSE; } /*********************************************************************//** @@ -107,10 +134,12 @@ switch ( genPermeateState ) { case FP_GENP_TANK_FILL_STATE: + updateDutyCycleAvg( FP_GENP_TANK_FILL_STATE ); genPermeateState = handleGenPTankFillState(); break; case FP_GENP_TANK_FULL_STATE: + updateDutyCycleAvg( FP_GENP_TANK_FULL_STATE ); genPermeateState = handleGenPTankFullState(); break; @@ -122,6 +151,8 @@ if ( prevState != genPermeateState ) { + stateTransitioned = TRUE; + calculateDutyCycleAvg( prevState ); setModeGenPTransition( genPermeateState ); SEND_EVENT_WITH_2_U32_DATA( FP_EVENT_GENP_CHANGE, genPermeateState, prevState ) } @@ -142,17 +173,24 @@ *************************************************************************/ static void setModeGenPTransition( FP_GENP_MODE_STATE_T state ) { + F32 initDutyCycle = 0.0F; // Execute on running state switch( state ) { case FP_GENP_TANK_FILL_STATE: + initDutyCycle = isFillAvgValid ? prevFillAvgDutyCycle : getCurrentROPumpDutyCyclePCT(); + setROPumpTargetDutyCycle( initDutyCycle, TRUE ); + timeInState = getMSTimerCount(); if ( TRUE == isBoostPumpInstalled() ) { setBoostPumpTargetPressure( GEN_PERMEATE_BOOST_PUMP_TGT_PSI ); } break; case FP_GENP_TANK_FULL_STATE: + initDutyCycle = isFullAvgValid ? prevFullAvgDutyCycle : getCurrentROPumpDutyCyclePCT(); + setROPumpTargetDutyCycle( initDutyCycle, TRUE ); + timeInState = getMSTimerCount(); if ( TRUE == isBoostPumpInstalled() ) { signalBoostPumpHardStop(); @@ -177,6 +215,16 @@ FP_GENP_MODE_STATE_T state = FP_GENP_TANK_FILL_STATE; PERMEATE_TANK_STATE_T permemeateTankState = getPermeateTankState(); + if ( TRUE == didTimeout( timeInState, PUMP_REST_TIMEOUT_MS ) && stateTransitioned == TRUE ) + { + stateTransitioned = FALSE; + setROPumpTargetFlowRateMLPM( GEN_PERMEATE_RO_PUMP_TGT_ML, TRUE ); + } + // Wait for RO rejection to stabilize after transition from full to fill + RO Rejection moving average duration + if ( TRUE == didTimeout( timeInState, RO_REJECTION_WAIT_TIME_MS ) ) + { + checkRORejectionRatio(); + } if ( permemeateTankState == PERMEATE_TANK_FULL_STATE ) { state = FP_GENP_TANK_FULL_STATE; @@ -195,6 +243,12 @@ static FP_GENP_MODE_STATE_T handleGenPTankFullState( void ) { FP_GENP_MODE_STATE_T state = FP_GENP_TANK_FULL_STATE; + + if ( TRUE == didTimeout( timeInState, PUMP_REST_TIMEOUT_MS ) && stateTransitioned == TRUE ) + { + stateTransitioned = FALSE; + setROPumpTargetFlowRateMLPM( GEN_PERMEATE_RO_PUMP_TGT_ML, TRUE ); + } PERMEATE_TANK_STATE_T permemeateTankState = getPermeateTankState(); if ( permemeateTankState == PERMEATE_TANK_FILL_STATE ) @@ -207,6 +261,58 @@ /*********************************************************************//** * @brief + * The updateDutyCycleAvg function accumulates duty cycle samples for + * states in generate permeate mode. + * @details \b Inputs: none + * @details \b Outputs: none + * @param state genPermeateState enum + * @return none + *************************************************************************/ +static void updateDutyCycleAvg( FP_GENP_MODE_STATE_T state ) +{ + F32 duty = getCurrentROPumpDutyCyclePCT(); + + if ( state == FP_GENP_TANK_FILL_STATE ) + { + fillDutySum += duty; + fillDutyCount++; + } + else if ( state == FP_GENP_TANK_FULL_STATE ) + { + fullDutySum += duty; + fullDutyCount++; + } +} + +/*********************************************************************//** + * @brief + * The calculateDutyCycleAvg function computes the average duty cycle + * from the accumulated samples collected using updateDutyCyle. + * @details \b Inputs: none + * @details \b Outputs: none + * @param state genPermeateState enum + * @return none + *************************************************************************/ +static void calculateDutyCycleAvg( FP_GENP_MODE_STATE_T state ) +{ + if ( state == FP_GENP_TANK_FILL_STATE && fillDutyCount > MIN_SAMPLES_NEEDED_FOR_DUTY_CYCLE_AVG) + { + prevFillAvgDutyCycle = fillDutySum / (F32)fillDutyCount; + isFillAvgValid = TRUE; + fillDutySum = 0.0F; + fillDutyCount = 0; + } + else if ( state == FP_GENP_TANK_FULL_STATE && fullDutyCount > MIN_SAMPLES_NEEDED_FOR_DUTY_CYCLE_AVG ) + { + prevFullAvgDutyCycle = fullDutySum / (F32)fullDutyCount; + isFullAvgValid = TRUE; + fullDutySum = 0.0F; + fullDutyCount = 0; + } +} + +/*********************************************************************//** + * @brief * The getCurrentGenPermeateState function returns the current state of the * gen permeate mode. * @details \b Inputs: genPermeateState