Skip to content

Uncertainty

A fit gives one estimate. Two functions say how much it would vary.

ps.ensemble ps.bootstrap
For synthetic studies, where you have the clean signal measured data
Repeats the fit on the clean data plus fresh noise, one draw per run the fitted signal plus the residuals, resampled
Answers how the method performs at this noise level how sure this particular estimate is
Starts each fit from the original starting values the original estimate

Both return an Ensemble: the estimate of every run (thetas), their mean, standard deviation (std) and coefficient of variation (cov, in percent), percentile intervals (interval(0.95)), and a summary().

Ensemble

The procedure of the SNAPE papers' tables: fit noise-free data once, then refit noisy copies.

import numpy as np
import pysnape as ps

t = np.linspace(0.0, 10.0, 301)
clean = ps.Data(fields={"x": np.exp(-0.1 * t) * np.cos(2.0 * t)}, coords={"t": t})
eq = "x_tt + a*x_t + b*x = 0"
base = ps.fit(eq, clean, unknowns={"a": 1.0, "b": 1.0}, multistart=False)

ens = ps.ensemble(base, n=20, noise=5, jobs=2)  # draws with seeds 0..19
print(ens.summary(truth={"a": 0.2, "b": 4.01}))

Draw i uses seed seed + i, so an ensemble is repeatable. ensemble warns if the fit's data does not look noise-free, since it would add noise on top of noise.

Bootstrap

For measurements, where no clean signal exists. It keeps the fitted signal, resamples the residuals at the measured points with replacement, and refits:

noisy = clean.add_noise(percent=5, seed=7)
result = ps.fit(eq, noisy, unknowns={"a": 1.0, "b": 1.0}, multistart=False)
boot = ps.bootstrap(result, n=50, jobs=2)
print(boot.interval(0.95))

The residuals are treated as independent. If your noise is correlated in time or space, the spread comes out too small.

The bootstrap can understate the spread even for independent noise, because the residuals of a fitted curve are a little smaller than the noise itself; in one of our tests its 95 % interval missed the true value. For a synthetic check, compare it with ensemble, and treat its intervals as a lower bound on the uncertainty.

Parallel runs

jobs= runs the fits in parallel processes. Set OMP_NUM_THREADS=1 in the environment first, so that the sparse solvers in each process do not compete for cores.