---
$schema: "http://json-schema.org/draft-07/schema#"
$id: "https://oimlsmart.org/schemas/R61.yaml"
title: "OIML R61 (Automatic gravimetric filling instruments) Certificate Schema"
description: |
  OIML R61:2017 "Automatic gravimetric filling instruments". Two accuracy
  axes:
    - reference_accuracy_class — the Ref(x) class declared at type test
      (R61-1 §5.2.2), encoded as a Ref() token.
    - accuracy_class — the operational X(x) class declared at putting
      into use (R61-1 §5.2.3), one of the Roman-numeral X class tokens
      X(0.2), X(0.5), X(1), X(2).

  R61-1 §3.1 also defines the load-cell-style accuracy classes I, II, III,
  IIII for the analog data-processing device portion of the system.

type: object
required: [certificate, certified_type, characteristics, recommendation]
properties:
  certificate:           { $ref: "_core.yaml#/definitions/Certificate" }
  issuing_authority:     { $ref: "_core.yaml#/definitions/IssuingAuthority" }
  applicants:            { $ref: "_core.yaml#/definitions/PartyList" }
  manufacturers:         { $ref: "_core.yaml#/definitions/PartyList" }
  certified_type:        { $ref: "#/definitions/CertifiedType" }
  characteristics:       { $ref: "#/definitions/Characteristics" }
  recommendation:
    type: object
    required: [id, edition, scheme]
    properties:
      id:          { type: string, const: R61 }
      edition:     { type: integer, enum: [2017] }
      amendment:   { type: [integer, string, "null"] }
      scheme:      { type: string, enum: [A, B] }
      accuracy_classes:
        description: |
          Flat list of accuracy-class tokens covered by the certificate,
          possibly mixing reference (Ref(x)) and operational (X(x))
          tokens. Per-axis values live in
          `characteristics.type_level.{reference_accuracy_class, accuracy_class}`.
        type: array
        items: { $ref: "#/definitions/AccuracyClassValue" }
  test_reports:          { $ref: "_core.yaml#/definitions/TestReportList" }
  revision_history:      { $ref: "_core.yaml#/definitions/RevisionHistory" }
  model_family:          { $ref: "_core.yaml#/definitions/ModelFamily" }
  components:
    type: array
    items: { $ref: "_core.yaml#/definitions/Component" }
  footnotes:             { $ref: "_core.yaml#/definitions/FootnoteList" }
  matrix_tables:
    type: array
    items:
      type: object
      required: [name, columns, rows]
      properties:
        name: { type: string }
        columns:
          type: array
          items: { type: string }
        rows:
          type: array
          items: { type: object }
        description: { type: string }
        footnotes:
          type: array
          items: { $ref: "_core.yaml#/definitions/Footnote" }
  d011_tests_applicable:
    description: Tests mandated by R61:2017 type evaluation (D 11:2013 subset).
    type: array
    items: { $ref: "#/definitions/D011TestReference" }
    default:
    - { test_id: d011_t06_static_temperature }
    - { test_id: d011_t07_static_temperature }
    - { test_id: d011_t08_damp_heat_steady_state }
    - { test_id: d011_t09_damp_heat_cyclic }
    - { test_id: d011_t11_atmospheric_pressure }
    - { test_id: d011_t18_dc_mains_voltage_variation }
    - { test_id: d011_t20_ac_mains_voltage_variation }
    - { test_id: d011_t22_dc_mains_dips_interruptions }
    - { test_id: d011_t23_ac_mains_dips_interruptions }
    - { test_id: d011_t26_bursts_ac_dc_mains }
    - { test_id: d011_t27_surges_ac_dc_mains }
    - { test_id: d011_t28_bursts_signal_data_control }
    - { test_id: d011_t29_surges_signal_data_control }
    - { test_id: d011_t33_rf_em_fields_general }
    - { test_id: d011_t35_electrostatic_discharges }

