formulab 0.37.0 → 0.37.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,41 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.37.1] - 2026-09-09
9
+
10
+ ### Fixed
11
+
12
+ - **`quality/mtbf()`** — availability and the failure rate were derived from the rounded
13
+ MTBF and MTTR the function reports rather than from the times it was given. Rounding a
14
+ mean to two decimals and then dividing by it is not a rounding whisker: when short times
15
+ are spread over many failures the rounded mean is a large fraction of its own value. One
16
+ hour of operating time with half an hour of repair over 34 failures reported 75%
17
+ availability against a true 66.67%, and across a swept grid of plausible inputs a third
18
+ of the cases differed in the reported digits. Availability now reduces to the time-based
19
+ ratio of up time to total time (the failure count cancels), and the failure rate is taken
20
+ from the unrounded mean. The reported MTBF and MTTR are unchanged.
21
+ - **`quality/mtbf()`** — `reliabilityAtMtbf` returned 0 instead of e^-1 when the mean time
22
+ between failures rounded down to 0.00, and `totalRepairTime` was not validated. Reliability
23
+ at T = MTBF is e^-1 for any positive MTBF, and a negative repair time now throws
24
+ `RangeError` like the other invalid inputs.
25
+
26
+ - **`machining/cuspHeight()`** — returned `NaN` instead of rejecting impossible input. A
27
+ stepover wider than the tool diameter drove the square root negative, and non-positive
28
+ radii and stepovers were not checked at all, so a caller received a silent `NaN` and
29
+ rendered it. All three now throw `RangeError`. A stepover of exactly the tool diameter
30
+ stays valid: the passes just touch and the ridge is a full tool radius high.
31
+
32
+ ### Changed
33
+
34
+ - **`quality/mtbf()`** — documented which defined term each output corresponds to, with an
35
+ `@reference` to EN 13306:2017 (maintenance terminology): 11.3 mean time between failures,
36
+ 11.2 mean operating time between failures, 11.4 mean repair time, 9.18 time between
37
+ failures, 4.9 time based availability. The function had carried no citation since an
38
+ earlier, incorrect attribution was removed. Dividing operating time by the failure count
39
+ is strictly the mean *operating* time between failures (11.2); the name MTBF is kept
40
+ because that is what the figure is called in practice, and the distinction is now stated
41
+ rather than left implicit.
42
+
8
43
  ## [0.37.0] - 2026-09-07
9
44
 
10
45
  ### Added
@@ -10,6 +10,9 @@ import type { CuspHeightInput, CuspHeightResult } from './types.js';
10
10
  *
11
11
  * @param input - Cusp height parameters
12
12
  * @returns CuspHeightResult with scallop height and approximate Ra
13
+ * @throws RangeError if toolRadius or stepover is not positive, or if stepover exceeds the
14
+ * tool diameter (adjacent passes never meet, so the formula has no scallop to describe —
15
+ * without the guard the square root goes negative and the result is silently NaN)
13
16
  */
14
17
  export declare function cuspHeight(input: CuspHeightInput): CuspHeightResult;
15
18
  //# sourceMappingURL=cuspHeight.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"cuspHeight.d.ts","sourceRoot":"","sources":["../../src/machining/cuspHeight.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEpE;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,gBAAgB,CAUnE"}
1
+ {"version":3,"file":"cuspHeight.d.ts","sourceRoot":"","sources":["../../src/machining/cuspHeight.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEpE;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,gBAAgB,CAoBnE"}
@@ -10,9 +10,21 @@ import { roundTo } from '../utils.js';
10
10
  *
11
11
  * @param input - Cusp height parameters
12
12
  * @returns CuspHeightResult with scallop height and approximate Ra
13
+ * @throws RangeError if toolRadius or stepover is not positive, or if stepover exceeds the
14
+ * tool diameter (adjacent passes never meet, so the formula has no scallop to describe —
15
+ * without the guard the square root goes negative and the result is silently NaN)
13
16
  */
14
17
  export function cuspHeight(input) {
15
18
  const { toolRadius, stepover } = input;
19
+ if (!(toolRadius > 0)) {
20
+ throw new RangeError('toolRadius must be greater than 0');
21
+ }
22
+ if (!(stepover > 0)) {
23
+ throw new RangeError('stepover must be greater than 0');
24
+ }
25
+ if (stepover > 2 * toolRadius) {
26
+ throw new RangeError('stepover must not exceed the tool diameter (2 x toolRadius)');
27
+ }
16
28
  const halfStep = stepover / 2;
17
29
  const h = toolRadius - Math.sqrt(toolRadius * toolRadius - halfStep * halfStep);
18
30
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"cuspHeight.js","sourceRoot":"","sources":["../../src/machining/cuspHeight.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAGtC;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,UAAU,CAAC,KAAsB;IAC/C,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IAEvC,MAAM,QAAQ,GAAG,QAAQ,GAAG,CAAC,CAAC;IAC9B,MAAM,CAAC,GAAG,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,CAAC,CAAC;IAEhF,OAAO;QACL,UAAU,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;QACzB,gBAAgB,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,iCAAiC;KAChF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"cuspHeight.js","sourceRoot":"","sources":["../../src/machining/cuspHeight.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAGtC;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,UAAU,CAAC,KAAsB;IAC/C,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC;IAEvC,IAAI,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,UAAU,CAAC,mCAAmC,CAAC,CAAC;IAC5D,CAAC;IACD,IAAI,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,UAAU,CAAC,iCAAiC,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,QAAQ,GAAG,CAAC,GAAG,UAAU,EAAE,CAAC;QAC9B,MAAM,IAAI,UAAU,CAAC,6DAA6D,CAAC,CAAC;IACtF,CAAC;IAED,MAAM,QAAQ,GAAG,QAAQ,GAAG,CAAC,CAAC;IAC9B,MAAM,CAAC,GAAG,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,UAAU,GAAG,QAAQ,GAAG,QAAQ,CAAC,CAAC;IAEhF,OAAO;QACL,UAAU,EAAE,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;QACzB,gBAAgB,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,iCAAiC;KAChF,CAAC;AACJ,CAAC"}
@@ -6,6 +6,26 @@ import type { MtbfInput, MtbfResult } from './types.js';
6
6
  * MTTR = Total Repair Time / Number of Failures
7
7
  * Availability = MTBF / (MTBF + MTTR)
8
8
  *
9
+ * Each output maps to a defined term:
10
+ * - `mtbf` — "average of the times between failures" (EN 13306:2017, 11.3). Note that a
11
+ * time between failures (9.18) is the duration between consecutive failures and "may
12
+ * include non-operating time after restoration"; when the input is operating time, as
13
+ * here, the quantity computed is strictly the mean operating time between failures
14
+ * (MOTBF, 11.2 — "average of the operating times between failures", applied to
15
+ * repairable items). Industry practice calls this figure MTBF, and the name is kept for
16
+ * that reason.
17
+ * - `mttr` — mean repair time (MRT, 11.4: "average of the repair times"). MTTR is the
18
+ * common industry spelling of the same average.
19
+ * - `availability` — the time-based availability ratio of 4.9: up time over total time
20
+ * (UT / (UT + DT)), expressed as a percentage.
21
+ * - `failureRate`, `reliabilityAtMtbf` — the constant-failure-rate (exponential) model,
22
+ * lambda = 1 / MTBF and R(t) = exp(-lambda·t). Not part of the terminology standard;
23
+ * it holds only during a constant failure period, and R(MTBF) = e^-1 always.
24
+ *
25
+ * @reference EN 13306:2017 — Maintenance terminology. 11.3 (mean time between failures),
26
+ * 11.2 (mean operating time between failures), 11.4 (mean repair time), 9.18 (time
27
+ * between failures), 4.9 (time based availability).
28
+ *
9
29
  * @param input - MTBF input parameters
10
30
  * @returns MTBF analysis result
11
31
  * @throws RangeError if totalOperatingTime is not positive, or if
@@ -1 +1 @@
1
- {"version":3,"file":"mtbf.d.ts","sourceRoot":"","sources":["../../src/quality/mtbf.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExD;;;;;;;;;;;GAWG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU,CAoCjD"}
1
+ {"version":3,"file":"mtbf.d.ts","sourceRoot":"","sources":["../../src/quality/mtbf.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU,CA8CjD"}
@@ -6,6 +6,26 @@ import { roundTo } from '../utils.js';
6
6
  * MTTR = Total Repair Time / Number of Failures
7
7
  * Availability = MTBF / (MTBF + MTTR)
8
8
  *
9
+ * Each output maps to a defined term:
10
+ * - `mtbf` — "average of the times between failures" (EN 13306:2017, 11.3). Note that a
11
+ * time between failures (9.18) is the duration between consecutive failures and "may
12
+ * include non-operating time after restoration"; when the input is operating time, as
13
+ * here, the quantity computed is strictly the mean operating time between failures
14
+ * (MOTBF, 11.2 — "average of the operating times between failures", applied to
15
+ * repairable items). Industry practice calls this figure MTBF, and the name is kept for
16
+ * that reason.
17
+ * - `mttr` — mean repair time (MRT, 11.4: "average of the repair times"). MTTR is the
18
+ * common industry spelling of the same average.
19
+ * - `availability` — the time-based availability ratio of 4.9: up time over total time
20
+ * (UT / (UT + DT)), expressed as a percentage.
21
+ * - `failureRate`, `reliabilityAtMtbf` — the constant-failure-rate (exponential) model,
22
+ * lambda = 1 / MTBF and R(t) = exp(-lambda·t). Not part of the terminology standard;
23
+ * it holds only during a constant failure period, and R(MTBF) = e^-1 always.
24
+ *
25
+ * @reference EN 13306:2017 — Maintenance terminology. 11.3 (mean time between failures),
26
+ * 11.2 (mean operating time between failures), 11.4 (mean repair time), 9.18 (time
27
+ * between failures), 4.9 (time based availability).
28
+ *
9
29
  * @param input - MTBF input parameters
10
30
  * @returns MTBF analysis result
11
31
  * @throws RangeError if totalOperatingTime is not positive, or if
@@ -20,19 +40,28 @@ export function mtbf(input) {
20
40
  if (numberOfFailures <= 0) {
21
41
  throw new RangeError('numberOfFailures must be greater than 0');
22
42
  }
43
+ if (totalRepairTime < 0) {
44
+ throw new RangeError('totalRepairTime must not be negative');
45
+ }
46
+ // Every derived figure below is computed from the raw times, never from the rounded
47
+ // values reported back. Rounding an intermediate to 2 decimals and then dividing by it
48
+ // is not a rounding whisker: with short times spread over many failures the rounded
49
+ // mean is a large fraction of its own value, and availability drifts by whole points
50
+ // (1 h operating / 0.5 h repair / 34 failures reads 75% that way, against a true 66.67%).
51
+ const mtbfExact = totalOperatingTime / numberOfFailures;
52
+ const mttrExact = totalRepairTime / numberOfFailures;
23
53
  // MTBF = Total Operating Time / Number of Failures
24
- const mtbfValue = roundTo(totalOperatingTime / numberOfFailures, 2);
54
+ const mtbfValue = roundTo(mtbfExact, 2);
25
55
  // MTTR = Total Repair Time / Number of Failures
26
- const mttr = numberOfFailures > 0 ? roundTo(totalRepairTime / numberOfFailures, 2) : 0;
27
- // Availability = MTBF / (MTBF + MTTR)
28
- const availability = mtbfValue + mttr > 0
29
- ? roundTo((mtbfValue / (mtbfValue + mttr)) * 100, 2)
30
- : 0;
56
+ const mttr = roundTo(mttrExact, 2);
57
+ // Availability = MTBF / (MTBF + MTTR). The failure count cancels, leaving the 4.9
58
+ // time-based ratio of up time to total time.
59
+ const availability = roundTo((totalOperatingTime / (totalOperatingTime + totalRepairTime)) * 100, 2);
31
60
  // Failure rate (lambda) = 1 / MTBF
32
- const failureRate = mtbfValue > 0 ? roundTo(1 / mtbfValue, 6) : 0;
61
+ const failureRate = roundTo(1 / mtbfExact, 6);
33
62
  // Reliability at time T = e^(-lambda * T), where T = MTBF
34
- // R(MTBF) = e^(-1) = 0.3679 = 36.79%
35
- const reliabilityAtMtbf = mtbfValue > 0 ? roundTo(Math.exp(-1) * 100, 2) : 0;
63
+ // R(MTBF) = e^(-1) = 0.3679 = 36.79%, whatever the MTBF is
64
+ const reliabilityAtMtbf = roundTo(Math.exp(-1) * 100, 2);
36
65
  return {
37
66
  mtbf: mtbfValue,
38
67
  mttr,
@@ -1 +1 @@
1
- {"version":3,"file":"mtbf.js","sourceRoot":"","sources":["../../src/quality/mtbf.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAGtC;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,IAAI,CAAC,KAAgB;IACnC,MAAM,EAAE,kBAAkB,EAAE,eAAe,EAAE,gBAAgB,EAAE,GAAG,KAAK,CAAC;IAExE,kBAAkB;IAClB,IAAI,kBAAkB,IAAI,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,UAAU,CAAC,2CAA2C,CAAC,CAAC;IACpE,CAAC;IACD,IAAI,gBAAgB,IAAI,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,UAAU,CAAC,yCAAyC,CAAC,CAAC;IAClE,CAAC;IAED,mDAAmD;IACnD,MAAM,SAAS,GAAG,OAAO,CAAC,kBAAkB,GAAG,gBAAgB,EAAE,CAAC,CAAC,CAAC;IAEpE,gDAAgD;IAChD,MAAM,IAAI,GAAG,gBAAgB,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,eAAe,GAAG,gBAAgB,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEvF,sCAAsC;IACtC,MAAM,YAAY,GAAG,SAAS,GAAG,IAAI,GAAG,CAAC;QACvC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC;QACpD,CAAC,CAAC,CAAC,CAAC;IAEN,mCAAmC;IACnC,MAAM,WAAW,GAAG,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAElE,0DAA0D;IAC1D,qCAAqC;IACrC,MAAM,iBAAiB,GAAG,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAE7E,OAAO;QACL,IAAI,EAAE,SAAS;QACf,IAAI;QACJ,YAAY;QACZ,WAAW;QACX,iBAAiB;KAClB,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"mtbf.js","sourceRoot":"","sources":["../../src/quality/mtbf.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAGtC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,UAAU,IAAI,CAAC,KAAgB;IACnC,MAAM,EAAE,kBAAkB,EAAE,eAAe,EAAE,gBAAgB,EAAE,GAAG,KAAK,CAAC;IAExE,kBAAkB;IAClB,IAAI,kBAAkB,IAAI,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,UAAU,CAAC,2CAA2C,CAAC,CAAC;IACpE,CAAC;IACD,IAAI,gBAAgB,IAAI,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,UAAU,CAAC,yCAAyC,CAAC,CAAC;IAClE,CAAC;IACD,IAAI,eAAe,GAAG,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,UAAU,CAAC,sCAAsC,CAAC,CAAC;IAC/D,CAAC;IAED,oFAAoF;IACpF,uFAAuF;IACvF,oFAAoF;IACpF,qFAAqF;IACrF,0FAA0F;IAC1F,MAAM,SAAS,GAAG,kBAAkB,GAAG,gBAAgB,CAAC;IACxD,MAAM,SAAS,GAAG,eAAe,GAAG,gBAAgB,CAAC;IAErD,mDAAmD;IACnD,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;IAExC,gDAAgD;IAChD,MAAM,IAAI,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;IAEnC,kFAAkF;IAClF,6CAA6C;IAC7C,MAAM,YAAY,GAAG,OAAO,CAAC,CAAC,kBAAkB,GAAG,CAAC,kBAAkB,GAAG,eAAe,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC;IAErG,mCAAmC;IACnC,MAAM,WAAW,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,EAAE,CAAC,CAAC,CAAC;IAE9C,0DAA0D;IAC1D,2DAA2D;IAC3D,MAAM,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC;IAEzD,OAAO;QACL,IAAI,EAAE,SAAS;QACf,IAAI;QACJ,YAAY;QACZ,WAAW;QACX,iBAAiB;KAClB,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "formulab",
3
- "version": "0.37.0",
3
+ "version": "0.37.1",
4
4
  "description": "Manufacturing & Engineering calculation formulas library - 203 industrial calculations across 15 domains for OEE, Cpk, SPC, FMEA, Nelson Rules, metal weight, CNC machining, GD&T, battery, environmental, pipe flow, logistics, IE time study, and more",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",