Download engine/test_nitp_b2.py from BEASTZZZ/OIML: direct link, hf CLI and curl.
- Browser
- Download file 5.84 kB
-
https://huggingface.co/spaces/BEASTZZZ/OIML/resolve/main/engine/test_nitp_b2.py
- Command line
-
hf download hf://spaces/BEASTZZZ/OIML/engine/test_nitp_b2.py
-
curl -L -o test_nitp_b2.py https://huggingface.co/spaces/BEASTZZZ/OIML/resolve/main/engine/test_nitp_b2.py
5.84 kB
| """ | |
| Second known-answer anchor: NITP 6.1 to 6.4, Appendix B.2. | |
| The first anchor (test_harness.py) is a published *approval* -- it fixes the | |
| instrument's derived properties. This one is a published *worked example*: the | |
| Australian National Measurement Institute's own National Instrument Test | |
| Procedures print a complete substitution-load weighing test for a class 3 | |
| weighbridge, with every indication, every additional load and every computed | |
| error shown. Reproducing that arithmetic exactly is the strongest correctness | |
| argument available short of a real filled-in RRSL report. | |
| NITP 6.1 to 6.4, First edition, second revision, January 2014 | |
| Appendix B.2, "Weighing Performance using Substitution Load Material" | |
| Three things are anchored here: | |
| 1. The mpe at seven loads, including 10 t. | |
| 2. The error formula E = I + 0.5e - dL - L (NITP clause 5.4.2, step 8), | |
| which is the same relation this project writes as P = I + 1/2 e - dL, | |
| E = P - L. An independent regulator stating it identically is worth more | |
| than our own derivation. | |
| 3. The substitution formula L_sub = I_sub + 0.5e - E (clause 5.4.2 A(e)). | |
| Why the 10 t row is the important one | |
| ------------------------------------- | |
| At e = 0.02 t, a load of 10 t is exactly 500 e. NMI prints its mpe as | |
| +/- 0.01 t, which is 0.5 e -- so 500 e falls in the FIRST band. That is only | |
| true if the second band opens at strictly greater than 500, exactly as | |
| mpe-bands.json records it. | |
| Anyone transcribing Table 6 from the Indian Kanoon rendering of the Seventh | |
| Schedule gets overlapping bands and would print +/- 0.02 t here. This single | |
| row is independent, third-party confirmation that the operators in | |
| mpe-bands.json are right and that rendering is corrupt. | |
| python3 engine/test_nitp_b2.py | |
| """ | |
| from nawi_engine import Instrument, mpe_for_load | |
| T = 1_000_000.0 # grams in a tonne | |
| E_T = 0.02 # verification scale interval, in tonnes | |
| PASSED = [] | |
| FAILED = [] | |
| def check(label, got, want, tol=1e-9): | |
| ok = abs(got - want) <= tol if isinstance(want, (int, float)) else got == want | |
| (PASSED if ok else FAILED).append(label) | |
| print(f" [{'ok ' if ok else 'FAIL'}] {label}: got {got}, want {want}") | |
| def rule(title): | |
| print("\n" + title) | |
| print("-" * len(title)) | |
| weighbridge = Instrument( | |
| manufacturer="(NITP 6.1 to 6.4, Appendix B.2)", | |
| model="class 3 static weighbridge", | |
| accuracy_class="III", | |
| max_capacity_g=60 * T, | |
| e_g=E_T * T, | |
| d_g=E_T * T, | |
| min_capacity_g=0.4 * T, | |
| ) | |
| # ========================================================================== | |
| rule("1. mpe at every load NMI prints in the Appendix B.2 report") | |
| # ========================================================================== | |
| # (load in tonnes, mpe in tonnes as printed by NMI) | |
| for load_t, want_t in [ | |
| (0.40, 0.01), # 20 e -> 0.5 e | |
| (10.00, 0.01), # 500 e -> 0.5 e <-- the band edge | |
| (16.00, 0.02), # 800 e -> 1.0 e | |
| (31.78, 0.02), # 1 589 e -> 1.0 e | |
| (39.08, 0.02), # 1 954 e -> 1.0 e | |
| (47.08, 0.03), # 2 354 e -> 1.5 e | |
| (59.86, 0.03), # 2 993 e -> 1.5 e | |
| ]: | |
| check(f"mpe at {load_t:g} t ({load_t / E_T:,.0f} e)", | |
| mpe_for_load(weighbridge, load_t * T) / T, want_t) | |
| # ========================================================================== | |
| rule("2. The band edge, stated on its own because it is the whole argument") | |
| # ========================================================================== | |
| check("500 e lands in the first band, so mpe = 0.5 e", | |
| mpe_for_load(weighbridge, 10 * T) / T, 0.5 * E_T) | |
| check("just past it, 500.5 e, mpe steps to 1.0 e", | |
| mpe_for_load(weighbridge, 10.01 * T) / T, 1.0 * E_T) | |
| # ========================================================================== | |
| rule("3. E = I + 0.5e - dL - L (NITP clause 5.4.2, step 8)") | |
| # ========================================================================== | |
| def error_t(indication_t, delta_load_t, load_t): | |
| """The project computes P = I + 1/2 e - dL, then E = P - L.""" | |
| return (indication_t + 0.5 * E_T - delta_load_t) - load_t | |
| for L, I, dL, want in [ | |
| (16.00, 16.02, 0.012, +0.018), | |
| (31.78, 31.80, 0.014, +0.016), | |
| (39.08, 39.10, 0.016, +0.014), | |
| (47.08, 47.10, 0.016, +0.014), | |
| (59.86, 59.88, 0.018, +0.012), | |
| ]: | |
| check(f"E at L = {L:g} t (I = {I:g}, dL = {dL:g})", error_t(I, dL, L), want) | |
| # ========================================================================== | |
| rule("4. L_sub = I_sub + 0.5e - E (NITP clause 5.4.2, method A(e))") | |
| # ========================================================================== | |
| for I_sub, E, want in [ | |
| (15.78, 0.018, 15.772), # Sub 1, test rig + forklift | |
| (31.08, 0.016, 31.074), # Sub 2, gravel truck | |
| (46.86, 0.014, 46.856), # Sub 3, Sub 1 + Sub 2 | |
| ]: | |
| check(f"L_sub from I_sub = {I_sub:g} t, E = {E:+g} t", | |
| I_sub + 0.5 * E_T - E, want) | |
| # ========================================================================== | |
| rule("5. Every load in the report is inside its mpe, as NMI records") | |
| # ========================================================================== | |
| # NMI marks every weighing row "pass". The errors above must therefore all | |
| # sit within the mpe for their load -- a end-to-end check of both tables. | |
| for L, I, dL in [(16.00, 16.02, 0.012), (31.78, 31.80, 0.014), | |
| (39.08, 39.10, 0.016), (47.08, 47.10, 0.016), | |
| (59.86, 59.88, 0.018)]: | |
| E = error_t(I, dL, L) | |
| mpe = mpe_for_load(weighbridge, L * T) / T | |
| check(f"|E| <= mpe at {L:g} t", abs(E) <= mpe + 1e-9, True) | |
| # ========================================================================== | |
| print("\n" + "=" * 62) | |
| print(f" {len(PASSED)} passed, {len(FAILED)} failed") | |
| for f in FAILED: | |
| print(f" FAILED: {f}") | |
| print("=" * 62) | |