Class SteadyStateDetector
- All Implemented Interfaces:
Serializable
Monitors a set of process variables over a sliding window and determines whether the process has reached steady state. The primary criterion is the R-statistic: the ratio of filtered variance (successive differences) to unfiltered variance (sample variance). At steady state, both variances are similar and R approaches 1.0. During ramps, steps, or oscillations, R drops well below 1.0.
Two additional optional criteria can be enabled:
- Slope test: the absolute slope from linear regression through the window must be below a threshold. This catches slow drifts that the R-test may miss.
- Standard deviation test: the standard deviation of the window must be below a threshold. This catches excessive noise.
The detector is designed for use in online optimization workflows where data is collected externally (e.g., in Python from a DCS historian) and fed into the detector one sample at a time. When all variables pass the SSD test, the process is at steady state and safe for data reconciliation or model calibration.
Typical usage from Python:
detector = SteadyStateDetector(30) # 30-sample window
detector.addVariable(SteadyStateVariable("feed_flow", 30).setUnit("kg/hr"))
detector.addVariable(SteadyStateVariable("temperature", 30).setUnit("C"))
# In a loop, push new readings:
detector.updateVariable("feed_flow", 1005.2)
detector.updateVariable("temperature", 82.1)
result = detector.evaluate()
if result.isAtSteadyState():
# safe to reconcile
...
References:
- Cao, S. and Rhinehart, R.R. (1995), "An efficient method for on-line identification of steady state", Journal of Process Control, 5(6), 363-374.
- Jiang, T., Chen, B. and He, X. (2003), "Industrial application of Wavelet-based steady state detection", Computers and Chemical Engineering, 27, 569-578.
- Version:
- 1.0
- Author:
- Process Optimization Team
- See Also:
-
Field Summary
FieldsModifier and TypeFieldDescriptionprivate intDefault window size for new variables.private static final org.apache.logging.log4j.LoggerLogger for this class.private doubleMinimum fraction (0-1) of variables that must be at steady state for the overall verdict.private booleanWhether a full window is required before declaring steady state.private doubleR-statistic threshold.private static final longprivate doubleMaximum allowed slope (units per sample).private doubleMaximum allowed standard deviation.private final List<SteadyStateVariable> Ordered list of variables (preserves insertion order).private final Map<String, SteadyStateVariable> Registered variables, keyed by name. -
Constructor Summary
ConstructorsConstructorDescriptionCreates a steady-state detector with a default window size of 30.SteadyStateDetector(int defaultWindowSize) Creates a steady-state detector with the given default window size. -
Method Summary
Modifier and TypeMethodDescriptionaddVariable(String name) Adds a variable by name using the default window size.addVariable(SteadyStateVariable variable) Adds a variable to the detector.voidclear()Clears all variables.Creates aDataReconciliationEnginepre-populated with variables from this detector.evaluate()Evaluates all variables against the SSD criteria and returns the result.private booleanEvaluates a single variable against the SSD criteria.intReturns the default window size.doubleReturns the required fraction of variables that must be steady for the overall verdict.doubleReturns the R-statistic threshold.doubleReturns the slope threshold.doubleReturns the standard deviation threshold.getVariable(String name) Returns a variable by name.intReturns the number of registered variables.Returns all registered variables.booleanReturns whether a full window is required before declaring steady state.booleanremoveVariable(String name) Removes a variable by name.setDefaultWindowSize(int defaultWindowSize) Sets the default window size for new variables.setRequiredFraction(double requiredFraction) Sets the required fraction of variables that must be at steady state.setRequireFullWindow(boolean requireFullWindow) Sets whether a full window is required before declaring steady state.setRThreshold(double rThreshold) Sets the R-statistic threshold.setSlopeThreshold(double slopeThreshold) Sets the slope threshold.setStdDevThreshold(double stdDevThreshold) Sets the standard deviation threshold.toString()Returns a summary string.voidUpdates all variables at once from a map of name-value pairs.updateAndEvaluate(Map<String, Double> values) Convenience method: updates all variables and evaluates in one call.voidupdateVariable(String name, double value) Updates a single variable with a new measurement value.
-
Field Details
-
serialVersionUID
private static final long serialVersionUID- See Also:
-
logger
private static final org.apache.logging.log4j.Logger loggerLogger for this class. -
variableMap
Registered variables, keyed by name. -
variableList
Ordered list of variables (preserves insertion order). -
defaultWindowSize
private int defaultWindowSizeDefault window size for new variables. -
rThreshold
private double rThresholdR-statistic threshold. A variable is at steady state if R >= this threshold. Default 0.5 (Cao-Rhinehart recommended range 0.1-1.0; 0.5 is a good balance). -
slopeThreshold
private double slopeThresholdMaximum allowed slope (units per sample). If > 0 and |slope| exceeds this, the variable is not at steady state. Default 0 (disabled). -
stdDevThreshold
private double stdDevThresholdMaximum allowed standard deviation. If > 0 and std.dev exceeds this, the variable is not at steady state. Default 0 (disabled). -
requiredFraction
private double requiredFractionMinimum fraction (0-1) of variables that must be at steady state for the overall verdict. Default 1.0 (all variables must be steady). -
requireFullWindow
private boolean requireFullWindowWhether a full window is required before declaring steady state. Default true.
-
-
Constructor Details
-
SteadyStateDetector
public SteadyStateDetector(int defaultWindowSize) Creates a steady-state detector with the given default window size.- Parameters:
defaultWindowSize- the default number of samples in the sliding window (must be at least 3)- Throws:
IllegalArgumentException- if defaultWindowSize is less than 3
-
SteadyStateDetector
public SteadyStateDetector()Creates a steady-state detector with a default window size of 30.
-
-
Method Details
-
addVariable
Adds a variable to the detector.- Parameters:
variable- the steady-state variable to monitor- Returns:
- this detector for chaining
- Throws:
IllegalArgumentException- if a variable with the same name already exists
-
addVariable
Adds a variable by name using the default window size.- Parameters:
name- the tag name- Returns:
- the created variable (for further configuration)
-
getVariable
Returns a variable by name.- Parameters:
name- the variable name- Returns:
- the variable, or null if not found
-
getVariables
Returns all registered variables.- Returns:
- unmodifiable list of variables in insertion order
-
getVariableCount
public int getVariableCount()Returns the number of registered variables.- Returns:
- variable count
-
removeVariable
Removes a variable by name.- Parameters:
name- the variable name to remove- Returns:
- true if the variable was found and removed
-
clear
public void clear()Clears all variables. -
updateVariable
Updates a single variable with a new measurement value.- Parameters:
name- variable name (tag)value- new measurement reading- Throws:
IllegalArgumentException- if the variable name is not found
-
updateAll
Updates all variables at once from a map of name-value pairs.Convenient for pushing a batch of readings from a DCS scan.
- Parameters:
values- map of variable name to measurement value- Throws:
IllegalArgumentException- if any variable name is not found
-
evaluate
Evaluates all variables against the SSD criteria and returns the result.A variable is at steady state if:
- Its window is full (if
requireFullWindowis true) - R-statistic >=
rThreshold - |slope| <=
slopeThreshold(if slopeThreshold > 0) - std.dev <=
stdDevThreshold(if stdDevThreshold > 0)
The overall process is at steady state if the fraction of steady-state variables is at least
requiredFraction.- Returns:
- the SSD result with per-variable diagnostics and overall verdict
- Its window is full (if
-
evaluateVariable
Evaluates a single variable against the SSD criteria.- Parameters:
v- the variable to evaluate- Returns:
- true if the variable passes all active SSD tests
-
updateAndEvaluate
Convenience method: updates all variables and evaluates in one call.- Parameters:
values- map of variable name to new measurement value- Returns:
- the SSD result
-
createReconciliationEngine
Creates aDataReconciliationEnginepre-populated with variables from this detector.Each steady-state variable that has a defined uncertainty is converted to a
ReconciliationVariableusing the latest value as the measurement and the configured uncertainty. Only variables currently at steady state are included (to avoid reconciling transient data).- Returns:
- a new engine with variables added, ready for constraints and reconciliation
-
getDefaultWindowSize
public int getDefaultWindowSize()Returns the default window size.- Returns:
- default window size for new variables
-
setDefaultWindowSize
Sets the default window size for new variables.- Parameters:
defaultWindowSize- window size (must be at least 3)- Returns:
- this detector for chaining
- Throws:
IllegalArgumentException- if less than 3
-
getRThreshold
public double getRThreshold()Returns the R-statistic threshold.- Returns:
- threshold value (default 0.5)
-
setRThreshold
Sets the R-statistic threshold.A lower threshold (e.g., 0.3) is more lenient — allows more variability before declaring transient. A higher threshold (e.g., 0.8) is stricter — requires very stable signals.
Cao-Rhinehart recommended range: 0.1 to 1.0, with 0.5 as a good default.
- Parameters:
rThreshold- R-statistic threshold in the range (0, 1]- Returns:
- this detector for chaining
- Throws:
IllegalArgumentException- if threshold is not in (0, 2]
-
getSlopeThreshold
public double getSlopeThreshold()Returns the slope threshold.- Returns:
- max allowed absolute slope (units per sample), or 0 if disabled
-
setSlopeThreshold
Sets the slope threshold.The slope is expressed in engineering-units per sample. Set to 0 to disable the slope test.
- Parameters:
slopeThreshold- maximum allowed |slope|, or 0 to disable- Returns:
- this detector for chaining
- Throws:
IllegalArgumentException- if negative
-
getStdDevThreshold
public double getStdDevThreshold()Returns the standard deviation threshold.- Returns:
- max allowed standard deviation, or 0 if disabled
-
setStdDevThreshold
Sets the standard deviation threshold.Set to 0 to disable the std.dev test. When enabled, a variable is only at steady state if its window standard deviation is at or below this threshold.
- Parameters:
stdDevThreshold- max standard deviation, or 0 to disable- Returns:
- this detector for chaining
- Throws:
IllegalArgumentException- if negative
-
getRequiredFraction
public double getRequiredFraction()Returns the required fraction of variables that must be steady for the overall verdict.- Returns:
- fraction in [0, 1]
-
setRequiredFraction
Sets the required fraction of variables that must be at steady state.Default is 1.0 (all variables must pass). Set to 0.8 to allow 20% of variables to be transient and still declare overall steady state.
- Parameters:
requiredFraction- fraction in [0, 1]- Returns:
- this detector for chaining
- Throws:
IllegalArgumentException- if not in [0, 1]
-
isRequireFullWindow
public boolean isRequireFullWindow()Returns whether a full window is required before declaring steady state.- Returns:
- true if full window is required (default)
-
setRequireFullWindow
Sets whether a full window is required before declaring steady state.- Parameters:
requireFullWindow- true to require full window- Returns:
- this detector for chaining
-
toString
-