version 1.5.0.0 (106 KB) by
John McDermid

This toolbox attaches units to Matlab variables and enables unit conversion.

**Editor's Note:** This file was selected as MATLAB Central Pick of the Week

Have you ever needed to convert horse power to watts but can't remember the conversion factor? How many inches light travels in a microsecond? This toolbox is designed to make getting these answers much easier.

The "unit" statement attaches units to a variable. For example,

>> x=unit(2,'yards')

x =

1.8288 m

returns the answer in International (SI) units. If you would rather have you answer in feet it can be converted to feet by

>> convert(x,'feet')

ans =

6 feet

Variables created by the "unit" statement can operated on by these operators:

Unary plus, Unary minus, +,-,*,.*,/,\,./,.\,^,.^,',.'

and sqrt

Variables are also supported by triginometric,hyperbolic, and exponential functions and can be compared by

==, ~=, >, <, >=, and <=

Special plotting routines are available for plotting variables with units. These are:

plot, semilogx, semilogy, and loglog

The toolbox appears in the html help screens and has "GettingStarted', "User Guide", and function help screens.

Just down load the tool box to the directory of you choice and set the Matlab path to include this directory. To verify operation, type

>> unit('yards')

ans =

0.9144 m

If you get this result, you are all set!

John McDermid (2021). Units Conversion Toolbox (https://www.mathworks.com/matlabcentral/fileexchange/29621-units-conversion-toolbox), MATLAB Central File Exchange. Retrieved .

Created with
R2010b

Compatible with any release

**Inspired:**
Unit Converters, kview - Interface for signal/data easy visualization and processing

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!Create scripts with code, output, and formatted text in a single executable document.

AlI was having an issue plotting tables with units. For example

x = convert(unit([1 2 3 4],'seconds'),'seconds'); % Time vector

y = convert(unit([1 1 3 2],'volt'),'volt'); % Voltage at time

t = table(x,y);

plot(t.x,t.y);

Error MATLAB

^{®}givesUndefined function or variable 'varname'.

Error in unit/plot (line 1417)

[rows,~]=size(varname);

To fix this (I'm sure there is a better way but I wanted to change the core code as little as possible)

go to unit.m, go to the function [handles,legendHandle]=plot(varargin), go down about 28 lines (about line 1400) and change

for I=1:nargin

temp=inputname(I);

if ~isempty(temp)

varname{count,1}=temp;

end %if

count=count+1;

end % for

change to:

for I=1:nargin

temp=inputname(I);

if ~isempty(temp)

varname{count,1}=temp;

else

varname{count,1}='';

end %if

count=count+1;

end % for

I did this for plot, semilogx, semilogy, loglog.

The shortcoming of this method is the name of the variable is lost, units are still kept. There is an issue with passing a table and varargin and it gets converted to a cell array and I couldn't find a way to get the name back.

Or you can just pass the plot command

plot(x,y)

but sometimes it if you need to use tables this is a workaround.

AlI use this toolbox all the time. It helped me find math errors quicker because I can check the end units and make sure they are what I expect. I second the idea of having a Git repo to add updates to so we can keep this awesome tool going.

David GustavssonI love this toolbox.

I've made a number of changes, including implementing subsref(unit) and similar to make "unit vectors" more useful, a double(unit) function and several other QOL changes. Is there a Git repo or anything if I want to contribute?

Kurt FeiglHi John,

Something seems to be amiss with the prefix "atto" (1E-18). (Pico and femto both work, though:-)

speed =

1e-18 m/s

>> convert(speed,'attometer/s')

Error using /

Matrix dimensions must agree.

Error in unit/convert (line 310)

C.value=((A.value+A.offset)-B.offset)/B.value;

Kurt FeiglA section to handle the units for hydrogeology would be very helpful. For example:

The SI unit for permeability is m^2.

A practical unit for permeability is the darcy (d), or more commonly the millidarcy (md) (1 darcy = 10−^12 m^2).

The name honors the French Engineer Henry Darcy who first described the flow of water through sand filters for potable water supply.

https://en.wikipedia.org/wiki/Permeability_(earth_sciences)

Karan GillMATLAB has unit conversions. See https://www.mathworks.com/help/symbolic/units-conversion.html. Symbolic Math Toolbox is needed.

u = symunit;

len = 1.2*u.m;

len = rewrite(len,u.cm)

len =

120*[cm]

Karan GillUnits are now in MATLAB if you have Symbolic Math Toolbox. Try:

>> u = symunit;

>> x = 2*u.meter

x =

2*[m]

>> x = rewrite(x,u.ft)

x =

(2500/381)*[ft]

>> double(separateUnits(x))

ans =

6.5617

See the tutorial: https://www.mathworks.com/help/symbolic/units-of-measurement-tutorial.html

Israel VieiraDear John,

There seems to be a issue with temperature conversion and operations, for example:

Trial>> c15 = unit(15, 'degC')

c15 =

288.15 K

Trial>> c20 = unit(20, 'degC')

c20 =

293.15 K

Trial>> dt = c20-c15

dt =

5 K

Trial>> convert(dt, 'degC')

ans =

-268.15 degC

I can see anyway to get the °C back.

Thanks

Israel

Frederik VanhollebekeMy patchfile for the error when using units which have a non integer exponent

Index: unit.m

===================================================================

--- unit.m (revision 210)

+++ unit.m (working copy)

@@ -2023,21 +2023,18 @@

digstr=[digstr s(p+1)];

p=p+1;

end %if

- % If we at least two characters the end and the next two

- % characters are digits, add them to the digit string and

- % advance the position pointer by two characters

- if p+2<=L && all(isstrprop(s(p+1:p+2),'digit'))

- digstr=[digstr s(p+1:p+2)];

- p=p+2;

- % If we are at least one character from the end and the

- % next character is a digit, add the character to the digit

- % string and advance the position pointer

- elseif p<L && isstrprop(s(p+1),'digit')

- digstr=[digstr s(p+1)];

- p=p+1;

- else

- error('Exponent in units string is not a proper number!')

- end %if

+

+% +++++++++++++++++++++ MOD BY FVA STARTS HERE +++++++++++++++++++++++++++++++

+ % Deterermine the length of the digstr

+ p_end = p;

+ while (p_end+1) <= L && (isstrprop(s(p_end+1),'digit') || s(p_end+1) == '.' )

+ p_end = p_end + 1;

+ end

+

+ digstr = s(p+1:p_end);

+ p = p_end;

+% +++++++++++++++++++++ MOD BY FVA STOPS HERE +++++++++++++++++++++++++++++++

+

% Convert the digit string to a number and multiply it by

% the increment in case the previous operator was a "/".

% Then set the increment back to zero

Frederik VanhollebekeDear John

There seems to be an issue with units which have non integer exponents.

Say I need the unit m/sqrt(Hz) (I actually want V/sqrt(Hz), but m/sqrt(Hz) makes my discussion easier ;-) )

>> unit('m')

ans =

1 m

>> unit('Hz')

ans =

1 1/s

(I modified the Hz unit btw, see comment below)

>> sqrt(unit('Hz'))

ans =

1 1/s^0.5

All seems ok till this point, but:

>> unit('m')/sqrt(unit('Hz'))

ans =

1 m

After some debugging it seems that the issue is in the simplifyFund routine which is called by the mrdivide routine. The simplifyFund looses the 0.5 exponent on s

Another example:

>> sqrt(unit('m'))^2

ans =

1

Is it possible to have a look at this?

Thanks!!

Best regards

Fred.

Alexander CranneySeems to work well so far, except that I had to manually add psi, which is a pretty common unit.

Alexander CranneyLeandro BarajasVery clean, useful, and expandable implementation.

Small issue with:

unit('Hz') = 6.28319 1/s

it should be unit('Hz') = 1 1/s

See: https://en.wikipedia.org/wiki/Hertz

convConstant.m needs to be updated to:

case {'hertz','Hz'} % frequency in hertz y=units2convFac(unit('1/second'));

Mark MikofskiTry quantities.

http://www.mathworks.com/matlabcentral/fileexchange/48988-mikofski-quantities

Inspired by python Pint.

Fernando Freitas AlvesI would be much more useful if we could have the option to store a value in any unit instead of stacking with primitive units.

For example, instead of:

unit(1,'ft') = 0.3048 m

it would be better if the result was not automatically converted, like:

unit(1,'ft') = 1 ft

Anyway, your structure is very good. Congratulations!

ErichFrederik,

Hz is converted to rad/s, because 'Hz' is the same as 'cycle/s' and a cycle is 2π radians. Since radians are unitless, the unit displays as '1/s'.

>> unit(2,'Hz')

ans =

12.5664 1/s

>> 2*2*pi

ans =

12.5663706143592

>> unit(2,'rad/s')

ans =

2 1/s

>> unit(2,'cycle/s')

ans =

12.5664 1/s

Frederik VanhollebekeLooks like an error?

>> unit(2,'Hz')

ans =

12.5664 1/s

Florian SchwaigerTo be precise, this test case fails:

classdef UnitConversionTests < matlab.unittest.TestCase

methods (Test)

function convertMustNotEditOriginal(self)

feet = unit(3.3, 'ft');

meter = feet.convert('m');

feet2 = meter.convert('ft');

self.verifyEqual(feet.name, 'ft');

self.verifyEqual(meter.name, 'm');

self.assertEqual(feet2.name, 'ft');

self.verifyEqual(feet2.value, feet.value);

end

end

end

Florian SchwaigerWhile this does work, a central part is misleading with bad code style:

% this example is obvious, convert changes the object

feet = unit('ft');

convert(feet, 'm');

% in this case, the feet object must not change, however, both feet and meter are identical then

feet = unit('ft');

meter = convert(feet, 'm');

Kurt FeiglGREAT JOB! I use this code every day (at work). However, I found out (the hard way) that the symbol "g" does not denote "gram".

Instead, it "g" is coded as the gravitational acceleration on Earth as

unit(1,'g') = 9.80665 m/s^2

To get units of mass, I use:

unit(1,'gram') = 0.001 kg

Error using unit/convert (line 315)

Incompatible conversion! Fundamental units of kg/m^3 vs. 1/m^2/s^2

This issue led to the error message below:

density = unit(1000,'kg/m^3')

convert(density,'g/cm^3')

Error using unit/convert (line 315)

Incompatible conversion! Fundamental units of kg/m^3 vs. 1/m^2/s^2

Nick DuttonHi,

I noticed that the conversion from eV to Joules is incorrect.

Line 104 of convConstant.m should read:

"y=units2convFac(1.60217646e-19*unit('J'))"

Besides this one error, very nice utility!

SinanThere is an error using units with offset.

test = unit('C');

answer = 2*(test+test);

answer should give result of

1096.6 = 2*(274.15+274.15);

I implemented the following to avoid this error.

In classdef unit in function U=unit(varargin) ...

switch nargin

...

case 2

%find this line

if isa(varargin{1},'double') && isa(varargin{2},'char')

X=unit(varargin{2});

U=X;

if U.hasBeenConverted == false

U.value=varargin{1}*X.value+X.offset;

U.offset = 0;

else

U.value=varargin{1}*X.value;

end

I hope this does not interfer with other functionalities, but my verifications showed no strange behaviour anymore.

Many thanks for your tool!

Best regards

Sinan

Matthew M.I've been thinking about incorporating this for a while, hemming and hawing. Tried it today, finally, and I'm sold. Great job.

I wish there were a way to match the display to the Command Window format setting - I generally like to display more significant digits than short g allows. But it appears that there's no easy way to retrieve the current command window display format (I'll bet Yair Altman could figure one out, but I couldn't). I know you can use the .value method to display it in the desired format, but that's sort of inelegant.

The workaround for me was to edit unit\display directly, changing the sprintf format from %g to %0.12g (I chose 12 rather arbitrarily).

Thanks!

MarcoI cannot use this toolbox to find roots of polynomial using the roots function when coefficientes are unit-class type. I first have to define a isfinite function in the unit class, but then I have problems with the transpose and ctranspose function I am unable to solve myself. Can someone help?

Marcocan you add this function to the unit class? Some formulas has absolute value in them, and I need to preserve units.

function C=abs(A)

A=unit(A);

C=A; C.value=abs(A.value);

end

Ronan CIMADUREPerfect :)

