Dimensioned Variable (DimVar) Class for MATLAB - notes and demos
Author: Sky Sartorius. Original base code: Rob deCarvalho.
A DimVar (Dimensioned Variable) contains both a value (any numeric type) and units (any combination of mass, length, time, etc.). Math operations performed on dimensioned variables will automatically perform dimensional analysis to ensure that units are consistent.
Both the m-files (units.m, unitsOf.m, etc.) and the directory ..\@DimVar must be placed on the current path (or in the current working directory).
Step one whenever using the DimVar class is to create the units struct, u, in the workspace.
u = units;
Or, shorthand syntax assigns the units struct to the variable u.
To create a dimensioned variable, multiply the value by the unit in the units struct.
l = 5*u.in
l = 0.1270 m
The variable will be displayed in base SI units. To display in another unit, divide by that unit.
ans = 0.4167
To convert between units, multiply by the starting unit and divide by the ending unit.
conversionFactor = u.mi^2/u.ft^2; fprintf('There are %d sq. feet in a sq. mile.', conversionFactor)
There are 27878400 sq. feet in a sq. mile.
More complicated units can be made by combining other units.
mach1 = 340.294*u.m/u.s
mach1 = 340.2940 m - s
If you wnat to use the speed of sound at sea level in your application often, expand the units struct with a new field after creating it. (You can also edit units.m and add a line to make mach1 available whenever working with the units struct.)
u = units; u.mach1 = 340.294*u.m/u.s;
Note that there is no such thing as a dimensioned variable with no units. If you perform operations that make the units cancel, a normal variable will be returned.
ans = DimVar
ans = double
Math with dimensioned variables is just like numeric variables except that dimensional/unit consistency is enforced. For example, adding two variables having different dimesions will result in an error.
3*u.s + 2*u.kg
Returns an error ("Unit inconsistency in addition").
Many MATLAB functions will not accept dimensioned variables. This is because most non-mathematical functions are only defined for dimensionless arguments.
t = (0:.1:1)*u.s; w = (2*pi)*10*u.Hz; % y = (3*u.in)*sin(t); % sin undefined for dimensioned argument t. y = (3*u.in)*sin(w.*t); % sin function now defined (w*t cancels units).
It can be convenient to define some dimensionless units, for example radians and degrees.
fprintf('The class of u.deg is "%s."\n',class(u.deg)) fprintf('There are %g degrees in one radian.\n',u.rad/u.deg)
The class of u.deg is "double." There are 57.2958 degrees in one radian.
The static method DimVar.strconv finds the conversion factor that converts from a unit indicated by a string to another unit indicated by a string.
ans = 1.3489e+03
It is possible to work in a non-SI units system. Several common alternatives are provided and can be selected by providing the function with a string indicating the desired system.
u = units('verbose'); u.Ohm
ans = 1 [meter^2][kilogram] -------------------- [second^3][ampere^2]
units IPS % Inch-pound(mass)-second u.mW
ans = 3.4171 [in^2][lbm] ----------- s^3
While writing code using the DimVar class makes code faster to develop, easier to read, and easier to debug, it will slow the code down due to all the calls to the DimVar methods. The units function itself also takes time. One good solution to working with the class is to develop the code using the class, but after it's all tested and debugged, replace the "u = units;" line with a list as generated by the static method DimVar.unitslist. For this demo file that would be
DimVar.unitslist([mfilename('fullpath') '.m'], '-copy')
u.Hz = 1 ; % [s^-1] u.Ohm = 1 ; % [m^2][kg^1][s^-3][A^-2] u.W = 1 ; % [m^2][kg^1][s^-3] u.atm = 101325 ; % [m^-1][kg^1][s^-2] u.cc = 1e-06 ; % [m^3] u.cm = 0.01 ; % [m^1] u.deg = 0.017453292519943 ; % u.ft = 0.3048 ; % [m^1] u.g0 = 9.80665 ; % [m^1][s^-2] u.gram = 0.001 ; % [kg^1] u.hp = 745.69987158227 ; % [m^2][kg^1][s^-3] u.in = 0.0254 ; % [m^1] u.knot = 0.51444444444444 ; % [m^1][s^-1] u.lbf = 4.4482216152605 ; % [m^1][kg^1][s^-2] u.m = 1 ; % [m^1] u.mW = 0.001 ; % [m^2][kg^1][s^-3] % "u.mach1" not defined in UNITS function. u.mi = 1609.344 ; % [m^1] u.rad = 1 ; % u.s = 1 ; % [s^1] u.slug = 14.593902937206 ; % [kg^1] ***List text copied to system clipboard.***
Example 1: Use the units struct to calculate the force at the bottom of a long vertical pipe that is capped at the bottom and filled with oil.
u = units; pipeInnerDiameter = 4*u.in; pipeHeight = 30*u.ft; densityOfOil = 0.926*u.gram/u.cc; pipeCrossSectionArea = pi*(pipeInnerDiameter/2)^2; % Find pressure of oil in the pipe using gravitational acceleration, u.g0. pressurePipeBottom = densityOfOil * u.g0 * pipeHeight; forceOnPipeBottom = pressurePipeBottom * pipeCrossSectionArea;
Note that each variable holds its value as expressed in SI units. To express these values in different units, divide by the desired unit.
fprintf('Bottom pressure is %g atmospheres. ', pressurePipeBottom/u.atm) fprintf('Force on the bottom cap is %g pounds.', forceOnPipeBottom/u.lbf)
Bottom pressure is 0.819504 atmospheres. Force on the bottom cap is 151.342 pounds.
Example 2: Find the Reynolds number (dimensionless) of an aircraft flying at 100 knots at sea level with chord of 223 cm using a mixture of units.
units; rho = .002377*u.slug/u.ft^3; V = 100*u.knot; c = 223*u.cm; mu = 28.8*u.gram/u.mi/u.s; Re = rho*V*c/mu
Re = 7.8534e+06
Methods such as disp, num2str, and plot are defined for DimVars.
acceleration = 1/6*u.g0; fallDistance = linspace(0,5)*u.ft; disp('Total time:') disp(sqrt(2*fallDistance(end)/acceleration))
Total time: 1.3656 s
v = sqrt(2*acceleration*fallDistance); [~,xStr,yStr] = plot(fallDistance,v); title(sprintf('Dropping an object on the moon\n(acceleration = %s)',... num2str(acceleration)));
Use the label text to add information.
xlabel(sprintf('Fall distance (%s)',xStr)); ylabel(sprintf('Velocity (%s)',yStr));