Add central material calibration support
This commit is contained in:
+123
-11
@@ -1,4 +1,104 @@
|
||||
# Bento 1 fresh bentonite consumption
|
||||
# Bento 1 fresh bentonite KPIs
|
||||
|
||||
|
||||
## Three distinct quantities
|
||||
|
||||
All **fresh bentonite** values exclude the third recycled/recovered-material
|
||||
scatterer. Only the two actual rpm signals listed below are used; no SET signals
|
||||
are introduced. The specific discharge is central calibration
|
||||
data: **2.75 kg/(revolution × metre product width)**.
|
||||
|
||||
A) **Instantaneous process application [g/m²]**
|
||||
|
||||
`application_g_m2 = (rpm_left + rpm_right) × 2.75 × 1000 / line_speed_m_min`
|
||||
|
||||
Emitted only for observed samples with line speed **strictly greater than
|
||||
0.3 m/min**. Zero, near-zero, negative and threshold-equal speeds emit no point.
|
||||
Width cancels between kg/min and m²/min; neither nominal width nor ERP good area
|
||||
enters this formula. For 3.739 + 3.956 rpm at 8 m/min the result is 2645.15625 g/m².
|
||||
This is fresh-roll process application, not FA material efficiency.
|
||||
|
||||
B) **Cumulative fresh consumption [kg]**, unchanged
|
||||
|
||||
`kg/min = (rpm_left + rpm_right) × nominal_width_m × 2.75`
|
||||
|
||||
The existing previous-value integration sums `kg/min × elapsed_seconds / 60`
|
||||
for eligible intervals, using the preceding sample's production gate. Width
|
||||
continues to come from the ERP nominal-width parser. The integration algorithm,
|
||||
gap handling, order checkpoint format and disjoint-run accumulation are unchanged.
|
||||
|
||||
C) **FA material efficiency [g/m²]**
|
||||
|
||||
`efficiency_g_m2 = cumulative_fresh_bentonite_kg × 1000 / cumulative_good_area_m2`
|
||||
|
||||
The generic material-efficiency service reads the latest exact-order cumulative
|
||||
snapshot **at or before the ERP feedback timestamp**, then divides by that
|
||||
feedback's cumulative good area. Missing/nonpositive good area emits no point.
|
||||
This ratio includes losses captured by the existing consumption model (startup
|
||||
material, rejects and other consumed material not represented in good area).
|
||||
It does not add consumption during intervals excluded by the validated gate or
|
||||
gap rules, including stopped-line periods. Disjoint runs of one FA share the
|
||||
existing order total; their cumulative snapshots must not be summed again.
|
||||
|
||||
## Configuration, PostgreSQL and Grafana
|
||||
|
||||
| Calculation ID | Table | Value column | Time column |
|
||||
| --- | --- | --- | --- |
|
||||
| `bento1-fresh-bentonite-application` | `material_application_snapshots` | `application_g_m2` | `timestamp` |
|
||||
| `bento1-fresh-bentonite-consumption` | `material_consumption_snapshots` | `consumption_kg` | `timestamp` |
|
||||
| `bento1-fresh-bentonite-efficiency` | `material_efficiency_snapshots` | `material_consumption_g_per_m2` | `erp_feedback_timestamp` |
|
||||
|
||||
Scope Grafana queries by calculation ID and
|
||||
`machine_id = '5f42a4f6-9ca0-4f6f-9786-40d50a35b230'`; optionally filter by
|
||||
`production_order` (application/consumption) or `enlyze_production_order`
|
||||
(efficiency). The efficiency table also stores `good_quantity_m2`,
|
||||
`material_consumption_kg`, `material_consumption_kg_per_m2` and
|
||||
`material_snapshot_timestamp` for auditability.
|
||||
|
||||
`config/bento1-material-consumption.yaml` opts into process snapshots through
|
||||
`process_application_calculation_id`. This generic option requires rotational
|
||||
sources and a positive speed gate. Both outputs reuse the same configured ACT
|
||||
signals, discharge factor and samples. Process points use source timestamps,
|
||||
including bootstrap samples from disjoint runs; no interpolation or hold-forward
|
||||
points are stored for inactive periods. Configure Grafana to leave missing
|
||||
periods as gaps rather than carrying the last active value forward.
|
||||
|
||||
The shared consumption poller still requires valid ERP width/order context to
|
||||
complete a cycle, although the application formula itself has no width input.
|
||||
Application rows are committed before the existing checkpoint advances; a failed
|
||||
application write retries the window. Duplicate source timestamps are ignored by
|
||||
the primary key. Existing checkpoints are retained, so earlier application
|
||||
history is not automatically backfilled. K7 does not enable this output.
|
||||
|
||||
`config/bento1-material-efficiency.yaml` uses the existing generic runner.
|
||||
`calculation_id` selects the cumulative input; optional `output_calculation_id`
|
||||
sets the distinct persisted KPI ID. Omitting it preserves existing behavior,
|
||||
including K7. ERP workplace `strip().casefold()` normalization is unchanged.
|
||||
|
||||
Before deploying, apply the additive, idempotent `db/schema.sql` to the existing
|
||||
PostgreSQL database to create `material_application_snapshots` and its index.
|
||||
The existing consumption and efficiency tables need no column migration. For
|
||||
example, on the deployment host:
|
||||
|
||||
```sh
|
||||
docker compose exec -T timescaledb psql -U production_analytics -d production_analytics \
|
||||
-v ON_ERROR_STOP=1 < db/schema.sql
|
||||
```
|
||||
|
||||
Restart the configured Bento consumption runner to enable process persistence,
|
||||
and supervise a separate generic efficiency runner:
|
||||
|
||||
```sh
|
||||
production-analytics run material-efficiency \
|
||||
--config config/bento1-material-efficiency.yaml \
|
||||
--secrets-file secrets/enlyze.env --erp-secrets-file secrets/erp.env
|
||||
```
|
||||
|
||||
No cleanup/reset of validated rpm consumption state or snapshots is required for
|
||||
these additions. No database migration, live service restart or historical data
|
||||
cleanup was performed as part of this implementation.
|
||||
|
||||
## Validated cumulative model details
|
||||
|
||||
`config/bento1-material-consumption.yaml` defines
|
||||
`bento1-fresh-bentonite-consumption`, an estimate of **fresh bentonite consumption**
|
||||
@@ -7,18 +107,19 @@ full web width. The recycled/recovered third spreader is excluded.
|
||||
|
||||
The generic `rotational_discharge` source converts one or more rpm signals to the
|
||||
existing integrator's kg/h: `sum(rpm) × nominal_width_m × specific_discharge_kg_per_rev_m × 60`.
|
||||
Bento config sets the factor to **3.12 kg/(rev·m)** and uses:
|
||||
Bento config sets the factor to **2.75 kg/(rev·m)** and uses:
|
||||
|
||||
- Right ACT: `6e5d2d94-98f9-4cc1-8a88-7987c6282525`
|
||||
- Left ACT: `cd7385c4-337b-4759-ab32-45d65beaf190`
|
||||
|
||||
ENLYZE now returns physical rpm directly (scaling factor 1.0); no division by
|
||||
1000 is applied. For 3.739 + 3.956 rpm and 5 m width, the rate is 120.042 kg/min
|
||||
(7202.52 kg/h), giving 20.007 kg in ten seconds.
|
||||
1000 is applied. For 3.739 + 3.956 rpm and 5 m width, the rate is 105.80625 kg/min
|
||||
(6348.375 kg/h), giving 17.634375 kg in ten seconds.
|
||||
|
||||
Transport speed `fef41976-1103-4090-b780-eaeecc02fdfa` is exclusively the
|
||||
production gate: speed must be strictly greater than 0.3 m/min. It does not
|
||||
multiply the mass rate. The generic rotational mode also supports omitting
|
||||
For cumulative consumption, transport speed
|
||||
`fef41976-1103-4090-b780-eaeecc02fdfa` remains exclusively the production gate:
|
||||
speed must be strictly greater than 0.3 m/min. It does not multiply the mass rate.
|
||||
For instantaneous application, this same speed is also the denominator. The generic rotational mode also supports omitting
|
||||
`gate_signal_ref` and `gate_threshold`, in which case all valid intervals are
|
||||
active. Bento retains its gate.
|
||||
|
||||
@@ -43,13 +144,24 @@ current ERP context supplies width for all runs of the same order, assuming
|
||||
constant article width. Historical orders no longer in the ERP workplace view
|
||||
need a historical width source for replay.
|
||||
|
||||
The configured factor is based on the supplied independent historical checks:
|
||||
3.1175 at 5.00 m (article 180305), 3.1193 and 3.1187 at 4.85 m (article 173000),
|
||||
and median 3.1208 at 5.00 m (article 180005; p05–p95 3.0703–3.1558).
|
||||
The current factor is **2.75 kg/(rev*m)**, independently derived on
|
||||
**2026-09-08** by the **gravimetric tray method**: measured application
|
||||
**4068 g/m²**, line speed **2.3 m/min**, actual rotational signals **left 1.65**
|
||||
and **right 1.75**. The derivation is `4.068 × 2.3 / (1.65 + 1.75) ≈ 2.75188`,
|
||||
rounded to the configured 2.75. This supersedes the earlier 3.12 estimate.
|
||||
See [central calibration configuration](material-calibrations.md) for updates
|
||||
and persistence semantics.
|
||||
|
||||
Tests use realistic rpm values and synthetic samples, including disjoint-run
|
||||
bootstrap and persisted resume. They are not a new replay of recorded ENLYZE data.
|
||||
|
||||
## Old calculation cleanup: review before execution
|
||||
## Historical migration from SET to rpm: review before execution
|
||||
|
||||
The following records the earlier source-model migration, **not a prerequisite
|
||||
cleanup for adding these KPIs**. Its deployment observations are historical.
|
||||
If the validated rpm model is already deployed, retain its state and snapshots;
|
||||
do not execute this historical cleanup for the KPI extension. Recheck deployment
|
||||
provenance separately if that earlier migration is still outstanding.
|
||||
|
||||
No production state or database rows were changed during this implementation,
|
||||
and no service start was requested. The operator reports Bento stopped;
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
# Material calibrations
|
||||
|
||||
Process calibration values live in the version-controlled
|
||||
`config/material-calibrations.yaml`. Calculations refer to opaque IDs; IDs have
|
||||
no special meaning to the parser. The current entry is:
|
||||
|
||||
```yaml
|
||||
calibrations:
|
||||
bento1-spreader-1-2:
|
||||
type: rotational_discharge
|
||||
value: 2.75
|
||||
unit: kg_per_rev_m
|
||||
calibrated_at: 2026-09-08
|
||||
method: gravimetric_tray
|
||||
description: Bento 1 fresh-bentonite spreaders 1 and 2
|
||||
reference:
|
||||
measured_application_g_m2: 4068
|
||||
line_speed_m_min: 2.3
|
||||
signal_values:
|
||||
left: 1.65
|
||||
right: 1.75
|
||||
```
|
||||
|
||||
All entry fields are required. Type, unit, method and description are non-empty
|
||||
strings; value must be a finite number (booleans are rejected); calibrated_at is
|
||||
a calendar date in YYYY-MM-DD format, quoted or unquoted. Reference is a non-empty
|
||||
mapping whose contents preserve source-specific measurement provenance. Unknown
|
||||
entry fields and duplicate YAML keys are rejected. The generic registry permits
|
||||
other types and units; each consuming calculation checks its own compatibility.
|
||||
|
||||
`config/bento1-material-consumption.yaml` contains
|
||||
`calibration_ref: bento1-spreader-1-2`. During configuration loading, references
|
||||
resolve from `material-calibrations.yaml` in the calculation file's directory,
|
||||
independently of the working directory. The entire registry is validated when a
|
||||
reference is used. Rotational discharge requires type `rotational_discharge`,
|
||||
unit `kg_per_rev_m` and a positive value. Resolution supplies the existing
|
||||
`specific_discharge_kg_per_rev_m` runtime field for both application and
|
||||
consumption; the calculation algorithms are unchanged. There is no unit conversion.
|
||||
|
||||
Missing/unreadable files, missing IDs, invalid metadata and incompatible type or
|
||||
unit raise `CalculationConfigError` before a runner starts. Existing direct numeric
|
||||
configurations remain supported; specifying both a reference and a direct factor
|
||||
is rejected. References are currently supported by rotational discharge consumers.
|
||||
K7 uses direct mass rate and does not load or require a calibration file.
|
||||
|
||||
## Updating a calibration
|
||||
|
||||
After a physical measurement, edit only the central entry's value, date, method
|
||||
and reference details, and keep its ID stable. Review and version-control the
|
||||
change. Additional machines can add new IDs using the same structure. A new
|
||||
calculation type needs an explicit consumer compatibility contract.
|
||||
|
||||
Ship the central YAML alongside the calculation YAML and restart the consuming
|
||||
process to load changes. No new CLI flag, environment variable, database migration
|
||||
or UI is required. There is no hot reload or historical date-based selection.
|
||||
Changes affect future calculations and explicitly rebuilt calculations. Historical
|
||||
persisted snapshots are **not automatically recalculated**. Existing checkpoints
|
||||
retain accumulated totals, so subsequent increments use the newly loaded factor;
|
||||
a complete historical rebuild requires a separately planned replay. Persisted
|
||||
snapshots do not gain calibration-version provenance through this change.
|
||||
|
||||
## Current Bento provenance
|
||||
|
||||
On 2026-09-08, an independent gravimetric tray measurement found 4068 g/m² at
|
||||
2.3 m/min with actual rotational signals left 1.65 and right 1.75.
|
||||
`(4068 / 1000) × 2.3 / (1.65 + 1.75) ≈ 2.75188 kg/(rev*m)` gives the configured
|
||||
rounded factor **2.75 kg/(rev*m)**. The original measurement remains recorded,
|
||||
without fitting or adjusting the runtime value to reproduce it exactly.
|
||||
|
||||
Only fresh-bentonite spreaders 1 and 2 are included. Before adding spreader 3,
|
||||
confirm its material scope, actual signal units, independent calibration and
|
||||
whether its output belongs in the fresh-material KPIs. No spreader 3 support is
|
||||
included here.
|
||||
Reference in New Issue
Block a user