Index: firmware/App/Controllers/BalancingChamber.c =================================================================== diff -u -r7278aeac8fdd894067a05c3bd3a177d38c0b0803 -re5c384741feb64828c1f4c32ff6daca07b20f46e --- firmware/App/Controllers/BalancingChamber.c (.../BalancingChamber.c) (revision 7278aeac8fdd894067a05c3bd3a177d38c0b0803) +++ firmware/App/Controllers/BalancingChamber.c (.../BalancingChamber.c) (revision e5c384741feb64828c1f4c32ff6daca07b20f46e) @@ -34,6 +34,7 @@ #include "TDInterface.h" #include "Temperature.h" #include "TestSupport.h" +#include "Timers.h" #include "Valves.h" /** @@ -64,6 +65,10 @@ #define COMP_SLOPE -0.000376F ///< Balancing chamber temperature compensation slope factor #define COMP_INTERCEPT 1.007269F ///< Balancing chamber temperature compensation intercept factor +#define BC_SS_VOL_DISCARD_MS ( 10 * SEC_PER_MIN * MS_PER_SECOND ) ///< Discard doses for 10 min before averaging. +#define BC_SS_VOL_WINDOW_MS ( 2 * SEC_PER_MIN * MS_PER_SECOND ) ///< Averaging window length (2 min). +#define BC_SS_VOL_MATCH_PCT 0.05F ///< Two consecutive window avgs must match within ±5%. + /// Payload record structure for balancing chamber switch only request typedef struct { @@ -116,6 +121,18 @@ // Balancing chamber state change tracker static BAL_CHAMBER_EXEC_STATE_T prevBalChamberState; ///< Balancing chamber Previous State tracking variable +// Steady-state bicarb dose volume (survives initBalanceChamber / PreGen→GenD): +// discard 10 min, then consecutive 2-min averages until two match within ±5%. +static BOOL ssBicarbVolActive; ///< TRUE while collecting (until SS confirmed) +static U32 ssBicarbVolStartTimeMS; ///< Collection start time (ms) — discard gate +static U32 ssBicarbVolWindowStartMS; ///< Current 2-min window start (ms) +static F32 ssBicarbVolSampleSum; ///< Dose sum in current window +static U32 ssBicarbVolSampleCount; ///< Dose count in current window +static F32 ssBicarbVolPrevAvg; ///< Previous 2-min window average (mL) +static BOOL ssBicarbVolHavePrev; ///< TRUE after first completed window +static F32 ssBicarbVolSteadyState; ///< Confirmed steady-state dose volume (mL) +static BOOL ssBicarbVolValid; ///< TRUE when steady-state is confirmed + // ********** private function prototypes ********** static BAL_CHAMBER_EXEC_STATE_T handleBalChamberState1FillStart( void ); @@ -134,6 +151,7 @@ static BOOL isBalChamberTimeBasedSwitching( void ); static void scheduleFirstCycleRelaxAfterQdApply( void ); static void calculateBalancingChamberError( void ); +static void recordSteadyStateBicarbVolDoseSample( F32 bicarbVolume ); /*********************************************************************//** * @brief @@ -264,6 +282,156 @@ /*********************************************************************//** * @brief + * The recordSteadyStateBicarbVolDoseSample function accumulates bicarb dose + * samples after the discard interval while SS volume is still being collected. + * @details \b Inputs: bicarbVolume, ssBicarbVolActive, ssBicarbVolValid, + * ssBicarbVolStartTimeMS + * @details \b Outputs: ssBicarbVolSampleSum, ssBicarbVolSampleCount + * @param bicarbVolume Bicarb dose volume at BC dose start (mL) + * @return none + *************************************************************************/ +static void recordSteadyStateBicarbVolDoseSample( F32 bicarbVolume ) +{ + if ( ( TRUE == ssBicarbVolActive ) && + ( FALSE == ssBicarbVolValid ) && + ( TRUE == didTimeout( ssBicarbVolStartTimeMS, BC_SS_VOL_DISCARD_MS ) ) ) + { + ssBicarbVolSampleSum += bicarbVolume; + ssBicarbVolSampleCount++; + } +} + +/*********************************************************************//** + * @brief + * The notifySteadyStateBicarbVolCalStart function starts steady-state bicarb + * volume collection. Keeps an already confirmed steady-state value. + * @details \b Inputs: TEST_CONFIG_DD_DISABLE_DRY_BICARB, ssBicarbVolValid + * @details \b Outputs: ssBicarbVolActive, ssBicarbVolValid, ssBicarbVolSteadyState, + * ssBicarbVolPrevAvg, ssBicarbVolHavePrev, ssBicarbVolSampleSum, + * ssBicarbVolSampleCount, ssBicarbVolStartTimeMS, ssBicarbVolWindowStartMS + * @return none + *************************************************************************/ +void notifySteadyStateBicarbVolCalStart( void ) +{ + if ( ( FALSE == getTestConfigStatus( TEST_CONFIG_DD_DISABLE_DRY_BICARB ) ) && + ( FALSE == ssBicarbVolValid ) ) + { + ssBicarbVolActive = TRUE; + ssBicarbVolValid = FALSE; + ssBicarbVolSteadyState = 0.0F; + ssBicarbVolPrevAvg = 0.0F; + ssBicarbVolHavePrev = FALSE; + ssBicarbVolSampleSum = 0.0F; + ssBicarbVolSampleCount = 0; + ssBicarbVolStartTimeMS = getMSTimerCount(); + ssBicarbVolWindowStartMS = 0; + } +} + +/*********************************************************************//** + * @brief + * The serviceSteadyStateBicarbVolCal function finishes consecutive 2-min + * dose averages after discard; when two consecutive averages match within + * ±5%, the latest average is stored as the steady-state volume. + * @details \b Inputs: ssBicarbVolActive, ssBicarbVolValid, ssBicarbVolStartTimeMS, + * ssBicarbVolWindowStartMS, ssBicarbVolSampleSum, ssBicarbVolSampleCount, + * ssBicarbVolHavePrev, ssBicarbVolPrevAvg + * @details \b Outputs: ssBicarbVolSteadyState, ssBicarbVolValid, ssBicarbVolActive, + * ssBicarbVolPrevAvg, ssBicarbVolHavePrev, ssBicarbVolSampleSum, + * ssBicarbVolSampleCount, ssBicarbVolWindowStartMS + * @return none + *************************************************************************/ +void serviceSteadyStateBicarbVolCal( void ) +{ + F32 windowAvg = 0.0F; + F32 delta = 0.0F; + BOOL matched = FALSE; + + if ( ( TRUE == ssBicarbVolActive ) && ( FALSE == ssBicarbVolValid ) ) + { + if ( TRUE == didTimeout( ssBicarbVolStartTimeMS, BC_SS_VOL_DISCARD_MS ) ) + { + // Start first averaging window when discard ends + if ( 0 == ssBicarbVolWindowStartMS ) + { + ssBicarbVolSampleSum = 0.0F; + ssBicarbVolSampleCount = 0; + ssBicarbVolHavePrev = FALSE; + ssBicarbVolWindowStartMS = getMSTimerCount(); + } + else if ( TRUE == didTimeout( ssBicarbVolWindowStartMS, BC_SS_VOL_WINDOW_MS ) ) + { + if ( ssBicarbVolSampleCount > 0 ) + { + windowAvg = ssBicarbVolSampleSum / (F32)ssBicarbVolSampleCount; + } + + if ( ( TRUE == ssBicarbVolHavePrev ) && ( ssBicarbVolPrevAvg > 0.0F ) ) + { + delta = windowAvg - ssBicarbVolPrevAvg; + if ( delta < 0.0F ) + { + delta = -delta; + } + + if ( delta <= ( ssBicarbVolPrevAvg * BC_SS_VOL_MATCH_PCT ) ) + { + matched = TRUE; + } + } + + if ( TRUE == matched ) + { + ssBicarbVolSteadyState = windowAvg; + ssBicarbVolValid = TRUE; + ssBicarbVolActive = FALSE; + } + else + { + // Slide window: previous = current, start next 2 min + ssBicarbVolPrevAvg = windowAvg; + ssBicarbVolHavePrev = TRUE; + ssBicarbVolSampleSum = 0.0F; + ssBicarbVolSampleCount = 0; + ssBicarbVolWindowStartMS = getMSTimerCount(); + } + } + } + } +} + +/*********************************************************************//** + * @brief + * The isSteadyStateBicarbVolumeValid function reports whether steady-state + * bicarb volume has been confirmed. + * @details \b Inputs: ssBicarbVolValid + * @details \b Outputs: none + * @return TRUE when steady-state bicarb volume is valid + *************************************************************************/ +BOOL isSteadyStateBicarbVolumeValid( void ) +{ + BOOL result = ssBicarbVolValid; + + return result; +} + +/*********************************************************************//** + * @brief + * The getSteadyStateBicarbVolume function returns the confirmed steady-state + * bicarb dose volume. + * @details \b Inputs: ssBicarbVolSteadyState + * @details \b Outputs: none + * @return Confirmed steady-state bicarb dose volume (mL) + *************************************************************************/ +F32 getSteadyStateBicarbVolume( void ) +{ + F32 result = ssBicarbVolSteadyState; + + return result; +} + +/*********************************************************************//** + * @brief * The getAcidDoseVol function gets acid mix volume * @details \b Inputs: acidDoseVolume * @details \b Outputs: none @@ -707,6 +875,7 @@ // start acid and bicarb pump with the expected quantity setConcentratePumpTargetSpeed( D11_PUMP, DOSING_CONCENTRATE_PUMP_SPEED, acidVolume ); setConcentratePumpTargetSpeed( D10_PUMP, DOSING_CONCENTRATE_PUMP_SPEED, bicarbVolume ); + recordSteadyStateBicarbVolDoseSample( bicarbVolume ); requestConcentratePumpOn( D11_PUMP ); requestConcentratePumpOn( D10_PUMP ); } @@ -1024,6 +1193,7 @@ // start acid and bicarb pump with the expected quantity setConcentratePumpTargetSpeed( D11_PUMP, DOSING_CONCENTRATE_PUMP_SPEED, acidVolume ); setConcentratePumpTargetSpeed( D10_PUMP, DOSING_CONCENTRATE_PUMP_SPEED, bicarbVolume ); + recordSteadyStateBicarbVolDoseSample( bicarbVolume ); requestConcentratePumpOn( D11_PUMP ); requestConcentratePumpOn( D10_PUMP ); }