units

package
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 19, 2026 License: MIT Imports: 3 Imported by: 0

Documentation

Overview

Package units provides type-safe unit conversion for physical quantities commonly encountered in marine (NMEA 2000) and general-purpose sensor systems.

Architecture overview:

Each physical quantity (distance, velocity, pressure, etc.) is represented by its own struct type (e.g., Distance, Velocity, Pressure) that wraps a numeric value and a unit enum. This ensures type safety at compile time -- you cannot accidentally add a Distance to a Velocity.

Most unit types use a "table-based conversion" approach (see tablebasedconversion.go) where each unit has a numeric ratio relative to a common reference unit. Conversion between any two units is done by multiplying: value * (newConv / oldConv). This works for all linear unit relationships. Temperature is the notable exception, as Fahrenheit/Celsius conversions involve offsets (not just ratios), so Temperature uses custom conversion logic.

Each unit type provides:

  • A constructor (e.g., NewDistance)
  • Convert() to change units
  • Add() and Sub() for arithmetic that handles mixed units
  • MarshalJSON() for serialization with unit type metadata

The UnitType enum is used in JSON serialization to identify which physical quantity a value represents, enabling generic handling by user interfaces, telemetry services, and stored data formats.

Relationship to PGN decoding: this package is not currently consumed by the pgn decode path. Decoded PGN struct fields hold raw wire ticks (*uint64/*int64); pgn.PhysicalValue applies a field's Resolution and Offset to produce a plain float64 physical value plus a unit string, but it does not construct units types, and no PGN struct field uses a units type. Integrating units into decoding would mean switching PGN struct fields from raw-tick integers to float-based quantities (each Unit[T] wraps a float32), which is a larger, cross-cutting change to the generated struct shapes and is deliberately deferred; for now, callers that want a units value construct one themselves from pgn.PhysicalValue's (float64, unit string) result.

Index

Constants

This section is empty.

Variables

View Source
var ErrInvalidDistanceUnit = errors.New("not a valid DistanceUnit")
View Source
var ErrInvalidFlowUnit = errors.New("not a valid FlowUnit")
View Source
var ErrInvalidPressureUnit = errors.New("not a valid PressureUnit")
View Source
var ErrInvalidTemperatureUnit = errors.New("not a valid TemperatureUnit")
View Source
var ErrInvalidUnitType = errors.New("not a valid UnitType")
View Source
var ErrInvalidVelocityUnit = errors.New("not a valid VelocityUnit")
View Source
var ErrInvalidVolumeUnit = errors.New("not a valid VolumeUnit")

Functions

This section is empty.

Types

type Distance

type Distance Unit[DistanceUnit]

Distance is a type-safe unit structure that represents a distance/length measurement. It combines a numeric value with a DistanceUnit to ensure correct unit handling.

func NewDistance

func NewDistance(u DistanceUnit, value float32) Distance

NewDistance creates a new Distance value with the given unit and magnitude.

Parameters:

  • u: the distance unit (Meter, Foot, Mile, NauticalMile, or Fathom)
  • value: the numeric magnitude in the specified unit

func (Distance) Add

func (p Distance) Add(o Distance) Distance

Add adds another Distance to this one, returning a new Distance in this value's unit. If the other Distance is in a different unit, it is automatically converted before adding. The result preserves the receiver's unit.

func (Distance) Convert

func (p Distance) Convert(newUnit DistanceUnit) Distance

Convert converts this distance value to a different distance unit, returning a new Distance. Uses the table-based conversion system (distanceConversions) for the math.

Parameters:

  • newUnit: the target distance unit to convert to

Returns a new Distance in the requested unit.

func (Distance) MarshalJSON

func (u Distance) MarshalJSON() ([]byte, error)

MarshalJSON implements a custom JSON marshaler that includes the UnitType discriminator. The output includes "value", "unit" (as the integer enum value), and "unitType" (as the UnitType enum value for Distance). This allows JSON consumers to identify this as a distance measurement and determine the specific unit.

func (Distance) Multiply

func (p Distance) Multiply(by float32) Distance

Multiply scales this distance by a scalar factor, returning a new Distance in the same unit. This is useful for operations like "double the distance" or "take half the distance".

Parameters:

  • by: the scalar multiplier (e.g., 2.0 to double, 0.5 to halve)

func (Distance) Sub

func (p Distance) Sub(o Distance) Distance

Sub subtracts another Distance from this one, returning a new Distance in this value's unit. If the other Distance is in a different unit, it is automatically converted before subtracting. The result preserves the receiver's unit.

type DistanceUnit

type DistanceUnit int

DistanceUnit is an enum for all supported distance/length unit types. ENUM(Meter, Foot, Mile, NauticalMile, Fathom) Meter is a meter Foot is a foot Mile is a mile NauticalMile is a nautical mile Fathom is a fathom

const (
	// Meter is a DistanceUnit of type Meter.
	Meter DistanceUnit = iota
	// Foot is a DistanceUnit of type Foot.
	Foot
	// Mile is a DistanceUnit of type Mile.
	Mile
	// NauticalMile is a DistanceUnit of type NauticalMile.
	NauticalMile
	// Fathom is a DistanceUnit of type Fathom.
	Fathom
)

func DistanceUnitValues

func DistanceUnitValues() []DistanceUnit

DistanceUnitValues returns a list of the values for DistanceUnit

func ParseDistanceUnit

func ParseDistanceUnit(name string) (DistanceUnit, error)

ParseDistanceUnit attempts to convert a string to a DistanceUnit.

func (DistanceUnit) IsValid

func (x DistanceUnit) IsValid() bool

IsValid provides a quick way to determine if the typed value is part of the allowed enumerated values

func (DistanceUnit) String

func (x DistanceUnit) String() string

String implements the Stringer interface.

type Flow

type Flow Unit[FlowUnit]

Flow is a type-safe unit structure that represents a flow rate measurement (volume over time). It combines a numeric value with a FlowUnit to ensure correct unit handling. This is commonly used for fuel flow rates in marine applications.

func NewFlow

func NewFlow(u FlowUnit, value float32) Flow

NewFlow creates a new Flow value with the given unit and magnitude.

Parameters:

  • u: the flow unit (LitersPerHour, GallonsPerMinute, or GallonsPerHour)
  • value: the numeric magnitude in the specified unit

func (Flow) Add

func (p Flow) Add(o Flow) Flow

Add adds another Flow to this one, returning a new Flow in this value's unit. If the other Flow is in a different unit, it is automatically converted before adding. The result preserves the receiver's unit.

func (Flow) Convert

func (p Flow) Convert(newUnit FlowUnit) Flow

Convert converts this flow value to a different flow unit, returning a new Flow. Uses the table-based conversion system (flowConversions) for the math.

Parameters:

  • newUnit: the target flow unit to convert to

Returns a new Flow in the requested unit.

func (Flow) MarshalJSON

func (u Flow) MarshalJSON() ([]byte, error)

MarshalJSON implements a custom JSON marshaler that includes the UnitType discriminator. The output includes "value", "unit" (as the integer enum value), and "unitType" (as the UnitType enum value for Flow). This allows JSON consumers to identify this as a flow rate measurement and determine the specific unit.

func (Flow) Sub

func (p Flow) Sub(o Flow) Flow

Sub subtracts another Flow from this one, returning a new Flow in this value's unit. If the other Flow is in a different unit, it is automatically converted before subtracting. The result preserves the receiver's unit.

type FlowUnit

type FlowUnit int

FlowUnit is an enum for all supported flow rate unit types. ENUM(LitersPerHour, GallonsPerMinute, GallonsPerHour) LitersPerHour is L/hr GallonsPerMinute is Gal/min GallonsPerHour is Gal/hr

const (
	// LitersPerHour is a FlowUnit of type LitersPerHour.
	LitersPerHour FlowUnit = iota
	// GallonsPerMinute is a FlowUnit of type GallonsPerMinute.
	GallonsPerMinute
	// GallonsPerHour is a FlowUnit of type GallonsPerHour.
	GallonsPerHour
)

func FlowUnitValues

func FlowUnitValues() []FlowUnit

FlowUnitValues returns a list of the values for FlowUnit

func ParseFlowUnit

func ParseFlowUnit(name string) (FlowUnit, error)

ParseFlowUnit attempts to convert a string to a FlowUnit.

func (FlowUnit) IsValid

func (x FlowUnit) IsValid() bool

IsValid provides a quick way to determine if the typed value is part of the allowed enumerated values

func (FlowUnit) String

func (x FlowUnit) String() string

String implements the Stringer interface.

type Pressure

type Pressure Unit[PressureUnit]

Pressure is a type-safe unit structure that represents a pressure measurement. It combines a numeric value with a PressureUnit to ensure correct unit handling.

func NewPressure

func NewPressure(u PressureUnit, value float32) Pressure

NewPressure creates a new Pressure value with the given unit and magnitude.

Parameters:

  • u: the pressure unit (Pa, Psi, or Hpa)
  • value: the numeric magnitude in the specified unit

func (Pressure) Add

func (p Pressure) Add(o Pressure) Pressure

Add adds another Pressure to this one, returning a new Pressure in this value's unit. If the other Pressure is in a different unit, it is automatically converted before adding. The result preserves the receiver's unit.

func (Pressure) Convert

func (p Pressure) Convert(newUnit PressureUnit) Pressure

Convert converts this pressure value to a different pressure unit, returning a new Pressure. Uses the table-based conversion system (pressureConversions) for the math.

Parameters:

  • newUnit: the target pressure unit to convert to

Returns a new Pressure in the requested unit.

func (Pressure) MarshalJSON

func (u Pressure) MarshalJSON() ([]byte, error)

MarshalJSON implements a custom JSON marshaler that includes the UnitType discriminator. The output includes "value", "unit" (as the integer enum value), and "unitType" (as the UnitType enum value for Pressure). This allows JSON consumers to identify this as a pressure measurement and determine the specific unit.

func (Pressure) Sub

func (p Pressure) Sub(o Pressure) Pressure

Sub subtracts another Pressure from this one, returning a new Pressure in this value's unit. If the other Pressure is in a different unit, it is automatically converted before subtracting. The result preserves the receiver's unit.

type PressureUnit

type PressureUnit int

PressureUnit is an enum for all supported pressure unit types. ENUM(Pa, Psi, Hpa) Psi is PSI (pounds per square inch) Hpa is HectoPascals (100 Pascals) Pa is Pascals

const (
	// Pa is a PressureUnit of type Pa.
	Pa PressureUnit = iota
	// Psi is a PressureUnit of type Psi.
	Psi
	// Hpa is a PressureUnit of type Hpa.
	Hpa
)

func ParsePressureUnit

func ParsePressureUnit(name string) (PressureUnit, error)

ParsePressureUnit attempts to convert a string to a PressureUnit.

func PressureUnitValues

func PressureUnitValues() []PressureUnit

PressureUnitValues returns a list of the values for PressureUnit

func (PressureUnit) IsValid

func (x PressureUnit) IsValid() bool

IsValid provides a quick way to determine if the typed value is part of the allowed enumerated values

func (PressureUnit) String

func (x PressureUnit) String() string

String implements the Stringer interface.

type Temperature

type Temperature Unit[TemperatureUnit]

Temperature is a type-safe unit structure that represents a temperature measurement. Unlike other unit types in this package, Temperature does NOT use the table-based conversion system because temperature conversions involve offsets (not just ratios). For example, Celsius = Kelvin - 273.15 and Fahrenheit = Kelvin * 9/5 - 459.67. These cannot be expressed as simple ratio tables.

func NewTemperature

func NewTemperature(u TemperatureUnit, value float32) Temperature

NewTemperature creates a new Temperature value with the given unit and magnitude.

Parameters:

  • u: the temperature unit (Kelvin, Fahrenheit, or Celsius)
  • value: the numeric magnitude in the specified unit

func (Temperature) Convert

func (p Temperature) Convert(newUnit TemperatureUnit) Temperature

Convert converts this temperature value to a different temperature unit, returning a new Temperature.

Unlike other unit types that use table-based conversion (simple ratio multiplication), temperature conversion requires a two-step process using Kelvin as the intermediate/base unit:

  1. Convert the current value to Kelvin (the SI base unit for temperature)
  2. Convert from Kelvin to the target unit

Conversion formulas:

  • Celsius to Kelvin: K = C + 273.15
  • Fahrenheit to Kelvin: K = (F + 459.67) * 5/9
  • Kelvin to Celsius: C = K - 273.15
  • Kelvin to Fahrenheit: F = K * 9/5 - 459.67

Parameters:

  • newUnit: the target temperature unit to convert to

Returns a new Temperature in the requested unit. Panics if either the current or target unit is an unknown TemperatureUnit value.

func (Temperature) MarshalJSON

func (u Temperature) MarshalJSON() ([]byte, error)

MarshalJSON implements a custom JSON marshaler that includes the UnitType discriminator. The output includes "value", "unit" (as the integer enum value), and "unitType" (as the UnitType enum value for Temperature). This allows JSON consumers to identify this as a temperature measurement and determine the specific unit.

type TemperatureUnit

type TemperatureUnit int

TemperatureUnit is an enum for all supported temperature unit types. ENUM(Kelvin, Fahrenheit, Celsius)

const (
	// Kelvin is a TemperatureUnit of type Kelvin.
	Kelvin TemperatureUnit = iota
	// Fahrenheit is a TemperatureUnit of type Fahrenheit.
	Fahrenheit
	// Celsius is a TemperatureUnit of type Celsius.
	Celsius
)

func ParseTemperatureUnit

func ParseTemperatureUnit(name string) (TemperatureUnit, error)

ParseTemperatureUnit attempts to convert a string to a TemperatureUnit.

func TemperatureUnitValues

func TemperatureUnitValues() []TemperatureUnit

TemperatureUnitValues returns a list of the values for TemperatureUnit

func (TemperatureUnit) IsValid

func (x TemperatureUnit) IsValid() bool

IsValid provides a quick way to determine if the typed value is part of the allowed enumerated values

func (TemperatureUnit) String

func (x TemperatureUnit) String() string

String implements the Stringer interface.

type Unit

type Unit[T ~int] struct {
	// Value is the numeric magnitude of the measurement in whatever unit Unit specifies.
	Value float32

	// Unit identifies which unit the Value is expressed in (e.g., Meter, Foot, Knots, etc.).
	// The catalog type depends on the physical quantity (DistanceUnit, VelocityUnit, etc.).
	Unit T
}

Unit is the generic base type that all specific unit structs (Distance, Velocity, etc.) are built from. It pairs a numeric value with a unit enum.

The type parameter T is constrained to ~int, which means it must be an int-based enum type (like DistanceUnit, VelocityUnit, etc.). This enables compile-time type safety: each physical quantity uses its own enum type, preventing accidental mixing.

type UnitType

type UnitType int

UnitType is an enum that identifies the category of physical quantity (distance, flow, etc.). It is included in JSON output so consumers can determine what kind of unit a value represents without needing to know the specific unit variant.

ENUM(Distance,Flow,Pressure,Temperature,Velocity,Volume)

const (
	// UnitTypeDistance is a UnitType of type Distance.
	UnitTypeDistance UnitType = iota
	// UnitTypeFlow is a UnitType of type Flow.
	UnitTypeFlow
	// UnitTypePressure is a UnitType of type Pressure.
	UnitTypePressure
	// UnitTypeTemperature is a UnitType of type Temperature.
	UnitTypeTemperature
	// UnitTypeVelocity is a UnitType of type Velocity.
	UnitTypeVelocity
	// UnitTypeVolume is a UnitType of type Volume.
	UnitTypeVolume
)

func ParseUnitType

func ParseUnitType(name string) (UnitType, error)

ParseUnitType attempts to convert a string to a UnitType.

func UnitTypeValues

func UnitTypeValues() []UnitType

UnitTypeValues returns a list of the values for UnitType

func (UnitType) IsValid

func (x UnitType) IsValid() bool

IsValid provides a quick way to determine if the typed value is part of the allowed enumerated values

func (UnitType) String

func (x UnitType) String() string

String implements the Stringer interface.

type Velocity

type Velocity Unit[VelocityUnit]

Velocity is a type-safe unit structure that represents a speed/velocity measurement. It combines a numeric value with a VelocityUnit to ensure correct unit handling.

func NewVelocity

func NewVelocity(u VelocityUnit, value float32) Velocity

NewVelocity creates a new Velocity value with the given unit and magnitude.

Parameters:

  • u: the velocity unit (MetersPerSecond, Knots, Mph, or Kph)
  • value: the numeric magnitude in the specified unit

func (Velocity) Add

func (p Velocity) Add(o Velocity) Velocity

Add adds another Velocity to this one, returning a new Velocity in this value's unit. If the other Velocity is in a different unit, it is automatically converted before adding. The result preserves the receiver's unit.

func (Velocity) Convert

func (p Velocity) Convert(newUnit VelocityUnit) Velocity

Convert converts this velocity value to a different velocity unit, returning a new Velocity. Uses the table-based conversion system (velocityConversions) for the math.

Parameters:

  • newUnit: the target velocity unit to convert to

Returns a new Velocity in the requested unit.

func (Velocity) MarshalJSON

func (u Velocity) MarshalJSON() ([]byte, error)

MarshalJSON implements a custom JSON marshaler that includes the UnitType discriminator. The output includes "value", "unit" (as the integer enum value), and "unitType" (as the UnitType enum value for Velocity). This allows JSON consumers to identify this as a velocity measurement and determine the specific unit.

func (Velocity) Sub

func (p Velocity) Sub(o Velocity) Velocity

Sub subtracts another Velocity from this one, returning a new Velocity in this value's unit. If the other Velocity is in a different unit, it is automatically converted before subtracting. The result preserves the receiver's unit.

func (Velocity) TimesTime

func (v Velocity) TimesTime(seconds float32) Distance

TimesTime computes a distance by multiplying this velocity by a duration in seconds. This implements the physics formula: distance = velocity * time.

The calculation works by first converting the velocity to knots, then multiplying by the time in hours (seconds / 3600) to get a distance in nautical miles. This is the natural unit pairing for marine applications: knots * hours = nautical miles.

Parameters:

  • seconds: the duration in seconds to multiply by

Returns a Distance in NauticalMile units.

Example: 10 knots * 1800 seconds (30 minutes) = 5 nautical miles

type VelocityUnit

type VelocityUnit int

VelocityUnit is an enum for all supported velocity/speed unit types. ENUM(MetersPerSecond, Knots, Mph, Kph)

const (
	// MetersPerSecond is a VelocityUnit of type MetersPerSecond.
	MetersPerSecond VelocityUnit = iota
	// Knots is a VelocityUnit of type Knots.
	Knots
	// Mph is a VelocityUnit of type Mph.
	Mph
	// Kph is a VelocityUnit of type Kph.
	Kph
)

func ParseVelocityUnit

func ParseVelocityUnit(name string) (VelocityUnit, error)

ParseVelocityUnit attempts to convert a string to a VelocityUnit.

func VelocityUnitValues

func VelocityUnitValues() []VelocityUnit

VelocityUnitValues returns a list of the values for VelocityUnit

func (VelocityUnit) IsValid

func (x VelocityUnit) IsValid() bool

IsValid provides a quick way to determine if the typed value is part of the allowed enumerated values

func (VelocityUnit) String

func (x VelocityUnit) String() string

String implements the Stringer interface.

type Volume

type Volume Unit[VolumeUnit]

Volume is a type-safe unit structure that represents a volume/capacity measurement. It combines a numeric value with a VolumeUnit to ensure correct unit handling.

func NewVolume

func NewVolume(u VolumeUnit, value float32) Volume

NewVolume creates a new Volume value with the given unit and magnitude.

Parameters:

  • u: the volume unit (Liter, MetersCubed, or Gallon)
  • value: the numeric magnitude in the specified unit

func (Volume) Add

func (p Volume) Add(o Volume) Volume

Add adds another Volume to this one, returning a new Volume in this value's unit. If the other Volume is in a different unit, it is automatically converted before adding. The result preserves the receiver's unit.

func (Volume) Convert

func (p Volume) Convert(newUnit VolumeUnit) Volume

Convert converts this volume value to a different volume unit, returning a new Volume. Uses the table-based conversion system (volumeConversions) for the math.

Parameters:

  • newUnit: the target volume unit to convert to

Returns a new Volume in the requested unit.

func (Volume) MarshalJSON

func (u Volume) MarshalJSON() ([]byte, error)

MarshalJSON implements a custom JSON marshaler that includes the UnitType discriminator. The output includes "value", "unit" (as the integer enum value), and "unitType" (as the UnitType enum value for Volume). This allows JSON consumers to identify this as a volume measurement and determine the specific unit.

func (Volume) Sub

func (p Volume) Sub(o Volume) Volume

Sub subtracts another Volume from this one, returning a new Volume in this value's unit. If the other Volume is in a different unit, it is automatically converted before subtracting. The result preserves the receiver's unit.

type VolumeUnit

type VolumeUnit int

VolumeUnit is an enum for all supported volume/capacity unit types. ENUM(Liter, MetersCubed, Gallon)

const (
	// Liter is a VolumeUnit of type Liter.
	Liter VolumeUnit = iota
	// MetersCubed is a VolumeUnit of type MetersCubed.
	MetersCubed
	// Gallon is a VolumeUnit of type Gallon.
	Gallon
)

func ParseVolumeUnit

func ParseVolumeUnit(name string) (VolumeUnit, error)

ParseVolumeUnit attempts to convert a string to a VolumeUnit.

func VolumeUnitValues

func VolumeUnitValues() []VolumeUnit

VolumeUnitValues returns a list of the values for VolumeUnit

func (VolumeUnit) IsValid

func (x VolumeUnit) IsValid() bool

IsValid provides a quick way to determine if the typed value is part of the allowed enumerated values

func (VolumeUnit) String

func (x VolumeUnit) String() string

String implements the Stringer interface.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL