10  Time to Steady State

10.1 What is time to steady state?

Time to steady state (TSS) is the dosing occasion (or clock time) at which pre-dose trough concentrations are no longer meaningfully rising. PKNCA provides two NCA-based methods for estimating TSS from trough concentration data collected across multiple dose occasions. Once at steady state, compute interval parameters with Multiple-Dose and Steady-State; to predict the steady-state profile from single-dose data, see Superposition.

Both methods work on trough concentrations (Ctrough = pre-dose concentration; the end of one dosing interval is the pre-dose sample of the next) collected at successive dose numbers, not full PK profiles. See also the package vignette Noncompartmental evaluation of time to steady-state.


10.2 Simulated dataset

We simulate trough concentrations for 6 subjects across 10 dose occasions. Concentrations approach an individual steady-state plateau following a monoexponential rise.

set.seed(42)
n_subjects <- 6
n_doses    <- 10

d_tss <- data.frame(
  Subject     = rep(1:n_subjects, each = n_doses),
  dose_number = rep(1:n_doses, n_subjects),
  ke          = rep(0.1 * exp(rnorm(n_subjects, 0, 0.2)), each = n_doses),
  Css         = rep(10  * exp(rnorm(n_subjects, 0, 0.3)), each = n_doses)
)
d_tss$ctrough <- d_tss$Css * (1 - exp(-d_tss$ke * d_tss$dose_number * 24)) +
                 rnorm(nrow(d_tss), 0, 0.1)

ggplot(d_tss, aes(x = dose_number, y = ctrough, group = Subject, colour = factor(Subject))) +
  geom_line() + geom_point() +
  labs(title = "Simulated trough concentrations across dose occasions",
       x = "Dose number", y = "Ctrough (mg/L)", colour = "Subject") +
  theme_minimal()


10.3 Method 1: Monoexponential (pk.tss.monoexponential)

Fits a monoexponential approach-to-plateau model:

\[C_{\text{trough}}(n) = C_{ss} \cdot \left(1 - e^{-k_{\text{tss}} \cdot n}\right)\]

Reports TSS as the dose occasion at which the predicted concentration reaches a specified fraction of Css (default: 90% = tss.fraction = 0.9).

Returns population, population-individual (popind), individual, and pooled single-model estimates (single fits one model to all data, ignoring subject differences).

