Skip to content

sdrummond-eng/UncertCalc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

UncertCalc

A small bash tool for computing GUM-style measurement uncertainty budgets for dimensional gauges, driven by plain-text .conf files. All arithmetic goes through bc(1), so there are no floating-point surprises at the precisions typical of gauge calibration (single-digit micro-inches).

What it does

Given a config file listing a measurand and a set of independent uncertainty contributors (each with a stated value, a probability distribution, and a divisor), UncertCalc:

  1. Converts each contributor's stated value to a standard uncertainty u_i = value / divisor.
  2. Combines them by root-sum-square: u_c = sqrt(Σ u_i²).
  3. Looks up (or accepts) a coverage factor k and reports the expanded uncertainty U = k · u_c.
  4. Prints a fixed-column budget table with per-contributor u_i and percent contribution, flagging the dominant component.

Methodology follows the GUM (JCGM 100:2008): RSS combination of independent standard uncertainties, with the large-DoF normal approximation for the coverage factor (90 % → 1.645, 95 % → 2.000, 99 % → 2.576). Welch–Satterthwaite and Type-A/B effective DoF tracking are not implemented; supply a literal k to override the preset if your situation calls for it.

Requirements

  • bash 4 or newer (uses [[ ... ]], regex matching, indexed arrays)
  • bc with the -l math library (provides sqrt, l(), etc.)

Both are present in every mainstream Linux/macOS install.

Installation

git clone <repo>
cd UncertCalc
chmod +x uncertcalc.sh

That's the whole install. Run it as ./uncertcalc.sh <config> or symlink it into your $PATH.

Usage

./uncertcalc.sh <config.conf> [options]

Flag reference

Flag Argument Effect
-k 90 | 95 | 99 | <decimal> Coverage selector. 90/95/99 map to GUM presets; a decimal passes through as a literal k. Overrides coverage = in the config.
-r <result> Measured result for the guard-banded decision rule. Must be paired with -t. Requires nominal in the config. See Decision rule.
-t <tolerance> Symmetric tolerance half-width (so the spec is nominal ± tolerance) for the decision rule. Must be paired with -r and strictly positive.
--no-color Suppress ANSI color codes on stdout, including the verdict color in the decision block. Implied when writing to a file with -o.
--sigfigs <N> Significant figures used to round u_c, U, and every value in the decision block for display (default 4).
-o <path> Write the budget (and decision block, if any) to <path> instead of stdout. Always plain text (no ANSI).
--force With -o, overwrite an existing file without prompting. Without --force, an existing target triggers a [y/N] prompt and a N exits 0 without writing.
-h, --help Print usage and exit 0.

Config grammar

Comments start with #. The top of the file holds the header fields:

measurand = Thread Plug Gauge Pitch Diameter
unit      = in            # in | mm
nominal   = 0.4675        # optional; required when using the -r/-t decision rule
coverage  = 95%           # 90% | 95% | 99% | <decimal k>; optional, overridden by -k

Unknown header keys produce a stderr warning but do not abort parsing, so a config authored against a newer schema still loads against an older parser. Unknown contributor keys remain a hard error.

Each contributor is an [section] with five fields:

[reference_standard]
name         = Reference Standard
type         = B                  # A | B  (informational; A/B otherwise warns)
value        = 0.000100           # stated half-width / std dev / cert U
distribution = normal             # normal | rectangular | triangular | u-shaped
divisor      = 2                  # GUM divisor for the chosen distribution

Exit codes

Code Meaning
0 Success (including user declining an -o overwrite prompt; also includes the guard-band-collapse case, which prints a stderr warning and forces FAIL)
1 Usage error: missing config arg, file not found, bad unit, bad -k, bad --sigfigs, unknown flag, write error, -r/-t mismatch, non-numeric or non-positive -r/-t, missing nominal when the decision rule is invoked
2 Config parse / validation error: grammar, missing key, non-numeric value, empty file
3 Arithmetic error: divisor of zero

Decision rule

When you also need a PASS/FAIL/INCONCLUSIVE statement of conformity, pass the measured result with -r and a symmetric tolerance half-width with -t. The config must include a nominal header. UncertCalc applies the ILAC P14:01/2022 simple guard band with w = U (clause 4.1):

  • Simple acceptance zone: [nominal − T, nominal + T]
  • Guard-banded acceptance zone: [nominal − T + U, nominal + T − U]
  • PASS — result inside the guard-banded zone (true value is within tolerance at the chosen coverage)
  • FAIL — result outside the simple acceptance zone
  • INCONCLUSIVE — result inside the guard band itself (between the guard-banded boundary and the simple boundary; risk of misclassification exceeds the chosen coverage)

