| """含量均匀度接受值(AV)计算器测试。 |
| |
| 基准校验:直接复算 SL-0010 源表中实验室自报的 A、S、A+2.2S 列,验证与药典 |
| (ChP 0941)一致;并覆盖 USP <905> 常数、限值判定与不臆断退化。 |
| """ |
|
|
| from __future__ import annotations |
|
|
| import math |
|
|
| from skills.descriptive_summary.content_uniformity import acceptance_value |
|
|
|
|
| |
| _CU_20 = [99.19, 100.0, 97.68, 96.0, 98.81] |
| _CU_40 = [99.25, 101.43, 99.59, 97.71, 99.48] |
| _CU_60 = [100.5, 101.01, 99.85, 99.98, 97.23] |
|
|
|
|
| def test_chp_matches_lab_reported_20ug(): |
| """20μg:复算 A/S/AV 应与源表 A=1.664、S=1.5500、A+2.2S=5.074 一致。""" |
| r = acceptance_value(_CU_20, standard="chp") |
| assert math.isclose(r.mean, 98.336, abs_tol=1e-3) |
| assert math.isclose(r.deviation, 1.664, abs_tol=1e-3) |
| assert math.isclose(r.std, 1.55000967738914, rel_tol=1e-6) |
| assert math.isclose(r.k, 2.2) |
| assert math.isclose(r.acceptance_value, 5.074, abs_tol=1e-3) |
| assert r.within_spec is True |
| assert r.limit == 15.0 and r.limit_is_default is True |
|
|
|
|
| def test_chp_matches_lab_reported_40ug_60ug(): |
| r40 = acceptance_value(_CU_40, standard="chp") |
| assert math.isclose(r40.deviation, 0.508, abs_tol=1e-2) |
| assert math.isclose(r40.acceptance_value, 3.418, abs_tol=1e-2) |
| assert r40.within_spec is True |
| r60 = acceptance_value(_CU_60, standard="chp") |
| assert math.isclose(r60.deviation, 0.286, abs_tol=1e-2) |
| assert math.isclose(r60.acceptance_value, 3.504, abs_tol=1e-2) |
| assert r60.within_spec is True |
|
|
|
|
| def test_usp_reference_m_and_constant(): |
| """USP <905>:X̄ 落在 [98.5,101.5] 内 → M=X̄ → AV=k·s,k=2.4(n≤10)。""" |
| r = acceptance_value(_CU_20, standard="usp") |
| assert r.reference_m is not None |
| |
| assert math.isclose(r.reference_m, 98.5, abs_tol=1e-9) |
| assert math.isclose(r.deviation, abs(98.5 - r.mean), abs_tol=1e-6) |
| assert math.isclose(r.k, 2.4) |
| assert math.isclose(r.acceptance_value, r.deviation + 2.4 * r.std, rel_tol=1e-9) |
|
|
|
|
| def test_usp_mean_within_band_uses_mean_as_m(): |
| vals = [100.0, 100.5, 99.5, 100.2, 99.8] |
| r = acceptance_value(vals, standard="usp") |
| assert math.isclose(r.reference_m, r.mean, rel_tol=1e-9) |
| assert math.isclose(r.deviation, 0.0, abs_tol=1e-9) |
|
|
|
|
| def test_explicit_limit_overrides_default(): |
| r = acceptance_value(_CU_20, standard="chp", limit=10.0) |
| assert r.limit == 10.0 and r.limit_is_default is False |
|
|
|
|
| def test_fails_when_av_exceeds_limit(): |
| """构造高变异样本使 AV>L → 判不合格。""" |
| vals = [80.0, 120.0, 95.0, 110.0, 90.0] |
| r = acceptance_value(vals, standard="chp") |
| assert r.acceptance_value > 15.0 |
| assert r.within_spec is False |
|
|
|
|
| def test_insufficient_sample_returns_none(): |
| assert acceptance_value([100.0], standard="chp") is None |
| assert acceptance_value([], standard="chp") is None |
|
|