tss_mono <- pk.tss.monoexponential(
  conc        = d_tss$ctrough,
  time        = d_tss$dose_number,
  subject     = d_tss$Subject,
  time.dosing = 1:n_doses
)
Warning in nlme.formula(conc ~ ctrough.ss * (1 - exp(tss.constant * time/tss)),
: Iteration 1, LME step: nlminb() did not converge (code = 1). Do increase
'msMaxIter'!
Warning in pk.tss.monoexponential.population(modeldata, output =
intersect(c("population", : tss.monoexponential.popind was requested, but the
best model did not include a random effect for tss.  Set to NA.
tss_mono
  subject tss.monoexponential.population tss.monoexponential.popind
1       1                      0.8797774                         NA
2       2                      0.8797774                         NA
3       3                      0.8797774                         NA
4       4                      0.8797774                         NA
5       5                      0.8797774                         NA
6       6                      0.8797774                         NA
  tss.monoexponential.individual tss.monoexponential.single
1                      0.7536625                  0.8806135
2                      1.0731366                  0.8806135
3                      0.8498045                  0.8806135
4                      0.8060571                  0.8806135
5                      0.8277943                  0.8806135
6                      0.9719632                  0.8806135

Interpreting the output columns:

Column Meaning
tss.monoexponential.population TSS from population-level fit (one value shared across subjects)
tss.monoexponential.popind TSS from mixed model with subject-level random effect for TSS (NA if not supported by data)
tss.monoexponential.individual TSS from individual-level fits
tss.monoexponential.single TSS ignoring between-subject variability

10.3.1 Changing the fraction threshold

A stricter 95% definition of steady state gives a later TSS:

# 95% of Css
pk.tss.monoexponential(
  conc        = d_tss$ctrough,
  time        = d_tss$dose_number,
  subject     = d_tss$Subject,
  time.dosing = 1:n_doses,
  tss.fraction = 0.95
)
Warning in nlme.formula(conc ~ ctrough.ss * (1 - exp(tss.constant * time/tss)),
: Iteration 1, LME step: nlminb() did not converge (code = 1). Do increase
'msMaxIter'!
Warning in nlme.formula(conc ~ ctrough.ss * (1 - exp(tss.constant * time/tss)),
: Singular precision matrix in level -1, block 1
Warning in pk.tss.monoexponential.population(modeldata, output =
intersect(c("population", : tss.monoexponential.popind was requested, but the
best model did not include a random effect for tss.  Set to NA.
  subject tss.monoexponential.population tss.monoexponential.popind
1       1                       1.144617                         NA
2       2                       1.144617                         NA
3       3                       1.144617                         NA
4       4                       1.144617                         NA
5       5                       1.144617                         NA
6       6                       1.144617                         NA
  tss.monoexponential.individual tss.monoexponential.single
1                      0.9805283                   1.145705
2                      1.3961661                   1.145705
3                      1.1056088                   1.145705
4                      1.0486509                   1.145705
5                      1.0769848                   1.145705
6                      1.2645547                   1.145705

10.4 Method 2: Stepwise linear (pk.tss.stepwise.linear)

A non-parametric approach: iteratively tests whether concentrations are still increasing linearly from dose occasion \(k\) onward. TSS is the earliest dose occasion at which the upward trend is no longer statistically significant.

This method is more robust when the rise to steady state is irregular or non-monoexponential.

tss_linear <- pk.tss.stepwise.linear(
  conc        = d_tss$ctrough,
  time        = d_tss$dose_number,
  subject     = d_tss$Subject,
  time.dosing = 1:n_doses
)

tss_linear
  tss.stepwise.linear
1                   2

The result is a data frame with a tss.stepwise.linear column containing the first dose occasion number where concentrations are deemed flat (or NA if steady state cannot be determined from the data).


10.5 Running both methods (pk.tss)

pk.tss() runs both methods and returns results side by side:

tss_combined <- pk.tss(
  conc        = d_tss$ctrough,
  time        = d_tss$dose_number,
  subject     = d_tss$Subject,
  time.dosing = 1:n_doses
)
Warning in nlme.formula(conc ~ ctrough.ss * (1 - exp(tss.constant * time/tss)),
: Iteration 1, LME step: nlminb() did not converge (code = 1). Do increase
'msMaxIter'!
Warning in pk.tss.monoexponential.population(modeldata, output =
intersect(c("population", : tss.monoexponential.popind was requested, but the
best model did not include a random effect for tss.  Set to NA.
tss_combined
  subject tss.monoexponential.population tss.monoexponential.popind
1       1                      0.8797774                         NA
2       2                      0.8797774                         NA
3       3                      0.8797774                         NA
4       4                      0.8797774                         NA
5       5                      0.8797774                         NA
6       6                      0.8797774                         NA
  tss.monoexponential.individual tss.monoexponential.single tss.stepwise.linear
1                      0.7536625                  0.8806135                   2
2                      1.0731366                  0.8806135                   2
3                      0.8498045                  0.8806135                   2
4                      0.8060571                  0.8806135                   2
5                      0.8277943                  0.8806135                   2
6                      0.9719632                  0.8806135                   2

10.6 Key arguments

Argument Default Applies to Meaning
conc both Trough concentrations (one per dose occasion per subject)
time both Dose occasion numbers or actual clock times
subject both Subject identifiers
time.dosing both Every dosing time; concentrations at these times are treated as the trough observations the models fit
type c("monoexponential", "stepwise.linear") pk.tss wrapper Which method(s) to run — both by default
tss.fraction 0.9 monoexponential Fraction of Css that defines “at steady state”
output c("population","popind","individual","single") monoexponential Which output types to return
verbose FALSE both Print model fitting details

Note: TSS estimation requires multiple dose occasions with consistent trough sampling. It is not applicable to single-dose studies or studies where trough collection was inconsistent.