systems.builtin.stochastic.discrete.DiscreteStochasticCSTR
systems.builtin.stochastic.discrete.DiscreteStochasticCSTR(*args, **kwargs)Discrete-time stochastic CSTR with multiple steady states and process noise.
Combines the challenging nonlinear dynamics of the CSTR (multiple equilibria, bifurcations) with discrete-time sampling and process noise, creating one of the most demanding benchmarks in stochastic process control.
Discrete-Time Stochastic Dynamics
Difference equation (Euler discretization):
C_A[k+1] = C_A[k] + [(F/V)·(C_A_feed - C_A[k]) - r[k]]·Δt + w_C[k]
T[k+1] = T[k] + [(F/V)·(T_feed - T[k]) + q_gen[k] + q_removal[k]]·Δt + w_T[k]
where: - r[k] = k₀·C_A[k]·exp(-E/T[k]): Reaction rate - q_gen = (-ΔH/ρC_p)·r: Heat generation - q_removal = (UA/VρC_p)·(T_jacket[k] - T[k]): Heat removal - w[k] ~ N(0, diag(σ_C², σ_T²)): Process noise
Physical Interpretation
Industrial Digital Control:
CSTR operated with: - PLC/DCS sampling: Δt = 1-60 s typical - Concentration: Online analyzer (GC, NIR) every 1-5 min - Temperature: Fast measurement (1-10 s) - Jacket temperature: Control valve updated discretely
Process Noise Sources:
- Concentration noise (σ_C):
- Feed composition variations (batch-to-batch)
- Sampling/analyzer uncertainty
- Flow rate fluctuations
- Typical: 0.001-0.01 mol/L per step
- Temperature noise (σ_T):
- Heat transfer coefficient variations (fouling)
- Ambient temperature changes
- Flow rate in jacket fluctuations
- Most critical: Affects rates exponentially
- Typical: 0.1-2.0 K per step
Why Temperature Noise Dominates:
Arrhenius: r ∝ exp(-E/T) - Small T change → large rate change - E/T² ≈ 8750/350² ≈ 0.071 K⁻¹ - 1 K noise → 7% rate change - This creates strong coupling to concentration
Multiple Steady States Under Noise
Deterministic: 1, 2, or 3 steady states possible
With Noise: - States fluctuate around deterministic equilibria - Noise can cause transitions between basins - Rare events: Escape from desired state - Metastability: Long residence time then sudden transition
Critical for Control: - Must maintain high-conversion despite noise - Risk of noise-induced transition to low-conversion - Probability of transition depends on σ_T, distance to saddle - Requires robust control + risk management
State Space
State: X[k] = [C_A[k], T[k]] - C_A[k]: Concentration at time k·Δt [mol/L] - T[k]: Temperature at time k·Δt [K] - Stochastic processes (not deterministic)
Control: u[k] = T_jacket[k] - Jacket temperature [K] - Zero-order hold between samples
Noise: w[k] = [w_C[k], w_T[k]] - w[k] ~ N(0, Σ_w) - Σ_w = diag(σ_C², σ_T²) - Independent, Gaussian, white
Key Properties
1. Markov Property: Essential for dynamic programming, RL, Kalman filtering.
2. Multiple Modes: State distribution may be multimodal (near bifurcation).
3. Exponential Sensitivity: Temperature noise amplified exponentially by Arrhenius.
4. Metastability: System can stay near unstable equilibrium for long time.
5. Rare Transitions: Low probability but high consequence events.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| F | float | Same as deterministic CSTR (see ContinuousCSTR) | required |
| V | float | Same as deterministic CSTR (see ContinuousCSTR) | required |
| C_A_feed | float | Same as deterministic CSTR (see ContinuousCSTR) | required |
| T_feed | float | Same as deterministic CSTR (see ContinuousCSTR) | required |
| k0 | float | Same as deterministic CSTR (see ContinuousCSTR) | required |
| E | float | Same as deterministic CSTR (see ContinuousCSTR) | required |
| delta_H | float | Same as deterministic CSTR (see ContinuousCSTR) | required |
| rho | float | Same as deterministic CSTR (see ContinuousCSTR) | required |
| Cp | float | Same as deterministic CSTR (see ContinuousCSTR) | required |
| UA | float | Same as deterministic CSTR (see ContinuousCSTR) | required |
| sigma_C | float | Process noise std dev for C_A [mol/L per step] - Typical: 0.001-0.01 mol/L - Smaller than batch reactor (continuous operation) | 0.001 |
| sigma_T | float | Process noise std dev for T [K per step] - Typical: 0.1-2.0 K - Most critical parameter - Conversion from continuous: σ_c·√Δt | 0.5 |
| dt | float | Sampling period [s] - CSTR typically slower than batch: 1-60 s - Faster near high-conversion (less stable) - Slower at low-conversion (more stable) | 5.0 |
Applications
1. Stochastic MPC: Model Predictive Control with chance constraints: - Probabilistic safety: P(T < T_max) ≥ 0.99 - Risk-sensitive objective: E[cost] + λ·Var[cost] - Scenario tree or robust tubes
2. Particle Filter: State estimation with multiple modes: - Essential near transitions - Handles non-Gaussian distributions - Expensive but necessary
3. Robust Startup: Transition low → high conversion despite noise: - Tube-based MPC - Barrier certificates - Risk-aware control
4. Reliability Analysis: Assess transition probability: - Monte Carlo with importance sampling - Large deviations theory - Mean first passage time
5. Fault Detection: Distinguish faults from noise: - Statistical tests on residuals - Anomaly detection on likelihood - Change point detection
Numerical Simulation
Monte Carlo Ensemble:
Critical for CSTR to characterize rare events: - N = 1,000-10,000 runs - Estimate transition probability - Identify escape paths - Design robust controllers
Single Trajectory:
May not be representative: - Could stay in one state by chance - May transition unusually fast/slow - Always report ensemble statistics
State Estimation
Recommended Approach:
For high-conversion operation: 1. Use UKF or particle filter (nonlinearity) 2. Monitor distance to saddle point 3. Increase measurement rate if approaching instability 4. Switch to particle filter if bimodality detected
For startup/transitions: 1. Particle filter essential (multimodal) 2. Large particle count (N ≥ 1000) 3. Importance sampling toward rare events
Comparison with Deterministic
Deterministic Discrete CSTR: - Single trajectory per IC and control - Multiple equilibria (1-3) - Bifurcations (saddle-node, Hopf)
Stochastic Discrete CSTR: - Ensemble of trajectories - Stochastic equilibria (distributions) - Stochastic bifurcations (P and D) - Noise-induced transitions
Critical Difference: Stochastic model essential for: - Reliability assessment - Risk management - Robust control design - Safety verification
Limitations
- Euler discretization: O(Δt) error
- Additive noise: Not multiplicative
- Constant noise: Not state/time-dependent
- White noise: No temporal correlation
- Gaussian noise: Not heavy-tailed
Extensions
- Higher-order discretization (RK4)
- Multiplicative noise: σ_T(T)
- Colored noise: Autoregressive
- Jump processes: Fault events
- Time-varying parameters: Catalyst deactivation
See Also
ContinuousStochasticCSTR : Continuous-time version DiscreteStochasticBatchReactor : Batch version DiscreteCSTR : Deterministic discrete CSTR
Methods
| Name | Description |
|---|---|
| compute_damkohler_number | Compute Damköhler number Da = k·τ. |
| compute_residence_time | Compute residence time τ = V/F. |
| define_system | Define discrete-time stochastic CSTR dynamics. |
| estimate_transition_probability | Estimate probability of transitioning to low-conversion state. |
| find_steady_states | Find all steady states (deterministic part). |
| get_process_noise_covariance | Get process noise covariance matrix. |
| setup_equilibria | Set up equilibrium points (deterministic part). |
compute_damkohler_number
systems.builtin.stochastic.discrete.DiscreteStochasticCSTR.compute_damkohler_number(
T,
)Compute Damköhler number Da = k·τ.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| T | float | Temperature [K] | required |
Returns
| Name | Type | Description |
|---|---|---|
| float | Damköhler number |
Notes
Da >> 1: Fast reaction, high conversion Da << 1: Slow reaction, low conversion
compute_residence_time
systems.builtin.stochastic.discrete.DiscreteStochasticCSTR.compute_residence_time(
)Compute residence time τ = V/F.
Returns
| Name | Type | Description |
|---|---|---|
| float | Residence time [s] |
Notes
Natural time scale for CSTR dynamics. Sampling period typically: dt ~ 0.5-5·τ
define_system
systems.builtin.stochastic.discrete.DiscreteStochasticCSTR.define_system(
F_val=100.0,
V_val=100.0,
C_A_feed_val=1.0,
T_feed_val=350.0,
k0_val=72000000000.0,
E_val=8750.0,
delta_H_val=-50000.0,
rho_val=1000.0,
Cp_val=0.239,
UA_val=50000.0,
sigma_C=0.001,
sigma_T=0.5,
dt=5.0,
discretization_method='euler',
x_ss=None,
u_ss=None,
)Define discrete-time stochastic CSTR dynamics.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| F_val | float | Volumetric flow rate [L/s] | 100.0 |
| V_val | float | Reactor volume [L] | 100.0 |
| C_A_feed_val | float | Feed concentration [mol/L] | 1.0 |
| T_feed_val | float | Feed temperature [K] | 350.0 |
| k0_val | float | Pre-exponential factor [1/s] | 72000000000.0 |
| E_val | float | Activation energy [K] (dimensionless Eₐ/R) | 8750.0 |
| delta_H_val | float | Heat of reaction [J/mol] (negative = exothermic) | -50000.0 |
| rho_val | float | Density [kg/L] | 1000.0 |
| Cp_val | float | Specific heat capacity [J/(kg·K)] | 0.239 |
| UA_val | float | Overall heat transfer coefficient × area [J/(s·K)] | 50000.0 |
| x_ss | Optional[np.ndarray] | Steady-state [Cₐ, T] for equilibrium setup | None |
| u_ss | Optional[np.ndarray] | Steady-state [T_jacket] for equilibrium setup | None |
| sigma_C | float | Process noise std dev for C_A [mol/L per step] - Smaller than batch (continuous operation) - Typical: 0.001-0.01 mol/L - Feed variability, analyzer noise | 0.001 |
| sigma_T | float | Process noise std dev for T [K per step] - Most critical parameter - Typical: 0.1-2.0 K - Heat transfer fluctuations, ambient changes - Conversion: σ_c·√Δt from continuous | 0.5 |
| dt | float | Sampling period [s] - CSTR slower than batch: 1-60 s typical - Residence time: τ = V/F = 1 s (for defaults) - Guideline: dt ~ 0.5-5·τ - Faster near high-conversion (less stable) | 5.0 |
| discretization_method | str | ‘euler’ or ‘rk4’ | 'euler' |
| x_ss | Optional[np.ndarray] | Steady state (if known) | None |
| u_ss | Optional[np.ndarray] | Steady state (if known) | None |
Notes
Noise Scaling:
For continuous σ_c [state/√s]: σ_discrete = σ_c·√dt
Example: σ_T_c = 1 K/√s, dt = 5 s → σ_T_d = 1·√5 ≈ 2.24 K per step
Temperature Noise Criticality:
Arrhenius sensitivity: ∂r/∂T ≈ r·(E/T²) - At T = 390 K, E = 8750 K: sensitivity = 0.058 K⁻¹ - 1 K noise → 5.8% rate change - 2 K noise → 11.6% rate change - This is why σ_T most important
Sampling Time:
Tradeoffs: - Smaller dt: More accurate, faster control, but more noise samples - Larger dt: Smoother (less noise), but miss dynamics
For CSTR: - High-conversion: dt = 1-5 s (critical, fast control) - Low-conversion: dt = 5-30 s (stable, slower) - Startup: dt = 1-2 s (transitions critical)
Multiple Steady States:
CSTR can have 1-3 steady states. Use find_steady_states() to locate all equilibria for given T_jacket.
Noise causes transitions between states! - Design σ_T small enough for reliability - Or design controller to prevent transitions
estimate_transition_probability
systems.builtin.stochastic.discrete.DiscreteStochasticCSTR.estimate_transition_probability(
x_initial,
u_sequence,
threshold_T,
n_simulations=1000,
)Estimate probability of transitioning to low-conversion state.
Uses Monte Carlo simulation to estimate rare event probability.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| x_initial | np.ndarray | Initial state (e.g., high-conversion) | required |
| u_sequence | np.ndarray | Control sequence (n_steps, 1) | required |
| threshold_T | float | Temperature threshold for transition [K] (e.g., T < 370 K indicates low-conversion) | required |
| n_simulations | int | Number of Monte Carlo runs | 1000 |
Returns
| Name | Type | Description |
|---|---|---|
| dict | Statistics: probability, mean_time, std_time |
Examples
>>> cstr = DiscreteStochasticCSTR()
>>> x0 = np.array([0.1, 390.0]) # High-conversion
>>> u_seq = np.full((200, 1), 350.0)
>>> result = cstr.estimate_transition_probability(
... x0, u_seq, threshold_T=370.0, n_simulations=1000
... )
>>> print(f"P(transition) = {result['probability']:.4f}")find_steady_states
systems.builtin.stochastic.discrete.DiscreteStochasticCSTR.find_steady_states(
T_jacket,
T_range=(300.0, 500.0),
n_points=100,
)Find all steady states (deterministic part).
Uses root finding with multiple initial guesses.
Parameters
| Name | Type | Description | Default |
|---|---|---|---|
| T_jacket | float | Jacket temperature [K] | required |
| T_range | tuple | Temperature search range [K] | (300.0, 500.0) |
| n_points | int | Number of initial guesses | 100 |
Returns
| Name | Type | Description |
|---|---|---|
| List[Tuple[float, float]] | List of (C_A, T) steady states |
Notes
For stochastic system, these are centers of probability distributions. Actual state fluctuates around these points.
With noise, transitions between states possible!
Examples
>>> cstr = DiscreteStochasticCSTR()
>>> states = cstr.find_steady_states(T_jacket=350.0)
>>> for i, (C_A, T) in enumerate(states):
... print(f"State {i+1}: C_A={C_A:.3f}, T={T:.1f}")get_process_noise_covariance
systems.builtin.stochastic.discrete.DiscreteStochasticCSTR.get_process_noise_covariance(
)Get process noise covariance matrix.
Returns
| Name | Type | Description |
|---|---|---|
| np.ndarray | 2x2 diagonal covariance matrix |
Examples
>>> cstr = DiscreteStochasticCSTR(sigma_C=0.001, sigma_T=0.5)
>>> Q = cstr.get_process_noise_covariance()
>>> print(f"Process noise:\n{Q}")setup_equilibria
systems.builtin.stochastic.discrete.DiscreteStochasticCSTR.setup_equilibria()Set up equilibrium points (deterministic part).
Note: With process noise, system doesn’t stay at equilibrium but fluctuates around it. Multiple equilibria may exist.