---
title: "Calibration and Quantification"
output: rmarkdown::html_vignette
vignette: >
%\VignetteIndexEntry{Calibration and Quantification}
%\VignetteEngine{knitr::rmarkdown}
%\VignetteEncoding{UTF-8}
resource_files:
- figures/logo.svg
- figures/logo-dark.svg
---
```{r setup, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.width = 7,
fig.height = 4.5,
message = FALSE,
warning = FALSE
)
```
```{r}
library(libscanR)
```
## From peak area to concentration
A LIBS calibration converts measured peak area (or intensity ratio) to
elemental concentration using a set of matrix-matched standards.
### Synthetic calibration dataset
```{r data}
cal_ds <- ls_example_data("calibration")
cal_ds
conc <- cal_ds$sample_info$concentration
unique(conc)
```
### Univariate calibration
```{r univariate}
cal <- ls_calibrate(cal_ds, element = "Ca", line_nm = 393.37,
concentrations = conc, method = "univariate",
verbose = FALSE)
cal
```
### Visualize
```{r plot, fig.alt="Concentration versus integrated response near 393.37 nm for 27 fictional teaching standards, with fitted line, 95 percent prediction band and estimated LOD and LOQ levels."}
ls_plot_calibration(cal)
```
### Residual diagnostics
```{r residuals, fig.alt="Residual concentration versus fitted concentration for the fictional Ca-labelled calibration, with a horizontal zero-residual reference line."}
ls_plot_residuals(cal)
```
### Internal standard calibration
An internal standard needs a measured, positive reference response in every
spectrum. The broad noisy display dataset above does not guarantee this. The
following separate numerical example uses two resolved Gaussian peaks, a constant
reference and a small deterministic background perturbation. It demonstrates the
ratio workflow, not a physically validated plasma or correction for matrix effects.
```{r internal}
wl_is <- c(seq(392, 395, by = 0.02), seq(587, 591, by = 0.02))
spectra_is <- lapply(seq_along(conc), function(i) {
response <- 5 + 0.1 * conc[i] * exp(-0.5 * ((wl_is - 393.37) / 0.12)^2) +
20 * exp(-0.5 * ((wl_is - 589.00) / 0.12)^2) +
0.1 * sin(3 * wl_is + i)
ls_spectrum(wl_is, response,
metadata = list(sample_id = paste0("ratio_standard_", i)))
})
is_ds <- ls_dataset(spectra_is)
cal_is <- ls_calibrate(is_ds, "Ca", 393.37, concentrations = conc,
method = "internal_std",
internal_std_nm = 589.00,
verbose = FALSE)
cal_is
ls_quantify(cal_is, is_ds)
```
### PLS calibration
```{r pls, eval = requireNamespace("pls", quietly = TRUE)}
cal_pls <- ls_calibrate(cal_ds, "Ca", 393.37, concentrations = conc,
method = "pls", n_components = 5,
verbose = FALSE)
cal_pls
```
## Quantifying unknowns
The calibration retains its exact wavelength axis, ordered preprocessing,
integration window, and internal-standard line or PLS feature columns. Apply the
same processing to new measurements. `ls_quantify()` reuses the saved recipe and
rejects a different supplied window, changed channel labels or missing legacy
contracts. Refit models created before the contract was introduced.
```{r quantify}
ls_quantify(cal, cal_ds)
```
## LOD and LOQ
For univariate and internal-standard fits, the estimates are `3 * sigma / abs(slope)`
and `10 * sigma / abs(slope)`, where the slope and residual standard deviation are
from an auxiliary response-on-concentration regression. These estimates have the
calibration concentration unit and remain invariant under instrument gain. The
inverse concentration-on-response model still supplies predictions.
The package retains its stated three-sigma convention. The
[IUPAC definition](https://goldbook.iupac.org/terms/view/L03540) makes the factor
depend on the chosen certainty, while
[ICH Q2(R2), section 3.2.3.3](https://database.ich.org/sites/default/files/ICH_Q2%28R2%29_Guideline_2023_1130_ErrorCorrection_2025.pdf)
uses 3.3 for the response-standard-deviation method and requires suitable
verification near the proposed limits. These functions do not establish
compliance with a validation protocol.
A supplied blank needs at least two replicate shots with the fitted wavelength
and processing contract. Its noise is the variation of the integrated response
(or internal-standard ratio) across shots, not variation across channels. Confirm
performance independently near any proposed instrument limit. PLS returns `NA`
for LOD/LOQ and reports training RMSE separately; missing limits produce missing
below-limit flags rather than a claim that a result exceeds a known limit.
```{r lod}
ls_lod(cal)
ls_loq(cal)
```
## Relative elemental amounts under a two-stage LTE model
This calculation requires independently justified electron density, first ionization
energies, partition functions, resolved transitions and instrument-response factors.
The line wavelengths must use the same air or vacuum convention as the measured
axis. A good fit does not establish LTE, optical thinness or stoichiometric ablation.
The example below uses fictional X/Y transitions and intensities calculated by an
independent high-precision forward model. The ordinary spectrum simulator is a
Gaussian display model and does not simulate Boltzmann or Saha populations.
```{r cf}
source(system.file("examples", "saha-boltzmann-synthetic.R", package = "libscanR"))
inputs <- saha_synthetic_example()
result <- do.call(ls_saha_boltzmann, inputs)
result
attr(result, "line_diagnostics")
```
The expected temperature is 10000 K and the relative elemental number fractions
are X = 0.7 and Y = 0.3. Fractions are normalized over the supplied elements only;
they are not mass fractions or absolute concentrations. The model includes neutral
and singly ionized stages, excluding molecules and higher charge states. No real
instrument or tissue data were used to qualify this example.
For experimental work, supply verified atomic records and retain their references.
`ls_element_db()` reads user-supplied atomic reference fields, but missing rates or vacuum
wavelengths must be resolved from primary sources before those rows can be used.
Partition functions and response factors are not provided by the line database.
See the [NIST line and Saha/LTE documentation](https://physics.nist.gov/PhysRefData/ASD/Html/lineshelp.html)
for the conventions. The previous incomplete implementation omitted required
physics; its outputs cannot serve as quantitative references and must be recalculated.