A TUR = T / U line is reported for context. When U ≥ T the guard band collapses and a PASS verdict is unreachable for any result; UncertCalc emits a stderr warning, forces the verdict to FAIL, and still exits 0 so the budget and decision block can be archived as evidence.

The verdict is rendered in color (green/red/yellow) on stdout and suppressed by --no-color or -o. The decision and zone math run against the full-precision U; per-display rounding (via --sigfigs) cannot move a verdict across a boundary.

ISO/IEC 17025:2017 clause 7.8.6 compliance

Clause 7.8.6 requires that any statement of conformity to a specification documents the decision rule used and accounts for the level of risk it carries. The output above (rule name, ILAC reference, guard-band width w, both zones, TUR, and the verdict) is intended to satisfy that documentation requirement on its own when archived alongside the calibration record. UncertCalc takes no position on what tolerance, coverage, or guard-band width is appropriate for your accreditation scope — those remain your lab's decisions.

Example

jobs/ring_go_3-8-16_2B_20260516.conf is a calibration of a GO thread ring gauge against a calibrated setting plug on a horizontal comparator. With a measured pitch diameter of 0.3330 in and a ±0.0005 in tolerance:

$ ./uncertcalc.sh jobs/ring_go_3-8-16_2B_20260516.conf -r 0.3330 -t 0.0005 --no-color
Uncertainty Budget: GO Thread Ring Gauge 3/8-16 UNC 2B

  Component              Type  Value       Distribution  Divisor     u_i              %
  ---------------------------------------------------------------------------------------
  Setting Plug Cal Cert  B     0.000100    normal        2.000000    0.000050     24.44
  Thermal Expansion      B     0.000058    rectangular   1.732051    0.000033     10.96
* Comparator R&R         A     0.000080    normal        1.000000    0.000080     62.56
  Comparator Resolution  B     0.000025    rectangular   1.732051    0.000014      2.04
  ---------------------------------------------------------------------------------------
  * dominant component

  Combined standard uncertainty   u_c = 0.0001011 in
  Coverage                              95% (k = 2.000)
  Expanded uncertainty            U     = 0.0002023 in

  Decision Rule (ILAC P14:01/2022, simple guard band, w = U)

  Nominal                        N   = 0.3331 in
  Tolerance                      T   = 0.0005000 in
  Result                         y   = 0.3330 in
  Expanded uncertainty           U   = 0.0002023 in
  Deviation from nominal         y-N = -0.0001000 in

  Simple acceptance zone               [0.3326, 0.3336] in
  Guard-banded acceptance zone         [0.3328, 0.3334] in
  Test Uncertainty Ratio         TUR = 2.472

  Verdict                              PASS

The TUR of 2.47 means the tolerance is about 2.5× the expanded uncertainty — adequate but not generous. The measured 0.3330 falls inside the guard-banded zone with about 0.0002 in of headroom against the lower boundary, so a true value within tolerance is the most defensible conclusion at 95 % coverage.

Omit -r and -t to get just the v1 budget table — the decision block is skipped entirely and the rest of the output is byte-for-byte unchanged.

Layout

uncertcalc.sh           # Entry point: argv parsing and orchestration
lib/parse.sh            # .conf parser + validator
lib/math.sh             # rss, percent_contribution, sig_round (bc-backed)
lib/coverage.sh         # 90/95/99% → k preset lookup
lib/decision.sh         # Guard-banded decision rule, zones, TUR
lib/output.sh           # Table + decision-block formatter and file writer
examples/
  thread_plug.conf      # Thread plug gauge (three-wire method)
  ring_gauge.conf       # Setting ring gauge ID (comparator vs gauge blocks)
jobs/
  ring_go_3-8-16_2B_20260516.conf   # Worked example used in this README
tests/
  test_uncertcalc.sh    # Bash test suite (no external framework)

Testing

bash tests/test_uncertcalc.sh

References

  • JCGM 100:2008 — Evaluation of measurement data — Guide to the expression of uncertainty in measurement (GUM).
  • ILAC P14:01/2022 — Policy for Uncertainty in Calibration; clause 4.1 describes the simple guard-band decision rule used here.
  • ISO/IEC 17025:2017 — General requirements for the competence of testing and calibration laboratories; clause 7.8.6 covers reporting statements of conformity to specifications, including the decision rule.

About

Bash CLI tool for GUM-compliant uncertainty budget aggregation — calibration lab use

Topics

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages