Simulation#
Bioreactor batch simulator#
A deterministic fed-batch bioreactor simulator with tunable disturbance channels.
Purpose#
This module is the quantitative baseline for batch trajectory adaptation and, later, batch mid-course correction. It makes three claims demonstrable, with numbers a reader can reproduce exactly from a seed:
Replaying a “golden batch” trajectory open-loop does not reproduce the golden outcome, because each batch carries its own disturbances.
The spread persists even when the measured initial conditions are held identical, because disturbances also arise during the batch.
The quality variance under replay therefore decomposes into a bucket that pre-batch (feedforward) adaptation can address, a bucket that only mid-course (feedback) correction can address, and a noise floor.
The model#
A 10-day fed-batch bioreactor with biomass X, substrate S, product
(titer) P and working volume V. The specific growth rate follows the
gamma-concept model of Rosso et al. (1995): a cardinal temperature model with
inflection (CTMI) multiplied by a cardinal pH model (CPM), each equal to 1 at
its optimum and exactly 0 outside its cardinal range, further multiplied by
Monod substrate limitation, a within-batch disturbance phi(t), an
initial-condition growth-inhibition factor and an oxygen-limitation factor:
mu_pot = mu_opt * gamma_T(T) * gamma_pH(pH) * S / (K_S + S) * phi * inh
f_O2 = smooth_min(1, our_capacity / ((o2_yield * mu_pot + o2_m) * X))
mu = mu_pot * f_O2
k_d = k_d0 * (1 + exp((T - temp_death) / width_death))
+ k_d_starv * k_s_starv / (k_s_starv + S)
+ k_d_hyp * (1 - f_O2)
q_P = (alpha_lp * mu + beta_lp * gamma_q(T) * gamma_pH(pH) * phi * f_O2)
* S / (k_sp + S)
dX/dt = mu * X - k_d * X - (F/V) * X
dS/dt = -(mu / yield_xs + maintenance) * X - q_P * X / yield_ps
+ (F/V) * (feed_substrate - S)
dP/dt = q_P * X - (F/V) * P
dV/dt = F
The couplings are chosen so the industrially standard biphasic temperature shift (a warm growth phase, then a mild-hypothermia production phase) is a genuine optimum rather than decoration, and so the right schedule depends on the batch’s own conditions:
The oxygen-transfer capacity caps the biomass pile the reactor can sustain, and the cap is temperature-dependent because warmer cells each demand more oxygen. Overshooting the cap is punished by hypoxic death, an irreversible loss, so the optimal pile size is interior.
Strong hypothermic growth arrest below about 28 degC (the reason biphasic mammalian-cell culture works) freezes the pile once the batch shifts cold, so the timing of the shift decides the production capacity, and the right timing depends on the inoculum and the growth rate the raw-material lot supports.
Production consumes substrate (
yield_ps) and stalls when it runs out (k_sp); starvation kills cells (k_d_starv). Residual growth at too-warm production temperatures burns the feed that production needs, which is what places the production hold at an interior optimum (temp_production) below the isolated productivity optimumtemp_q_opt.The growth-inhibition factor
inh(from the raw-material impurity latent factor) acts on growth only, so an inhibited lot needs a longer warm growth phase, not a scaled-down copy of the same batch.
The gamma hypothesis (temperature and pH acting independently on growth) is a modelling choice, not an established fact: published work finds the cardinal temperatures themselves shift with pH. It is adopted here because it keeps the true optimum interpretable in closed form.
Sensitivity by construction#
A simulator whose quality output moves visibly when an input moves by less than an instrument can resolve is not believable. Three structural properties keep this model insensitive to meaningless input changes while still responsive to real ones:
Quality is a time integral of bounded, smooth rates over 240 integration steps, so high-frequency input noise averages out and only sustained deviations accumulate.
The nominal recipe sits at stationary points of the response: pH is held at its cardinal optimum, and the production-phase temperature hold is the interior optimum of the hold-temperature response. Instrument-scale deviations around a stationary point are second order.
Sustained multi-degree deviations, by contrast, cross real mechanisms (hypothermic growth arrest on the cold side, feed-burning residual growth and hypoxia on the warm side), so they cost percent-level titer, as they should.
BioreactorSimulator.sensitivity_budget() computes the resulting budget
from the live configuration, so the realism claim can be checked rather than
taken on trust. Indicative values for the default configuration: zero-mean
control-loop noise at instrument scale (sd 0.15 degC, 0.02 pH) moves the
final titer by under 0.3% (standard deviation), a sustained 0.1 degC bias
costs about 0.2%, a sustained 0.02 pH bias is invisible (about 0.01%), while
a sustained 1 degC bias costs 7 to 11% and a sustained 2 degC bias about
20%. Around the operating point overheating costs more than the same
excursion undercooling (feed burn plus hypoxia); far from it undercooling
costs more (full growth arrest).
Disturbance channels#
Three independently tunable channels, each with a scale that can be set to
zero (ic_scale, within_batch_scale, noise_scale):
Measured initial conditions: an 11-variable upstream
Zblock generated from three latent factors (seed viability, medium richness, inhibitor level) with three cluster centres, the feed classes A, B and C. Only the three latent factors drive the process, soZalso carries directions that do not matter, as real upstream data do.Within-batch, unmeasured but observable: an Ornstein-Uhlenbeck process on
log phi(t)with a correlation time comparable to the batch length, plus a per-batch feed-rate drift. It is not predictable fromZ, is continuously visible in the oxygen and offgas trajectories, and its present partly predicts its own future, which is exactly why observing the running batch helps.Control-loop and measurement noise: autocorrelated zero-mean deviation of the realised trajectory from its setpoints, plus independent measurement noise on every recorded tag, at instrument scale.
All random draws are made on every call and multiplied by their channel
scale exactly once, so setting a scale to zero removes that channel without
changing the draw sequence of the others: the same seed with a channel
switched off is a true counterfactual for the same batch. The
initial-condition scale acts where upstream data are drawn
(sample_initial_conditions()); a caller-supplied Z block is
measured data and is used at face value.
References
Rosso, L., Lobry, J. R., Bajard, S. and Flandrois, J. P. (1995), “Convenient model to describe the combined effects of temperature and pH on microbial growth”, Applied and Environmental Microbiology, 61 (2), 610-616.
Luedeking, R. and Piret, E. L. (1959), “A kinetic study of the lactic acid fermentation”, Journal of Biochemical and Microbiological Technology and Engineering, 1 (4), 393-412.
- process_improve.simulation.batch.cardinal_temperature(temperature, t_min, t_opt, t_max)[source]#
Cardinal temperature model with inflection (CTMI) of Rosso et al. (1995).
Equal to 1 at
t_opt, exactly 0 at and beyond the cardinal bounds, and smoothly curved in between with an inflection in the suboptimal range.- Parameters:
temperature (float or np.ndarray) – Temperature(s) [degC].
t_min (float) – Cardinal temperatures [degC]: no growth at or below
t_min, maximum growth att_opt, no growth at or abovet_max. The CTMI is well posed only fort_opt >= (t_min + t_max) / 2; below that the denominator has a root strictly inside the cardinal window and the formula is meaningless there, so such triples are rejected.t_opt (float) – Cardinal temperatures [degC]: no growth at or below
t_min, maximum growth att_opt, no growth at or abovet_max. The CTMI is well posed only fort_opt >= (t_min + t_max) / 2; below that the denominator has a root strictly inside the cardinal window and the formula is meaningless there, so such triples are rejected.t_max (float) – Cardinal temperatures [degC]: no growth at or below
t_min, maximum growth att_opt, no growth at or abovet_max. The CTMI is well posed only fort_opt >= (t_min + t_max) / 2; below that the denominator has a root strictly inside the cardinal window and the formula is meaningless there, so such triples are rejected.
- Returns:
The dimensionless growth factor gamma_T in [0, 1], with the same shape as
temperature.- Return type:
np.ndarray
- process_improve.simulation.batch.cardinal_ph(ph, ph_min, ph_opt, ph_max)[source]#
Cardinal pH model (CPM) of Rosso et al. (1995).
Equal to 1 at
ph_optand exactly 0 at and beyond the cardinal bounds.- Parameters:
ph (float or np.ndarray) – pH value(s) [-].
ph_min (float) – Cardinal pH values: no growth at or below
ph_min, maximum growth atph_opt, no growth at or aboveph_max.ph_opt (float) – Cardinal pH values: no growth at or below
ph_min, maximum growth atph_opt, no growth at or aboveph_max.ph_max (float) – Cardinal pH values: no growth at or below
ph_min, maximum growth atph_opt, no growth at or aboveph_max.
- Returns:
The dimensionless growth factor gamma_pH in [0, 1], with the same shape as
ph.- Return type:
np.ndarray
- class process_improve.simulation.batch.BioreactorConfig(mu_opt=0.8, k_s=0.2, yield_xs=0.4, maintenance=0.02, alpha_lp=0.3, beta_lp=0.35, yield_ps=0.9, k_sp=0.1, k_d_starv=0.08, k_s_starv=0.12, temp_min=27.5, temp_opt=36.8, temp_max=41.5, k_d0=0.015, temp_death=39.0, width_death=0.9, temp_q_min=22.0, temp_q_opt=31.5, temp_q_max=40.5, ph_min=6.3, ph_opt=7.1, ph_max=7.9, batch_days=10.0, samples_per_batch=20, steps_per_day=24, feed_rate=0.055, feed_substrate=50.0, volume_initial=1.0, biomass_initial=0.3, substrate_initial=5.0, temp_bounds=(28.0, 39.0), ph_bounds=(6.6, 7.6), shift_start_day=3.0, shift_end_day=4.5, temp_production=29.05, ic_scale=1.0, within_batch_scale=1.0, noise_scale=1.0, ou_tau_days=6.0, ou_sd=0.15, feed_drift_sd=0.06, control_sd_temp=0.15, control_sd_ph=0.02, control_tau_h=6.0, meas_sd_temp=0.05, meas_sd_ph=0.01, meas_sd_do=1.0, meas_sd_co2=0.08, meas_sd_volume=0.005, o2_yield=0.55, o2_maintenance=0.02, our_capacity=1.85, k_d_hyp=0.4, rq=1.0, co2_gain=1.0, co2_inlet_pct=0.04)[source]#
Bases:
objectKinetic, operating and disturbance parameters of the simulated bioreactor.
All parameters have defaults chosen so the nominal batch lands in a physiologically plausible range for a pilot-scale mammalian-cell fed-batch process (peak biomass a few g/L, final titer of order 10 g/L). Units are given per field. The dataclass is frozen; derive variants with
dataclasses.replace().- Parameters:
mu_opt (float) – Maximum specific growth rate at the cardinal optima [1/day].
k_s (float) – Monod half-saturation constant for the substrate [g/L].
yield_xs (float) – Biomass yield on substrate [g biomass / g substrate].
maintenance (float) – Maintenance substrate consumption [g substrate / g biomass / day].
alpha_lp (float) – Luedeking-Piret coefficients: growth-associated product yield [g product / g biomass] and non-growth-associated specific productivity [g product / g biomass / day].
beta_lp (float) – Luedeking-Piret coefficients: growth-associated product yield [g product / g biomass] and non-growth-associated specific productivity [g product / g biomass / day].
yield_ps (float) – Product yield on substrate [g product / g substrate]: production consumes substrate, so a large biomass pile competes with its own productivity for feed.
k_sp (float) – Half-saturation substrate concentration for product formation [g/L]: production stalls when the substrate runs out.
k_d_starv (float) – Additional death rate under full starvation [1/day].
k_s_starv (float) – Substrate concentration at which the starvation death rate reaches half its maximum [g/L].
temp_min (float) – Cardinal temperatures for growth [degC].
temp_opt (float) – Cardinal temperatures for growth [degC].
temp_max (float) – Cardinal temperatures for growth [degC].
k_d0 (float) – Baseline first-order death rate [1/day].
temp_death (float) – Onset temperature [degC] and width [degC] of the exponential rise in the death rate.
width_death (float) – Onset temperature [degC] and width [degC] of the exponential rise in the death rate.
temp_q_min (float) – Cardinal temperatures for the non-growth-associated productivity [degC];
temp_q_optsits belowtemp_opt, which is what makes the biphasic temperature shift a real trade-off.temp_q_opt (float) – Cardinal temperatures for the non-growth-associated productivity [degC];
temp_q_optsits belowtemp_opt, which is what makes the biphasic temperature shift a real trade-off.temp_q_max (float) – Cardinal temperatures for the non-growth-associated productivity [degC];
temp_q_optsits belowtemp_opt, which is what makes the biphasic temperature shift a real trade-off.ph_min (float) – Cardinal pH values, shared by growth and productivity.
ph_opt (float) – Cardinal pH values, shared by growth and productivity.
ph_max (float) – Cardinal pH values, shared by growth and productivity.
batch_days (float) – Batch duration [day].
samples_per_batch (int) – Number of recorded samples (and setpoint intervals) per batch.
steps_per_day (int) – Integration steps per day for the fixed-step RK4 integrator.
feed_rate (float) – Nominal constant feed rate [L/day].
feed_substrate (float) – Substrate concentration in the feed [g/L].
volume_initial (float) – Working volume at inoculation [L].
biomass_initial (float) – Nominal initial biomass and substrate concentrations [g/L]; the measured initial-condition channel perturbs these per batch.
substrate_initial (float) – Nominal initial biomass and substrate concentrations [g/L]; the measured initial-condition channel perturbs these per batch.
temp_bounds (tuple[float, float]) – Recipe-allowed operating window for the setpoints; requested and realised trajectories are validated or clipped against these.
ph_bounds (tuple[float, float]) – Recipe-allowed operating window for the setpoints; requested and realised trajectories are validated or clipped against these.
shift_start_day (float) – Start and end [day] of the nominal biphasic temperature ramp from
temp_optdown totemp_production.shift_end_day (float) – Start and end [day] of the nominal biphasic temperature ramp from
temp_optdown totemp_production.temp_production (float) – The production-phase hold temperature of the nominal recipe [degC]. It sits below the isolated productivity optimum
temp_q_optbecause residual growth at warmer temperatures consumes the feed that production needs; cold enough to arrest growth is what a sensible recipe holds.ic_scale (float) – Scale of the upstream variation put into drawn initial conditions (campaigns that draw their own
Zblock, andsample_initial_conditions()when called through them); 0 collapses drawn batches to the nominal upstream values. A caller-suppliedZblock is measured data and is always used at face value, independent of this scale.within_batch_scale (float) – Scale of the unmeasured within-batch channel; 0 switches it off.
noise_scale (float) – Scale of the control-loop and measurement noise channel; 0 switches it off.
ou_tau_days (float) – Correlation time of the Ornstein-Uhlenbeck disturbance on
log phi(t)[day].ou_sd (float) – Stationary standard deviation of
log phi(t)[-].feed_drift_sd (float) – Per-batch fractional standard deviation of the realised feed rate [-].
control_sd_temp (float) – Stationary standard deviation of the realised-minus-setpoint control error for temperature [degC] and pH [-].
control_sd_ph (float) – Stationary standard deviation of the realised-minus-setpoint control error for temperature [degC] and pH [-].
control_tau_h (float) – Correlation time of the control error [hour].
meas_sd_temp (float) – Measurement noise standard deviations on the recorded tags [degC, -, % saturation, % offgas, L].
meas_sd_ph (float) – Measurement noise standard deviations on the recorded tags [degC, -, % saturation, % offgas, L].
meas_sd_do (float) – Measurement noise standard deviations on the recorded tags [degC, -, % saturation, % offgas, L].
meas_sd_co2 (float) – Measurement noise standard deviations on the recorded tags [degC, -, % saturation, % offgas, L].
meas_sd_volume (float) – Measurement noise standard deviations on the recorded tags [degC, -, % saturation, % offgas, L].
o2_yield (float) – Oxygen demand per unit growth [g O2 / g biomass].
o2_maintenance (float) – Maintenance oxygen uptake [g O2 / g biomass / day].
our_capacity (float) – Maximum oxygen transfer the sparger and agitation can supply [g O2 / L / day]. This is the binding constraint of the process: it caps the biomass pile the reactor can sustain, and the cap is temperature-dependent because warmer cells demand more oxygen each.
k_d_hyp (float) – Additional death rate under full oxygen limitation [1/day]: overshooting the sustainable biomass pile is an irreversible loss, which is what gives the optimal schedule curvature on both sides.
rq (float) – Respiratory quotient, the CO2 evolved per O2 consumed [g/g].
co2_gain (float) – Offgas CO2 percentage per unit CO2 evolution rate [% / (g/L/day)].
co2_inlet_pct (float) – CO2 percentage of the inlet gas [%].
- process_improve.simulation.batch.sample_initial_conditions(n_batches, *, proportions=None, ic_scale=1.0, random_state=None)[source]#
Draw upstream (initial-condition) data for a campaign of batches.
Each batch belongs to one of three feed-disturbance classes, A, B or C, with a cluster centre in the three-dimensional latent space (seed viability, medium richness, inhibitor level). The observed
Zblock has 11 variables generated from those latent factors through a fixed loading matrix plus residual noise, so a PCA ofZrecovers about three meaningful components and shows the three classes as clusters.- Parameters:
n_batches (int) – Number of batches to draw.
proportions (dict[str, float], optional) – Expected class proportions keyed by
"A","B","C". They must be non-negative and sum to a positive number (they are normalised). Default{"A": 0.40, "B": 0.35, "C": 0.25}.ic_scale (float, default=1.0) – Scale of the initial-condition variation. 0 collapses every batch to the nominal upstream values while keeping the class labels.
random_state (int, np.random.Generator, or None) – Seed or generator; see
process_improve._random.check_random_state.
- Returns:
result – With keys
z(DataFrame,n_batchesrows by 11 upstream variables, integer batch ids as index),classes(Series of “A” / “B” / “C” labels, same index) andlatent(DataFrame of the three latent factor values, same index).- Return type:
- class process_improve.simulation.batch.BioreactorSimulator(config=None)[source]#
Bases:
objectA deterministic fed-batch bioreactor with tunable disturbance channels.
See the module docstring for the model, its citations, and the design constraints. Given the same configuration, inputs and
random_state, every method reproduces its results exactly.- Parameters:
config (BioreactorConfig, optional) – The full parameter set; defaults to
BioreactorConfig().
Examples
>>> from process_improve.simulation import BioreactorSimulator >>> sim = BioreactorSimulator() >>> golden = sim.golden_trajectory() >>> campaign = sim.simulate_campaign(50, policy="replay", trajectory=golden.trajectory, random_state=42) >>> float(campaign.quality["titer"].std()) > 0.0 True
- nominal_trajectory()[source]#
Return the nominal (recipe) setpoint schedule: biphasic temperature, pH held.
Temperature holds the growth optimum until
shift_start_day, ramps linearly to the production holdtemp_productionbyshift_end_day, and holds it for the rest of the batch. pH is held at its cardinal optimum throughout, matching the industrial practice of holding pH and shifting temperature.- Returns:
samples_per_batchrows indexed by setpoint interval start time [day], columns["pH", "temperature"]. Each row is the setpoint held over the following interval (zero-order hold).- Return type:
pd.DataFrame
- simulate_batch(initial_conditions=None, trajectory=None, *, random_state=None)[source]#
Simulate one batch under given initial conditions and setpoints.
- Parameters:
initial_conditions (pd.Series, optional) – One row of the upstream
Zblock (index: the 11 upstream variable names).Noneruns the nominal batch (all upstream variables at their means).trajectory (pd.DataFrame, optional) – Setpoint schedule with
samples_per_batchrows and columns["pH", "temperature"]; each row is held over its interval (zero-order hold).Noneusesnominal_trajectory().random_state (int, np.random.Generator, or None) – Seed or generator for the disturbance and noise draws.
- Returns:
result – With keys:
tags: DataFrame,samples_per_batchrows indexed by sample time [day], columns["pH", "temperature", "dissolved_oxygen", "offgas_co2", "volume"]: what the historian records, including measurement noise. Each row reads at the end of its interval: states at that instant, inputs as delivered over the interval that ends there.titer: float, the final product concentration [g/L].states: DataFrame on the integration grid (indexed by day) with columns["biomass", "substrate", "titer", "volume", "phi", "temperature", "pH"]: the noise-free god view, including the unmeasured disturbancephi. The input columns (phi,temperature,pH) hold the value in force during the step starting at each grid instant.realised_trajectory: DataFrame liketagsbut only["pH", "temperature"]and without measurement noise: what the control loops delivered over the interval ending at each sample time.initial_conditions: Series, theZrow used, taken at face value (seeic_scaleinBioreactorConfig).
- Return type:
- optimal_trajectory(initial_conditions=None, *, n_knots=4, n_starts=5, random_state=0)[source]#
Find the true optimal setpoint schedule for a batch’s initial conditions.
Maximises the deterministic (disturbance-free) final titer over pH and temperature schedules parameterised by
n_knotsvalues each, linearly interpolated across the batch and held per interval. Because the optimiser queries the simulator’s own model, the result is the true optimum for these initial conditions: the ceiling any data-driven scheme can be scored against.- Parameters:
initial_conditions (pd.Series, optional) – One upstream
Zrow;Nonefor the nominal batch.n_knots (int, default=4) – Number of knots per manipulated variable.
n_starts (int, default=5) – Multi-start count: the nominal trajectory plus
n_starts - 1random starts inside the operating bounds.random_state (int, np.random.Generator, or None, default=0) – Seed for the random starts; the default makes the search reproducible without an argument.
- Returns:
result – With keys
trajectory(DataFrame in the same layout asnominal_trajectory()),titer(float, the deterministic titer of that trajectory) andoptimizer_success(bool).- Return type:
- golden_trajectory(*, n_knots=4, n_starts=5, random_state=0)[source]#
Find the golden batch: the optimal schedule for the nominal initial conditions.
This is what golden-batch practice enshrines as the recipe. It is the true optimum only for the conditions under which it was found; the whole point of the baseline is what happens when it is replayed under other conditions. Parameters and return value match
optimal_trajectory()withinitial_conditions=None.
- simulate_campaign(n_batches, *, policy='replay', trajectory=None, initial_conditions=None, mv_variation=0.0, n_knots=4, n_starts=5, random_state=None)[source]#
Simulate a campaign of batches under a named operating policy.
- Parameters:
n_batches (int) – Number of batches in the campaign.
policy ({"replay", "historical", "adapted"}, default="replay") –
"replay": every batch is given the same setpoint schedule, the golden-batch practice."historical": the same schedule plus deliberate per-batch setpoint variation of sizemv_variation(see below). A perfectly consistent history contains no information about how the controls affect quality; this policy produces a history that does."adapted": each batch runs the true optimal schedule for its own initial conditions, computed from the simulator’s model viaoptimal_trajectory(). This is the ceiling a perfect feedforward scheme could reach, not an implementable policy.
trajectory (pd.DataFrame, optional) – The schedule used by
"replay"and"historical"; defaults tonominal_trajectory(). Ignored by"adapted".initial_conditions (pd.DataFrame, optional) – The upstream
Zblock, one row per batch (the 11 upstream variables as columns).Nonedraws it withsample_initial_conditions()using the configuration’sic_scale.mv_variation (float, default=0.0) – Size of the deliberate variation for
"historical": each batch draws a random constant offset and a random start-to-end ramp for temperature (standard deviationmv_variationdegC each) and for pH (standard deviation0.1 * mv_variationeach), clipped to the operating bounds.n_knots (int) – Passed to
optimal_trajectory()for the"adapted"policy, which runs the optimiser once per batch; lower values trade optimality for speed. Ignored by the other policies.n_starts (int) – Passed to
optimal_trajectory()for the"adapted"policy, which runs the optimiser once per batch; lower values trade optimality for speed. Ignored by the other policies.random_state (int, np.random.Generator, or None) – Seed or generator; child seeds are spawned per batch, so a campaign is reproducible end to end.
- Returns:
result – With keys:
batches:dict[int, pd.DataFrame], the recorded tags per batch in the package’s standard batch-dictionary format.quality: DataFrame indexed by batch id with the single columntiter[g/L].initial_conditions: DataFrame, theZblock used.classes: Series of feed-class labels (“A”/”B”/”C”), or"?"wheninitial_conditionswas supplied by the caller.trajectories:dict[int, pd.DataFrame], the requested setpoint schedule per batch.
- Return type:
- sensitivity_budget(*, n_noise_replicates=100, random_state=0)[source]#
How much the final titer moves under standard input perturbations.
This is the realism check: a credible process model must not respond visibly to input changes smaller than an instrument can resolve, and must respond clearly to sustained multi-degree deviations. The rows cover zero-mean control-loop noise at instrument scale, sustained setpoint biases of increasing size, and a single-sample excursion. All effects are measured on the deterministic model (disturbance channels off) except the control-noise row, which uses the configured control-error model.
- Parameters:
- Returns:
One row per perturbation with columns
perturbation(index),titer_g_Landeffect_pct(percentage change of the final titer against the unperturbed nominal batch; for the noise row, the standard deviation across replicates).- Return type:
pd.DataFrame
- process_improve.simulation.batch.variance_decomposition(simulator, n_batches=200, *, trajectory=None, random_state=None)[source]#
Split the replay-policy titer variance into its three sources.
Runs four replay campaigns with the same size and schedule: all channels on (the total), then each channel alone. The initial-condition bucket is what pre-batch (feedforward) trajectory adaptation could remove; the within-batch bucket is what only mid-course (feedback) correction can reach; the noise bucket is the floor. Because the model is nonlinear the three buckets do not sum exactly to the total; the difference is reported as the interaction residual rather than hidden.
- Parameters:
simulator (BioreactorSimulator) – The simulator whose configuration (including channel scales) defines the “all channels on” case.
n_batches (int, default=200) – Batches per campaign.
trajectory (pd.DataFrame, optional) – The replayed schedule; defaults to the simulator’s nominal.
random_state (int, np.random.Generator, or None) – Seed or generator; each campaign draws its own child seed.
- Returns:
Rows
["measured initial conditions", "within-batch disturbance", "control and measurement noise", "interaction residual", "total"]with columnsvariance[g^2/L^2],sd[g/L],cv_pct(sd as a percentage of the all-channels mean titer) andpct_of_total(share of the total variance; the residual’s share can be negative).- Return type:
pd.DataFrame