Model 01 Compartments - matej-hron/decojs GitHub Wiki

Model-01 — Compartments

Bühlmann ZH-L16 is a parallel-compartment model: 16 theoretical tissue groups, each with a half-time $T_{1/2}$ (how fast it on-/off-gasses) and two Bühlmann coefficients $a$ (bar) and $b$ (dimensionless) defining its M-value line. The letter suffix (A/B/C) picks one of three coefficient tables — same half-times, different a values (plus one $b$ quirk at TC1). See References.

All 16 compartments — full A/B/C table

Drawn directly from js/tissueCompartments.js. Bold values differ from variant A.

ID $T_{1/2}$ (min)¹ $b$ ² $a$ (16A) $a$ (16B) $a$ (16C) Category
1 4 / 5 0.5050 / 0.5578 1.2599 1.1696 1.1696 Fast
2 8 0.6514 1.0000 1.0000 1.0000 Fast
3 12.5 0.7222 0.8618 0.8618 0.8618 Fast
4 18.5 0.7825 0.7562 0.7562 0.7562 Medium
5 27 0.8126 0.6667 0.6667 0.6200 Medium
6 38.3 0.8434 0.5933 0.5600 0.5043 Medium
7 54.3 0.8693 0.5282 0.4947 0.4410 Medium
8 77 0.8910 0.4710 0.4500 0.4000 Medium
9 109 0.9092 0.4187 0.4187 0.3750 Slow
10 146 0.9222 0.3798 0.3798 0.3500 Slow
11 187 0.9319 0.3497 0.3497 0.3295 Slow
12 239 0.9403 0.3223 0.3223 0.3065 Slow
13 305 0.9477 0.2971 0.2850 0.2835 Slow
14 390 0.9544 0.2737 0.2737 0.2610 Slow
15 498 0.9602 0.2523 0.2523 0.2480 Slow
16 635 0.9653 0.2327 0.2327 0.2327 Slow

¹ TC1 is the only half-time that varies across variants: 4 min in A, 5 min in B/C. ² TC1 is the only $b$ that varies across variants: 0.5050 in A, 0.5578 in B/C. The half-time and $b$ swap together as a pair.

Pattern at a glance: B changes TC1 + TC6-8 + TC13 (4 compartments). C changes TC1 + TC5-15 (12 compartments). TC2-4 and TC16 are identical across all three variants. Smaller $a$ = more conservative (lower M-value at any depth).

The TC1 pairing is immutable — half-time and $b$ swap together when the variant changes. See js/tissueCompartments.js:46-61:

// js/tissueCompartments.js:46-61
const COMPARTMENT_1_HALFTIME = {
    [ZHL16_VARIANTS.A]: 4.0,   // Original Bühlmann specification
    [ZHL16_VARIANTS.B]: 5.0,   // Modified for printed tables
    [ZHL16_VARIANTS.C]: 5.0    // Modified for dive computers
};

const COMPARTMENT_1_B_N2 = {
    [ZHL16_VARIANTS.A]: 0.5050, // Paired with 4 min half-time
    [ZHL16_VARIANTS.B]: 0.5578, // Paired with 5 min half-time
    [ZHL16_VARIANTS.C]: 0.5578
};

Rate constant

The exponential loading/unloading rate follows directly from the half-time:

$$k = \frac{\ln 2}{T_{1/2}}$$

// js/tissueCompartments.js:216
export function getRateConstant(halfTime) {
    return Math.LN2 / halfTime;
}

Used by Model-02-Haldane-Equation and Model-03-Schreiner-Equation equations.

Bühlmann a/b — where they come from

Tabulated in js/tissueCompartments.js rather than computed at runtime, but they follow Baker's half-time formulas (see References):

$$a = 2 \cdot T_{1/2}^{-1/3} \quad (\text{bar}) \qquad b = 1.005 - T_{1/2}^{-1/2}$$

These give the ZH-L16A (experimental) values exactly. The B and C variants share A's $b$ values for TC2–TC16 (TC1 has its own pairing) and selectively lower the $a$ coefficient on a subset of compartments to produce tables / computer firmware that proved more conservative in practice. See the table above for which compartments differ in B vs. C.

See also: Sandbox: M-Values, whose bottom playground visualizes these formulas alongside the 16 stored compartment values — toggling between A and C lifts the adjusted dots off the analytical curves.

Variant semantics

Variant Purpose Conservatism
ZH-L16A Experimental (derived from formulas) Least — found too permissive in middle compartments in use
ZH-L16B Printed dive tables More conservative $a$ for TC6–8 and TC13
ZH-L16C Dive computers (DecoJS default) Most conservative — lowered $a$ for TC5 through TC15
// js/tissueCompartments.js:40
let currentVariant = ZHL16_VARIANTS.C;

Runtime switching

setZHL16Variant() mutates the exported COMPARTMENTS array in place (no reassignment) so downstream modules holding a reference pick up the change:

// js/tissueCompartments.js:182-192
export function setZHL16Variant(variant) {
    if (!Object.values(ZHL16_VARIANTS).includes(variant)) {
        console.warn(`Unknown ZH-L16 variant: ${variant}, defaulting to ZH-L16C`);
        variant = ZHL16_VARIANTS.C;
    }
    currentVariant = variant;
    const newCompartments = buildCompartments(variant);
    COMPARTMENTS.length = 0;
    COMPARTMENTS.push(...newCompartments);
}

Callers must recalculate any cached tissue loading after switching (the charts in js/charts/MValueChart.js do this on the variant-select handler).

Color coding

Used by the M-value and profile charts for quick visual grouping:

  • Reds / oranges (TC1–4): fast compartments
  • Greens (TC5–8): medium-fast
  • Blues (TC9–12): medium-slow
  • Purples / magentas (TC13–16): slow

See Model-04-M-Values for how $a$ and $b$ are actually used to compute the M-value line.