definitions:
  ReferenceAccuracyClass:
    description: |
      R61-1 §4.2 + §3.4.11 — reference value for accuracy class Ref(x),
      declared at type test. Per §4.2 the class designation factor x
      shall be ≤ 2 and in the form 1×10^k, 2×10^k, or 5×10^k.
      Canonical classes from R61-1 Table 3: Ref(0.2), Ref(0.5), Ref(1), Ref(2).
    allOf:
    - $ref: "_core.yaml#/definitions/StructuredValue"
    - properties:
        value:
          type: string
          oneOf:
          - const: Ref(0.2)
            description: Reference class 0.2 — best, error ≤ 0.2 %
          - const: Ref(0.5)
            description: Reference class 0.5 — error ≤ 0.5 %
          - const: Ref(1)
            description: Reference class 1 — error ≤ 1 %
          - const: Ref(2)
            description: Reference class 2 — coarsest, error ≤ 2 %
          - const: "N/A"
            description: Not applicable

  OperationalAccuracyClass:
    description: |
      R61-1 §4.2 — operational accuracy class X(x) declared at putting the
      instrument into use. Four canonical classes per R61-1 Table 3.
    allOf:
    - $ref: "_core.yaml#/definitions/StructuredValue"
    - properties:
        value:
          oneOf:
          - type: string
            oneOf:
            - const: X(0.2)
              description: X class 0.2 — best, operational error ≤ 0.2 %
            - const: X(0.5)
              description: X class 0.5 — error ≤ 0.5 %
            - const: X(1)
              description: X class 1 — error ≤ 1 %
            - const: X(2)
              description: X class 2 — coarsest, error ≤ 2 %
            - const: "N/A"
              description: Not applicable
          - type: array
            description: Multi-class instrument (e.g. certified for both X(1) and X(2)).
            minItems: 1
            items:
              type: string
              enum: [X(0.2), X(0.5), X(1), X(2)]

  AccuracyClassValue:
    description: |
      Bare accuracy class token for `recommendation.accuracy_classes`.
      May be either Ref(x) or X(x) form. Per R61-1 §4.2.
    type: string
    oneOf:
    - const: Ref(0.2)
    - const: Ref(0.5)
    - const: Ref(1)
    - const: Ref(2)
    - const: X(0.2)
    - const: X(0.5)
    - const: X(1)
    - const: X(2)
    - const: "N/A"

  MethodOfOperation:
    description: |
      R61-1 §3.2 — method of operation for the filling instrument.
      Accepts canonical token or array of tokens for multi-mode instruments.
    oneOf:
    - type: string
      oneOf:
      - const: filling_by_one_weighing_cycle
        description: Filling by one weighing cycle (direct weighing)
      - const: cumulative_weighing
        description: Cumulative weighing — multiple weighing cycles per fill
      - const: selective_combination_weighing
        description: Selective combination weighing — multi-module computed combination
      - const: subtractive_weighing
        description: Subtractive weighing — dispense by loss-in-weight
      - const: "N/A"
        description: Not applicable
    - allOf:
      - $ref: "_core.yaml#/definitions/StructuredValue"
      - properties:
          value:
            oneOf:
            - type: string
              enum: [filling_by_one_weighing_cycle, cumulative_weighing,
                     selective_combination_weighing, subtractive_weighing, "N/A"]
            - type: array
              minItems: 1
              items:
                type: string
                enum: [filling_by_one_weighing_cycle, cumulative_weighing,
                       selective_combination_weighing, subtractive_weighing]

  InstrumentType:
    description: |
      R61-1 §3.2 — instrument classification. Covers complete AGFIs
      (4 categories per §3.2.2) plus component-level types declared on
      module-only certificates.
    type: [string, "null"]
    anyOf:
    - const: automatic_gravimetric_filling_instrument
      description: General AGFI — automatic gravimetric filling instrument (§3.2.1)
    - const: cumulative_weighing_instrument
      description: Cumulative weighing AGFI — one weighing module, multiple cycles per fill (§3.2.2.1.1)
    - const: selective_combination_weighing_instrument
      description: Selective combination AGFI — multiple modules, computed combination (§3.2.2.1.2)
    - const: subtractive_weighing_instrument
      description: Subtractive AGFI — fill determined by output feed control (§3.2.2.2)
    - const: multi_load_agfi
      description: Multi-load AGFI — uses more than one load per fill (§3.2.2.1)
    - const: weighing_transmitter
      description: Weighing transmitter / digitizing unit (module-only certificate)
    - const: multihead_weigher
      description: Multihead weigher (selective combination variant)
    - const: load_cell_digitizing_unit
      description: Load-cell digitizing unit / analog data processing device (module-only)
    - const: "N/A"
      description: Not applicable
    - const: "Not applicable"
      description: Not applicable (surface form)
    - type: "null"
    # Free-text surface forms from extraction data are accepted (anyOf with
    # the bare type:string below). These should be normalized to canonical
    # tokens by the normalizer.
    - type: string
      description: Free-text instrument description from extraction data

  CertifiedType:
    type: object
    required: [category, type_designations]
    properties:
      category: { type: string }
      type_designations:
        type: array
        minItems: 1
        items: { type: string }
      module_designation:
        $ref: "#/definitions/InstrumentType"
      description: { type: string }

  Characteristics:
    type: object
    properties:
      type_level: { $ref: "#/definitions/TypeLevel" }
      model_level:
        type: array
        items: { $ref: "#/definitions/ModelLevelEntry" }
      config_level:
        type: array
        items: { $ref: "#/definitions/ConfigLevelEntry" }

  TypeLevel:
    type: object
    properties:
      # Two accuracy axes
      reference_accuracy_class:        { $ref: "#/definitions/ReferenceAccuracyClass" }
      reference_class:                 { $ref: "#/definitions/ReferenceAccuracyClass" }
      accuracy_class:                  { $ref: "#/definitions/OperationalAccuracyClass" }
      # Environmental
      temperature_range:               { $ref: "_modules/d011_environmental.yaml#/definitions/TemperatureRange" }
      operational_temperature:         { $ref: "_core.yaml#/definitions/StructuredValue" }
      humidity_class:                  { $ref: "_modules/d011_environmental.yaml#/definitions/ClimaticClass" }
      electromagnetic_environment_class: { $ref: "_modules/d011_environmental.yaml#/definitions/EMClass" }
      mechanical_environment_class:    { $ref: "_modules/d011_environmental.yaml#/definitions/MechanicalClass" }
      climatic_environment_humidity_indicator:           { $ref: "_core.yaml#/definitions/StructuredValue" }
      climatic_environment_humidity_mechanical_assembly: { $ref: "_core.yaml#/definitions/StructuredValue" }
      climatic_environment_humidity_adpd_ddpd:           { $ref: "_core.yaml#/definitions/StructuredValue" }
      climatic_environment_intended_location_closed:                { $ref: "_core.yaml#/definitions/StructuredValue" }
      climatic_environment_intended_location_open_and_closed:       { $ref: "_core.yaml#/definitions/StructuredValue" }
      # Weighing parameters
      maximum_capacity:                { $ref: "_core.yaml#/definitions/StructuredValue" }
      minimum_capacity:                { $ref: "_core.yaml#/definitions/StructuredValue" }
      scale_interval:                  { $ref: "_core.yaml#/definitions/StructuredValue" }
      number_of_scale_intervals:       { $ref: "_core.yaml#/definitions/StructuredValue" }
      measuring_range:                 { $ref: "_core.yaml#/definitions/StructuredValue" }
      tare:                            { $ref: "_core.yaml#/definitions/StructuredValue" }
      weighing_range:                  { $ref: "_core.yaml#/definitions/StructuredValue" }
      weighing_ranges:                 { $ref: "_core.yaml#/definitions/StructuredValue" }
      maximum_tare_effect:             { $ref: "_core.yaml#/definitions/StructuredValue" }
      maximum_number_of_verification_scale_intervals_ni:    { $ref: "_core.yaml#/definitions/StructuredValue" }
      maximum_number_of_verification_scale_intervals_n:     { $ref: "_core.yaml#/definitions/StructuredValue" }
      maximum_number_of_scale_intervals: { $ref: "_core.yaml#/definitions/StructuredValue" }
      maximum_capacity_of_interval_max_i: { $ref: "_core.yaml#/definitions/StructuredValue" }
      initial_zero_setting_range:      { $ref: "_core.yaml#/definitions/StructuredValue" }
      fractional_factor_pi:            { $ref: "_core.yaml#/definitions/StructuredValue" }
      minimum_input_voltage_per_vsi:   { $ref: "_core.yaml#/definitions/StructuredValue" }
      minimum_input_voltage_per_vsi_ei: { $ref: "_core.yaml#/definitions/StructuredValue" }
      maximum_time_between_automatic_zero_setting: { $ref: "_core.yaml#/definitions/StructuredValue" }
      load_cell_interface:             { $ref: "_core.yaml#/definitions/StructuredValue" }
      minimum_input_impedance:         { $ref: "_core.yaml#/definitions/StructuredValue" }
      maximum_input_impedance:         { $ref: "_core.yaml#/definitions/StructuredValue" }
      minimum_input_voltage_from_load_cell: { $ref: "_core.yaml#/definitions/StructuredValue" }
      maximum_input_voltage_from_load_cell: { $ref: "_core.yaml#/definitions/StructuredValue" }
      circuit_for_remote_sense:        { $ref: "_core.yaml#/definitions/StructuredValue" }
      load_cell_linearization_feature: { $ref: "_core.yaml#/definitions/StructuredValue" }
      connecting_cable_to_load_cells:  { $ref: "_core.yaml#/definitions/StructuredValue" }
      number_of_load_receptors:        { $ref: "_core.yaml#/definitions/StructuredValue" }
      maximum_number_of_load_receptors: { $ref: "_core.yaml#/definitions/StructuredValue" }
      maximum_capacity_of_each_load_receptor: { $ref: "_core.yaml#/definitions/StructuredValue" }
      # Two-station filler characteristics
      maximum_capacity_main_station:   { $ref: "_core.yaml#/definitions/StructuredValue" }
      maximum_capacity_top_up_station: { $ref: "_core.yaml#/definitions/StructuredValue" }
      minimum_capacity_main_station:   { $ref: "_core.yaml#/definitions/StructuredValue" }
      minimum_capacity_top_up_station: { $ref: "_core.yaml#/definitions/StructuredValue" }
      rated_minimum_fill:              { $ref: "_core.yaml#/definitions/StructuredValue" }
      maximum_fill:                    { $ref: "_core.yaml#/definitions/StructuredValue" }
      # Operation
      type:                            { $ref: "_core.yaml#/definitions/StructuredValue" }
      method_of_operation:             { $ref: "#/definitions/MethodOfOperation" }
      indicator_option1:               { $ref: "_core.yaml#/definitions/StructuredValue" }
      indicator_option2:               { $ref: "_core.yaml#/definitions/StructuredValue" }
      # Power
      power_supply_voltage:            { $ref: "_core.yaml#/definitions/StructuredValue" }
      power_supply_frequency:          { $ref: "_core.yaml#/definitions/StructuredValue" }
      power_supply_type:               { $ref: "_core.yaml#/definitions/StructuredValue" }
      power_supply_battery:            { $ref: "_core.yaml#/definitions/StructuredValue" }
      mains_power_supply:              { $ref: "_core.yaml#/definitions/StructuredValue" }
      mains_power_supply_voltage:      { $ref: "_core.yaml#/definitions/StructuredValue" }
      mains_power_supply_restriction:  { $ref: "_core.yaml#/definitions/StructuredValue" }
      supply_voltage:                  { $ref: "_core.yaml#/definitions/StructuredValue" }
      # Warm-up / adjustment
      warm_up_time:                    { $ref: "_core.yaml#/definitions/StructuredValue" }
      minimum_warm_up_time:            { $ref: "_core.yaml#/definitions/StructuredValue" }
      adjustment_period:               { $ref: "_core.yaml#/definitions/StructuredValue" }
      # Software
      software_identification:         { $ref: "_core.yaml#/definitions/SoftwareIdentification" }
      software_identification_monitor_sw_version: { $ref: "_core.yaml#/definitions/StructuredValue" }
      software_identification_brainsbox_sw_versie: { $ref: "_core.yaml#/definitions/StructuredValue" }
      software_identification_measurement_electronics: { $ref: "_core.yaml#/definitions/StructuredValue" }
      # Analog data-processing-device-specific (Roman-numeral accuracy class)
      analog_data_processing_device_accuracy_class:                       { $ref: "_core.yaml#/definitions/StructuredValue" }
      analog_data_processing_device_weighing_range:                       { $ref: "_core.yaml#/definitions/StructuredValue" }
      analog_data_processing_device_maximum_number_of_scale_intervals:    { $ref: "_core.yaml#/definitions/StructuredValue" }
      analog_data_processing_device_load_cell_excitation_voltage:         { $ref: "_core.yaml#/definitions/StructuredValue" }
      analog_data_processing_device_minimum_signal_input_voltage:         { $ref: "_core.yaml#/definitions/StructuredValue" }
      analog_data_processing_device_minimum_input_voltage_per_verification_scale_interval: { $ref: "_core.yaml#/definitions/StructuredValue" }
      analog_data_processing_device_minimum_load_cell_resistance:         { $ref: "_core.yaml#/definitions/StructuredValue" }
      analog_data_processing_device_maximum_load_cell_resistance:         { $ref: "_core.yaml#/definitions/StructuredValue" }
      analog_data_processing_device_fraction_of_the_maximum_permissible_error: { $ref: "_core.yaml#/definitions/StructuredValue" }
      analog_data_processing_device_load_cell_interface:                  { $ref: "_core.yaml#/definitions/StructuredValue" }
      analog_data_processing_device_maximum_value_of_the_cable_length_per_cross_wire_section: { $ref: "_core.yaml#/definitions/StructuredValue" }
      # Cable / mounting
      maximum_cable_length_between_er500_f_and_junction_box: { $ref: "_core.yaml#/definitions/StructuredValue" }
      load_cell_excitation_voltage:    { $ref: "_core.yaml#/definitions/StructuredValue" }
      minimum_load_cell_impedance:     { $ref: "_core.yaml#/definitions/StructuredValue" }
      maximum_load_cell_impedance:     { $ref: "_core.yaml#/definitions/StructuredValue" }

  ModelLevelEntry:
    type: object
    required: [attribute, values]
    properties:
      attribute: { type: string }
      unit:
        $ref: "_units.yaml#/definitions/Unit"
      values:
        type: array
        items:
          type: object
          required: [model, value]
          properties:
            model:            { type: string }
            value:            { $ref: "_core.yaml#/definitions/ValueOrScalar" }
            footnote_markers:
              type: array
              items: { type: string }

  ConfigLevelEntry:
    type: object
    required: [attribute, axis, values]
    properties:
      attribute: { type: string }
      axis:      { oneOf: [ { type: string }, { type: "null" } ] }
      unit:
        $ref: "_units.yaml#/definitions/Unit"
      values:
        type: array
        items:
          type: object
          required: [value]
          properties:
            condition: { type: string }
            model:     { type: string }
            value:     { $ref: "_core.yaml#/definitions/ValueOrScalar" }

  D011TestReference:
    description: Reference to an OIML D 11:2013 performance test.
    type: object
    required: [test_id]
    properties:
      test_id:          { type: string, pattern: '^d011_t\d{2}_' }
      test_level_index: { type: integer, minimum: 1, maximum: 5 }
      notes:            { type: string }

allOf:
- description: |
    D 11 §9.2 damp-heat tests apply per humidity class:
    H2 → t08 (steady state); H3 → t09 (cyclic).
  if:
    properties:
      characteristics:
        properties:
          type_level:
            properties:
              humidity_class:
                properties:
                  value: { const: H2 }
  then:
    properties:
      d011_tests_applicable:
        contains: { properties: { test_id: { const: d011_t08_damp_heat_steady_state } } }
- if:
    properties:
      characteristics:
        properties:
          type_level:
            properties:
              humidity_class:
                properties:
                  value: { const: H3 }
  then:
    properties:
      d011_tests_applicable:
        contains: { properties: { test_id: { const: d011_t09_damp_heat_cyclic } } }
