Introduction
Software for simulation or real time software typically manipulate physical quantities, and a solid foundation of quantities, units, and dimensions is a key issue. Common software languages do not provide native support for expressing units and quantities in order to avoid wrong assignments and comparisons or to do an automatic dimensional analysis. This causes of loss of time and trouble, and in a worst case, as the famous Mart Climate Orbiter, the failure of a mission due to a conversion error between systems of units.
Model Library for Quantities, Units, Dimensions and Values (QUDV) of sysML provides a solid model to express system physical properties. It provides an abstract syntax of the library expressed by a sequence of block diagrams.
In this article, we present a concrete implementation of the QUDV abstract model through an object oriented implementation. Our formulation is concentrate to provide the basis for defining basic units and other units via conversion or derivation. Also, it provides the definition of a system of units where it is possible to specify coherent derived units as a product of the base unit. In this version of the library, we miss the part for defining a declarative specification of dimensional analysis assigning an expression and its dependencies to each quantity kind. (It is an open issue.)
Analysis and Class Diagram
A system of units is generally a system of units of measurement composed of base units and derived units. A quantity is written as a number followed by a unit symbol.
In figure, 1 we have our class diagram with the main class that describes the implementation of a specific system of units. SimpleUnit
provides the base class for defining other units via conversion: AffineConversionUnit
, LinearConversionUnit
, or the derivation DerivedUnit
. SystemOfUnits
provides the definition of all units and quantity kinds of our system.
Figure 1
A quantity
is composed of a unique quantity kind, a numerical value, and a reference unit with other units defined by the conversion belonging to the same quantity kind.
Code System of Units
The system of units is implemented by hard coding the relations between the units and the quantity kinds in a unique class SystemOfUnits
. For instance the quantity kind Temperature
has a base unit of measurement Kelvin and other derived units as Centigrade, Fahrenheit, and Celsius. That relation is captured with a declarative specification, exploiting the model presented in figure 1.
Following the declaration of Kelvin, you find a description, a symbol K, and the reference to the quantity kind associated.
temperature = New QuantityKind("temperature", "T", "")
mKelvin = New SimpleUnit("kelvin", "K", temperature)
Another related unit of temperature is Centigrade that we define by a conversion from Kelvin.
mCentigradi = New AffineConversionUnit("Centigrade", "C", temperature, mKelvin, 1, 273.15)
Following the structure of the temperature declaration, we define the quantity kinds useful in our projects as pressure, length, time, mass, density, and related units as Pascal, Meter, Second, Kilogram; for a complete list, see the code in the attachment.
Public Class SystemOfUnits
Private mName As String
Private mCelsius As SimpleUnit
Private mKelvin As SimpleUnit
Private mFahrenheit As AffineConversionUnit
Private mCentigradi As AffineConversionUnit
Private mNewton As DerivedUnit
Private mPascal As DerivedUnit
Private mBar As LinearConversionUnit
Private mBarg As AffineConversionUnit
...
ReadOnly Property Pascal As DerivedUnit
Get
Return mPascal
End Get
End Property
ReadOnly Property Bar As LinearConversionUnit
Get
Return mBar
End Get
End Property
ReadOnly Property Barg As AffineConversionUnit
Get
Return mBarg
End Get
End Property
...
Public Sub New()
Dim temperature As QuantityKind
temperature = New QuantityKind("temperature", "T", "")
mKelvin = New SimpleUnit("kelvin", "K", temperature, "T", ""))
mCentigradi = New AffineConversionUnit("Centigradi", "C", temperature, mKelvin, 1, 273.15)
Dim pressure As QuantityKind
pressure = New QuantityKind("Pressure", "P", "")
mPascal = New DerivedUnit("Pascal", "Pa", pressure)
mPascal.addFactor(New UnitFactor(mMeter, -1))
mPascal.addFactor(New UnitFactor(mKg, 1))
mPascal.addFactor(New UnitFactor(mSecond, -2))
mBar = New LinearConversionUnit("Bar", "bar", pressure, mPascal, 101325)
mBarg = New AffineConversionUnit("Barg", "barg", pressure, mPascal, 101325, 101325)
Dim length As QuantityKind
length = New QuantityKind("Length", "l", "")
mMeter = New SimpleUnit("Meter", "m", length)
mKm = New LinearConversionUnit("kilometer", "km", length, mMeter, 1000)
mMm = New LinearConversionUnit("mmillimeter", "mm", length, mMeter, 0.0001)
...
End Sub
End Class
In order to make the declarative specification of SystemOfUnits
reusable in several projects, we build a library with all the defined classes.
Quantities
The association between the numerical value and the corresponding unit is made with the class Quantity
. For instance, the value of pressure is represented by the class Pressure
that inherits from the more general class Quantity
. It contains all the related units of the quantity pressure and a numerical value to represent the measure from which to start all conversions.
Public Class Pressure
Inherits Quantity
Private mpascal As DerivedUnit
Private mBar As LinearConversionUnit
Private mBarg As AffineConversionUnit
Public Sub New(ByVal si As SystemOfUnits)
mQuantityKind = si.Pascal.QuantityKind
mpascal = si.Pascal
mBar = si.Bar
mBarg = si.Barg
End Sub
ReadOnly Property unitPascal As Units
Get
Return mpascal
End Get
End Property
ReadOnly Property unitBar As Units
Get
Return mBar
End Get
End Property
ReadOnly Property unitBarg As Units
Get
Return mBarg
End Get
End Property
Property Pascal As Double
Get
Return mValore
End Get
Set(ByVal value As Double)
mValore = value
check()
End Set
End Property
Property dBar As Double
Get
Return (mValore / mBar.factor)
End Get
Set(ByVal value As Double)
Dim avalue As Double = (value * mBar.factor)
mValore = avalue
check()
End Set
End Property
Property dBarg As Double
Get
Return ((mValore - mBarg.Offset) / mBarg.Factor)
End Get
Set(ByVal value As Double)
Dim avalue As Double = ((value * mBarg.Factor) + mBarg.Offset)
mValore = avalue
check()
End Set
End Property
...
In the Quantity
class, we introduce a convention: adding a property for each unit represented inside the class called with its symbol and a letter "d" to indicate if is a derived unit. This list of properties is to avoid assignment error when writing code, in particular when writing physical formula. We make explicit the meaning of the variable by its name, with the unit symbol previously designed and implemented in the library.
All other implementations of the Quantity
class as Time
, LinearPosition
, Flow
are provided in the code in the attachment.
Operator Overload
An interesting feature to automatically avoid errors in comparisons and adding incompatible physical quantities is obtained by adding to the class Quantity
the overloads of operators +, -, >, <.
Public Shared Operator <(ByVal lp As Pressure, ByVal rp As Pressure) As Boolean
If lp.Pascal < rp.Pascal Then
Return True
Else
Return False
End If
End Operator
Public Shared Operator >(ByVal lp As Pressure, ByVal rp As Pressure) As Boolean
If lp.Pascal > rp.Pascal Then
Return True
Else
Return False
End If
End Operator
Public Shared Operator +(ByVal lp As Pressure, ByVal rp As Pressure) As Pressure
Dim result As New Pressure(New SystemOfUnits)
result.Pascal = lp.Pascal + rp.Pascal
Return result
End Operator
Example of use
In the example, we will see how to instantiate the quantity Pressure
, how to assign a numerical value, and how to compare and sum in safety mode.
In the example, the first assignment is from Pascal, the second from Barg. The library permits a correct comparison between the two values of pressure assigned from different units, as follows:
Dim pressure1 As New Pressure(si)
Dim pressure2 As New Pressure(si)
pressure1.Pascal = 100000
pressure2.dBarg = 5
If pressure2 > pressure1 Then
MsgBox(pressure2.Pascal & " is greater then " & pressure1.Pascal)
End If
At first look, 5 is less than 100000, but it is exactly the contrary! Thanks QUDV library! We can add the two values avoiding conversion errors, exploiting the overload of the sum operator.
Dim result As Pressure
result = pressure1 + pressure2
MsgBox("The sum is " & result.Pascal)
You can use the test project in the attachment to see and build other examples.
Conclusions
In our experience, the use of physical quantities inside programs for simulation can be made more flexible by exploiting the class SystemOfUnits
and the specialized classes of Quantity
. This approach reduces the risk in adding and comparing values of different units (implementing the comparable interface completely eliminates the risk). The classes encapsulate the conversion factors and the structure of unit dimensions making it possible to do dimensional analysis. The creation of specialized quantities is useful to describe properties more close to the system behavior.
Other solutions exist as showed in [2] below where we formulate dimensions and units as classes in a nominally typed object-oriented language through the use of statically typed meta-classes. The new and promising F# language [3] provides native support to manage units of measure. It permits to annotate numeric types with a symbol that indicates the quantity kind and also helps to infer the derived type of an assignment.
References
- Quantities, Units, Dimensions, Values (QUDV), http://www.omgwiki.org/OMGSysML/doku.php?id=sysml-qudv:quantities_units_dimensions_values_qudv
- Eric Allen, David Chase, Victor Luchangco, Jan-Willem Maessen, and Guy L. Steele, Jr.. 2004. Object-oriented units of measurement. In Proceedings of the 19th annual ACM SIGPLAN conference on Object-oriented programming, systems, languages, and applications (OOPSLA '04). ACM, New York, NY, USA, 384-403. DOI=10.1145/1028976.1029008 http://doi.acm.org/10.1145/1028976.1029008.
- Units of Measure (F#) http://msdn.microsoft.com/en-us/library/dd233243.aspx