Measurements

Create measurements to capture and validate data within phases.

OpenHTF Device Under Test (DUT) documentation section header with TofuPilot.

Overview

Hardware tests are more complex than simple pass/fail checks like in software testing. They often require measuring physical values and comparing them to limits. OpenHTF simplifies logging and validating numeric, string, and boolean values, either individually or in arrays, using built-in decorators.

With the TofuPilot integration, you get control charts and histograms to compare measurements across test runs.

Numeric

You can define and validate numeric measurements.

main.py

import openhtf as htf
from openhtf.util import units

@htf.measures(
    htf.Measurement("temperature")     # Declares the measurement name
    .in_range(0, 100)                  # Defines the validator
    .with_units(units.DEGREE_CELSIUS)  # Specifies the unit
    .with_precision(1)                 # Rounds to 1 decimal place
)
def phase_temperature(test):
    test.measurements.temperature = 25 # Set the temperature value to 25°C

def main():
    test = htf.Test(phase_temperature)
    test.execute(lambda: "PCB001")

if __name__ == "__main__":
    main()

Validators

  • Name
    .in_range(minimum, maximum)
    Type
    number, number
    Description

    Ensure the measurement is within the given range.

  • Name
    .within_percent(value, percent)
    Type
    number, number
    Description

    Ensure the measurement is within the given percentage range.

  • Name
    .equals(value)
    Type
    number
    Description

    Ensure the measurement exactly matches the specified value.

  • Name
    .with_validator(lambda)
    Type
    function → bool
    Description

    Apply a custom validator function to the measurement.

Options

  • Name
    .with_units(units)
    Type
    UnitDescriptor
    Description

    Define unit to the measurement (e.g. AMPERE, VOLT, full list here).

  • Name
    .with_precision(precision)
    Type
    int
    Description

    Round the value to the specified precision before validation.

main.py

import openhtf as htf
from openhtf.util import units

@htf.measures(
    htf.Measurement("voltage")
    .in_range(maximum=10)
    .with_units(units.VOLT)
)
def phase_voltage(test):
    test.measurements.voltage = 5.3

@htf.measures(
    htf.Measurement("memory")
    .equals(8)
    .with_units(units.GIGABYTE)
)
def phase_memory(test):
    test.measurements.memory = 8

def main():
    test = htf.Test(phase_voltage, phase_memory)
    test.execute(lambda: "PCB001")

if __name__ == "__main__":
    main()

String

You can define and validate string measurements.

main.py

import openhtf as htf
from openhtf.util import units

@htf.measures(
    htf.Measurement("firmware_version")
    .equals("1.2.4")
)
def phase_firmware(test):
    test.measurements.firmware_version = "1.2.4"

def main():
    test = htf.Test(phase_firmware)
    test.execute(lambda: "PCB001")

if __name__ == "__main__":
    main()

Validators

  • Name
    .equals(value)
    Type
    str
    Description

    Ensure the measurement exactly matches the specified value.

  • Name
    .matches_regex(pattern)
    Type
    str
    Description

    Ensure the string matches the specified regex pattern.

  • Name
    .with_validator(lambda)
    Type
    function → bool
    Description

    Apply a custom validator function to the measurement.

Boolean

You can define and validate boolean measurements.

main.py

import openhtf as htf

@htf.measures(
    htf.Measurement("is_led_switch_on")
    .equals(True)
)
def phase_led(test):
    test.measurements.is_led_switch_on = True

def main():
    test = htf.Test(phase_led)
    test.execute(lambda: "PCB001")

if __name__ == "__main__":
    main()

Validators

  • Name
    .equals(value)
    Type
    bool
    Description

    Ensure the measurement exactly matches the specified value.

  • Name
    .with_validator(lambda)
    Type
    function → bool
    Description

    Apply a custom validator function to the measurement.

Multiple measurements

You can also use multiple measurements in a single phase.

main.py

import openhtf as htf
from openhtf.util import units

@htf.measures(
    htf.Measurement("is_connected").equals(True),
    htf.Measurement("firmware_version").equals("1.2.7"),
    htf.Measurement("temperature").in_range(0, 100).with_units(units.DEGREE_CELSIUS),
)
def phase_multi_measurements(test):
    test.measurements.is_connected = True
    test.measurements.firmware_version = "1.2.7" if test.measurements.is_connected else "N/A"
    test.measurements.temperature = 22.5

