KAHIBARO
Discord Login Register

16.4 Detector Resolution Simulation

Gaussian smearing

In many real detectors the measured value of a quantity, for example an energy or a position, is not exactly equal to the true value. Instead, each measurement fluctuates around the true value with some spread. A very common and useful approximation is that these fluctuations follow a Gaussian distribution. In ROOT you can simulate this effect by adding Gaussian noise to your ideal or simulated values. This procedure is usually called Gaussian smearing.

Suppose you have a true value $x_{\text{true}}$. A smeared, detector-like value $x_{\text{meas}}$ is modeled as
$$x_{\text{meas}} = x_{\text{true}} + \delta,$$
where $\delta$ is a random number drawn from a Gaussian with mean $0$ and standard deviation $\sigma$. The parameter $\sigma$ represents the detector resolution. A smaller $\sigma$ means a better, more precise detector.

In ROOT, the class TRandom or TRandom3 provides Gaussian random numbers. The method Gaus(mean, sigma) returns one number sampled from a Gaussian with the given mean and sigma. To smear a value you can write, for example, inside a macro or event loop:

cpp
TRandom3 rng(1234); // fixed seed for reproducibility
double x_true  = 5.0;       // true value, for example in GeV
double sigma   = 0.2;       // detector resolution
double x_meas  = rng.Gaus(x_true, sigma); // smeared measurement

Here, the call rng.Gaus(x_true, sigma) directly returns a value distributed as a Gaussian centered at x_true with width sigma. This is equivalent to generating delta = rng.Gaus(0, sigma) and adding it to x_true.

You can apply this smearing to many events by looping and filling a histogram that represents what the detector would see:

cpp
TRandom3 rng(42);
TH1F hTrue ("hTrue",  "True values;X;Entries",   100, 0, 10);
TH1F hMeas ("hMeas",  "Measured values;X;Entries", 100, 0, 10);
for (int i = 0; i < 100000; ++i) {
    double x_true = rng.Uniform(2.0, 8.0);          // some ideal distribution
    double x_meas = rng.Gaus(x_true, 0.3);          // apply Gaussian smearing
    hTrue.Fill(x_true);
    hMeas.Fill(x_meas);
}
hTrue.SetLineColor(kBlue);
hMeas.SetLineColor(kRed);
TCanvas *c = new TCanvas("c", "Detector resolution", 800, 600);
hTrue.Draw();
hMeas.Draw("SAME");

In this example you see how the smeared histogram is broader and the sharp features of the true distribution are washed out. This mimics the loss of resolution introduced by the detector.

Gaussian smearing is also frequently used to simulate detector resolution on energies that scale with the value itself. In that case the resolution is often written as a relative resolution, for example $\sigma = r \cdot E$ where $r$ is a constant fraction and $E$ is the true energy. In ROOT you can implement that as:

cpp
double E_true  = rng.Uniform(0.5, 5.0);  // GeV
double relRes  = 0.1;                   // 10% resolution
double sigmaE  = relRes * E_true;       // absolute sigma
double E_meas  = rng.Gaus(E_true, sigmaE);

This gives worse resolution at higher energies in absolute units, which is typical of some detector systems.

Important rule: To simulate detector resolution, replace each ideal value $x_{\text{true}}$ by a smeared value $x_{\text{meas}} = x_{\text{true}} + \delta$, where $\delta$ is drawn from a Gaussian with mean $0$ and standard deviation equal to the detector resolution $\sigma$.

Measurement uncertainty

Detector resolution and measurement uncertainty describe the spread of repeated measurements of the same true quantity. In a simulation this spread is exactly what you control with the Gaussian width $\sigma$. In real data analysis you usually do not know the true value event by event, but you can often estimate the resolution from calibration measurements or from known spectral features, for example the width of a well known peak.

In ROOT based simulations there are three closely related uses of measurement uncertainty.

First, you can model how the detector broadens an ideal theoretical distribution. This is what you achieve with Gaussian smearing applied to your Monte Carlo truth. The resulting smeared distribution tells you what you would expect to see in a real experiment with that resolution. Later you can compare this to measured data.

Second, you can assign an uncertainty to each simulated measurement. For a value $x_{\text{meas}}$ that comes from smearing with a Gaussian of width $\sigma$, it is natural to quote the measurement as
$$x_{\text{meas}} \pm \sigma,$$
under the Gaussian assumption. If you store such points in a TGraphErrors, you can visualize both the central value and the uncertainty.

A minimal example to create a graph with uncertainties from smeared measurements is:

cpp
const int N = 50;
TRandom3 rng(7);
double x[N], y_true[N], y_meas[N], y_err[N];
for (int i = 0; i < N; ++i) {
    x[i]      = 0.1 * i;
    y_true[i] = TMath::Sin(x[i]);
    double sigma = 0.05;                 // measurement uncertainty
    y_meas[i] = rng.Gaus(y_true[i], sigma);
    y_err[i]  = sigma;                   // same uncertainty for all points
}
TGraphErrors *g = new TGraphErrors(N, x, y_meas, nullptr, y_err);
g->SetTitle("Measurement with uncertainties;X;Y");
g->SetMarkerStyle(20);
TCanvas *c = new TCanvas("c_unc", "Measurement uncertainty", 800, 600);
g->Draw("AP");

Here, each point is drawn with a vertical error bar of size sigma. The error bars represent the one standard deviation range of the measurement uncertainty for each point.

Third, measurement uncertainty determines the statistical errors of histogram bins when you are working with smeared data. When you fill histograms with smeared values, each entry still contributes one count, so the bin counting uncertainty is usually $\sqrt{N}$ for $N$ entries in a bin. However, the smearing spreads entries across neighboring bins and broadens peaks. This effect must be included in any interpretation of the histogram shape and in any fit that extracts physical parameters. In practice you compare your smeared simulation with data and adjust parameters until they match within uncertainties.

Sometimes detector resolution is not constant. For example, it may depend on energy as
$$\sigma(E) = \sqrt{a^2 E + b^2},$$
where $a$ and $b$ are constants determined from calibration. You can implement such energy dependent uncertainties directly in ROOT:

cpp
double a = 0.1;   // stochastic term
double b = 0.02;  // constant term
double E_true = rng.Uniform(0.2, 5.0);
double sigmaE = TMath::Sqrt(a*a * E_true + b*b);
double E_meas = rng.Gaus(E_true, sigmaE);

In this way each event carries its own individual resolution, and your simulation captures more realistic behavior.

Key statement: In a Gaussian model of detector resolution, the standard deviation $\sigma$ of the smearing is the one standard deviation measurement uncertainty. Quoting a value as $x_{\text{meas}} \pm \sigma$ means that, under the Gaussian assumption, about 68 percent of repeated measurements would fall inside this interval.

By consistently adding Gaussian smearing with a chosen $\sigma$ and, when needed, storing or plotting these $\sigma$ values as uncertainties, you can emulate realistic detector performance in your ROOT simulations and prepare analyses that correctly account for measurement uncertainty.

Views: 10

Comments

Please login to add a comment.

Don't have an account? Register now!