CollinCollinGreat toolbox.

Ran into a small problem with non-dimensional unit's plus and minus (unit class with .name = ''). I fixed the problem by replacing all the

if A.name == B.name

......

end

with

if strcmpi(A.name,B.name)

......

end

as ''=='' is an empty matrix

JohnThanks Erich, that works perfectly

ErichTry

>> a= unit([1 2],'m')

Michael KatzJohnThis is a great toolbox to have handy but it seems to have problems with vectors and arrays of objects. For example, (I am running MATLAB 2010b):

>> a = [unit(1,'m') unit(2,'m')]

a =

??? Error using ==> plus

Too many input arguments.

Error in ==> unit>unit.display at 1827

s=sprintf(' %g %s',x.value+x.offset,x.name);

But when I change it to

>> a = [unit(1,'m') unit(2,'m')];

there is not issue. It seems the call to sprintf is having trouble with multiple inputs.

Overall this printing issue is not what concerns me, it is when I try to perform an operation on this array when I really run into trouble:

>> a * unit(1,'m')

??? Comma separated list must have exactly one item.

Error in ==> unit>unit.unit at 163

if U.hasBeenConverted

Error in ==> unit>unit.mtimes at 387

A=unit(A);B=unit(B);

I was hoping to get back a <1x2 unit> where both values are now in m^2. I run some highly vectorized code and it was be great if this issue could be resolved, overall great toolbox. Thanks

ErichVery easy to work with units using this toolbox. Author quickly updated the files when R2011b introduced an incompatibility.

ErichIn MATLAB R2011b I get:

>> Units(3, 'ft')

Error using Units

Error: File: Units.m Line: 1 Column: 10

Naming a class 'Units' is not allowed, because it is already a built-in class.