def main():
    test = htf.Test(phase_multi_measurements)
    test.execute(lambda: "PCB001")

if __name__ == "__main__":
    main()

TofuPilot integration

The TofuPilot integration is natively compatible with OpenHTF phases and measurements.

To integrate TofuPilot, install the open-source client:

pip install tofupilot

Add it to your test like this:

main.py

import openhtf as htf
from openhtf.util import units
from tofupilot.openhtf import TofuPilot

def phase_one(test):
    return htf.PhaseResult.CONTINUE

@htf.measures(
    htf.Measurement("temperature")
    .in_range(0, 100)
    .with_units(units.DEGREE_CELSIUS)
)
def phase_temperature(test):
    test.measurements.temperature = 25

def main():
    test = htf.Test(phase_one, phase_temperature)
    with TofuPilot(test):                          # just works™️
        test.execute(lambda: "PCB001")

if __name__ == "__main__":
    main()

You can visualize the test measurements (referred to as steps) on each run page.

Run page showing the different steps performed for a Unit Under Test (UUT) in OpenHTF with TofuPilot.

You can display control charts and histograms for a measurement to track its evolution across test runs.

Procedure page showing the control chart for a specific numeric measure for several Unit Under Test (UUT) in OpenHTF with TofuPilot

You can access more phase performance indicators on TofuPilot and filter test runs by date, revision, and other criteria.

Learn more in the TofuPilot Docs

Advanced use cases

You can leverage advanced OpenHTF options to handle complex measurement use cases.

Multidimensional

You can capture data in arrays, like time-series or across categories, with multidimensional measurements.

main.py

import openhtf as htf
from openhtf.util import units
import random
import time

@htf.measures(
    htf.Measurement("voltage_over_time")
    .with_dimensions(units.SECOND, units.VOLT)
)
def phase_voltage_measurement(test):
    for t in range(10):
        timestamp = t
        voltage = round(random.uniform(3.3, 3.5), 2)
        test.measurements.voltage_over_time[timestamp, voltage] = 0
        time.sleep(0.1)

def main():
    test = htf.Test(phase_voltage_measurement)
    test.execute(lambda: "PCB001")

if __name__ == "__main__":
    main()

Options

  • Name
    .with_dimensions(*dims)
    Type
    UnitDescriptor
    Description

    Set multiple units for multidimensional measurements.

Marginal

You can mark a measure as marginal to show it’s close to failing, even if it passes.

main.py

import openhtf as htf
from openhtf.util import units

@htf.measures(
    htf.Measurement('resistance')
    .with_units('ohm')
    .in_range(minimum=5, maximum=17, marginal_minimum=9, marginal_maximum=11)
)
def phase_marginal(test):
  test.measurements.resistance = 13

def main():
    test = htf.Test(phase_marginal)
    test.execute(lambda: "PCB001")

if __name__ == "__main__":
    main()

Terminal

================= test: openhtf_test  outcome: PASS (MARGINAL) =================

Documentation

You can add a description to your measurements.

main.py

import openhtf as htf

@htf.measures(
    htf.Measurement("temperature")
    .in_range(0, 100)
    .doc("This measurement tracks the ambient temperature during the test.")
)
def phase_temperature(test):
    test.measurements.temperature = 25

def main():
    test = htf.Test(phase_temperature)
    test.execute(lambda: "PCB001")

if __name__ == "__main__":
    main()

Dynamic naming

You can customize measurement names dynamically at execution.

main.py

import openhtf as htf

@htf.measures(
    htf.Measurement("test_result_{level}")
    .with_args(level="high")
    .equals(True)
)
def phase_test(test):
    test.measurements.test_result_high = True

def main():
    test = htf.Test(phase_test)
    test.execute(lambda: "PCB001")

if __name__ == "__main__":
    main()

Transformation function

You can apply measurement transformation functions before validation.

main.py

import openhtf as htf

@htf.measures(
    htf.Measurement("voltage")
    .in_range(0, 10)
    .with_transform(lambda x: x * 1.1)
    .with_units("V")
)
def phase_voltage(test):
    test.measurements.voltage = 5  # Value will be transformed to 5.5 before validation

def main():
    test = htf.Test(phase_voltage)
    test.execute(lambda: "PCB001")

if __name__ == "__main__":
    main()

Was this page helpful?