MastHEad

 


The k_units Data Type


 

This page describes, in detail, how Kornucopia's data type k_units works within the MATLAB environment.

Sub-sections on this help page:

Definition of the k_units data type

As noted in the previous help sections (Kornucopia Introduction & Features and Overview of Kornucopia), Kornucopia's k_units data type is designed to hold scalar or tabular-oriented data, including units and other meta-information. The k_units data type strives, whenever possible, to keep your numeric data, its units, and any related meta-info intact throughout your calculations. This means that the k_units data type is designed to allow you to use it naturally in MATLAB's mathematical operations, with Kornucopia functions, and with many MATLAB functions without the need to constantly separate and re-attach the numerical data from the rest of the data type (like is the case with traditional MATLAB work-flows using MATLAB table, cell, and/or struct data types). A significant difference of the k_units data type over other data types is that units stored in a k_units data type are "real units", not just tags. Through Kornucopia's full-featured Units Engine, Kornucopia will know how to identify and calculate with these units. This means you have the freedom to work with units of all sorts.

In brief, Kornucopia allows users to associate units like 'm', 'N', or 'lbf' to their data in a column-wise manner. Units can also be combined units like 'N/mm', 'lbf*in/s', 'MPa^0.5', or even something like 'in^3/(snail*s)'. The Kornucopia Units Engine is also able to readily handle  mixed units like 'lbf/mm' or something crazy like '(G^2/Hz)*kg*mile/day'.   When data associated with units via the k_units data type is supplied to Kornucopia functions, or is supplied to any of the overloaded MATLAB functions and operators, the functions will recognize the units and properly utilize them, including checking for units compatibility and automatically doing units conversions as needed so that you obtain accurate and clearly denoted results. Another handy feature of the k_units data type is that it allows you the flexibility of referencing your data by row and column names and/or row and column indices (a similar feature to the MATLAB table data type, although with slightly different syntax from a MATLAB table). 

Kornucopia accomplishes this by leveraging the features of MATLAB's Object Oriented Programming (OOP). Without getting too deep into the weeds of OOP, this means that the k_units data type is also a class which then allows Kornucopia to tell MATLAB how to process this data type in many MATLAB operations and functions so that your calculations work smoothly and that all the units issues, such as units conversion and units compatibility checking, are handled automatically by Kornucopia's Units Engine.

Shown below is a depiction of a typical variable using the k_units data type, followed by a depiction of the k_units object model that shows all the "buckets" available to hold various Properties for the variable. Also depicted at the bottom right are the k_units Methods, which are special functions for the data type (they will be explained in a few moments). In the depiction, the variable matls holds a column-oriented table-like representation of some material information for three different materials. The variable's Properties include the numeric Data (the 4 column by 3 row array of numeric values), their associated Units and ColNames (column names), as well as RowNames and an overall Description Property. Additionally, if other other Props exist in the variable that are not displayed to the screen, a note is provided by Kornucopia under the output display noting this fact (in the image below, the variable matls does not have these extra Props defined, so no notice appears).   

  

 

Important note: As depicted in the object model above, the k_units data type is designed to hold tabular data (or scalar data). The tabular data format implies that Kornucopia data storage and calculations are column-oriented. This approach is consistent with MATLAB's table data type, but it may be different than some other traditional MATLAB work-flows that use row-wise storage and calculation set-ups.

k_units Properties 

The k_units data type has two primary Properties, Data and Units, and then additional meta-info Properties which are grouped under the Property name of Props. Please note the following:

All of the possible Properties associated with a k_units data type are described here.

For any variable or entity of data type k_units, you can obtain a quick overview of its Properties via the function k_summary.  To actually access a variable's Properties, you use MATLAB "dot" notation, such as A.Data, A.Units, and A.Props, where A is the name of a variable. To access the sub-Properties under Props, the syntax is simply A.Props.Description or A.Props.ColNames , etc.

Some Property Limitations

The Properties of Units, Props.ColNames, and Props.RowNames have the following limitations on the char-strings that can be supplied inside their cell-strings:

k_units Methods

Listed below is a brief description of each of the k_units Methods. The Methods are special functions that work on k_units data types. They are typically used via a "dot" syntax call such as A.convert('mm,  MPa, N') or A.toStruct, where A is the name of the k_units data type you want to apply the Method on. Arguments, if any, and specific syntax are described later on this help page and are also supplied on the specific help pages for each Method.

To aid in determining what is a Property and what is a Method, all the k_units Properties begin with a capital letter and all of its Methods begin with a lower case letter.  You can always access either using MATLAB "dot" notation, as these syntax examples below show:

B = A.Data - This would return the array of numeric data held in the Data Property of variable A.

B = A.Units - This would return the cell-string containing the Units strings for the various columns of the Data held in variable A.

B = A.Props.ColNames - This would return the cell-string containing the column names for the various columns of the Data held in variable A.

A = A.convert('mm_N_s') - This would convert all the columns in variable A from their original Units to the Units of the Units Preference named 'mm_N_s'. A Units Preference is like a Units System, but it has additional features and flexibility.   

Working with the k_units data type

The remainder of this help page discusses and demonstrates how to use the k_units data type in MATLAB. Throughout these discussions and demonstrations, you will find a variety of hyperlinks that lead to other help pages to provide additional details on related functionality or topics.

Ways to create a variable holding k_units data type  

There are four ways to create a variable (or entity) that hold a k_units data type. 

  1. Use the constructor function k_units, supplying as arguments the primary numeric data, and optionally any Units and other meta-info such as an overall description, column names, and more. You can also feed any Kornucopia-compatible variable into the constructor function k_units to create a k_units data type.

  2. Performing any math (+, -, *, /, ^, etc) on entities where one or more of the entities involved in the math calculation are of data type k_units. The result of any such calculation will be a k_units data type.

  3. Importing a data file into MATLAB via one of Kornucopia's functions for reading text files or importing other file formats such as Abaqus ODB or Spectral Dynamics IMPAX data files. The result of using this functionality will either be a single array of data type k_units, a cell array where each element in the cell array contains a single array of data type k_units, or a MATLAB struct or table variable type where each field (or column) holds a single array of data type k_units.

  4. Using nearly any Kornucopia function. With only a few exceptions, nearly all Kornucopia functions return a k_units data type or a cell array, MATLAB table, or structure containing k_units data types.

To further explain how the k_units data type works, we will concentrate mostly on the first two approaches from the list above. We start very simple and build our way up so that you get a good understanding of the k_units data type, and how Kornucopia and MATLAB work with it.  You are encouraged to open MATLAB and type (or copy) the various commands that will be presented throughout the rest of this help section. Since we will show the result of such commands, you can also just read the help section as-is.

The function k_units is the class' constructor function. It has the following two calling syntax options:

  1. A = k_units(Data, Units, ADV)

  2. A = k_units(KornucopiaCompatibleDataType)

The argument ADV is Kornucopia terminology meaning that the function has optional Advanced arguments. In Kornucopia, each function's help page describes the ADV's for that function. Additionally, Kornucopia provides some other general features related to the use of ADV's that are described in the general help section ADV Parameter.  For any Kornucopia function, you can always take default settings for any ADV options by simply omitting the ADV argument (which is what we will do in the examples that follow). 

For the moment, we will concentrate on the first calling syntax approach for the k_units function (the second calling syntax is described on the k_units function's help page).  

Creating a few variables of data type k_units

To begin, we create a variable Lx  that is to hold the scalar value of 25*mm and a variable B which is to hold a 2x3 array of values with units, by column, of s, N/m^2, and in.

In MATLAB, enter and run the following commands in the traditional MATLAB script editor. Please note: In many of the calculations that are shown on this help page, we will be omitting the trailing semicolon so that the result of the calculation will automatically display in the MATLAB command window. (The special comment shown at the top of the editor, %#ok<*NOPTS> tells the editor to not issue warnings about this.)

 

Lx = k_units(25, {'mm'})
B = k_units([0, 10, 0.8; 5, 15, 1.2], {'s', 'N/m^2', 'in'})

 

In the MATLAB environment you see the following returned:

A few notable observations:

  1. The "Initial Kornucopia Units Preference Notice" appears the first time you use any Kornucopia-related commands, variables, or functions in a new MATLAB session.  The notice tells you what is the current active Units Preference. Unless you have made some advanced Kornucopia settings, the message will show that 'SI_partial' is the activated Units Preference.

  2. Both variables, Lx and B, display their results in the MATLAB window including their units. The variable Lx appears as a scalar while the variable B appears as a Kornucopia table.

  3. The MATLAB Workspace states that BOTH variables are a 1x1 k_units Value of Class k_units. The "size" of 1x1 is referring to the fact that each variable is a single instance of a k_units object, it is NOT referring to the size of the primary Data property.  A little bit later in this demonstration we will show a few different approaches to get at the size of the primary Data portion of variables of type k_units.

Using string-list syntax

In the MATLAB commands above, we entered the units as elements of a cell array, known as a cell-string. This is because the Units Property of a k_units data type holds its contents as a cell-string. While this input syntax is proper and correct, it can quickly become annoying, especially if you have many columns of different units to define. Because the use of comma and semicolons are restricted from Units strings, Kornucopia can offer an alternative input syntax called a string-list for suppling Units. A string list is a single char-string where the units in the string are separated by commas or semicolons. Since a comma and semicolon cannot be part of the Units string itself, it can then be interpreted as a delimiter.  

Thus, we can use the following simpler alternative syntax instead.

 

B = k_units([0, 10, 0.8; 5, 15, 1.2], 's, N/m^2, in')

 

Evaluating the above in MATLAB will produce the exact same result as the more "formal" input syntax initially demonstrated. Kornucopia will internally convert the string-list into a cell-string identical to the original direct specification of the Units. You, as the user, have the freedom to use either form of input. The approach of using a string-list also works for the Props.ColNames and Props.RowNames Properties since the use of comma and semicolon are also restricted from these Properties too.

Using dot syntax

Depicted below are two commands using "dot" notation to define the Description Property and the ColNames Property for variable B. Following those commands is a command to extract just the contents of the Data Property from B and place it in a new variable called justNumbers. The last set of commands are an alternative all-in-one specification of the variable B using ADV options of the k_units function (click for k_units function help page to see all of its ADV options). For the creation of variable B_1 below, note that the ADV options are specified as pairs of a ParamName and ParamVal. For the ParamName 'ColNames', the ParamVal was the string-list of column names. For the ParamName 'Description', the ParamVal was a descriptive sentence (to specify multiple rows for the description, enter a cell-string).

 

B.Props.Description = 'A simple data set.';
B.Props.ColNames = 'Time, stress, Vert Length';
display(B)

justNumbers = B.Data

% Alternate (Equivalent) all-in-one definition
data = [0, 10, 0.8; 5, 15, 1.2];
B_1 = k_units(data, 's, N/m^2, in', ...
   
'ColNames', 'Time, stress, Vert Length', ...
   
'Description', 'A simple data set.')

 

The output results are shown below.

Clearly, the information communicated by B is much richer than the justNumbers variable. You also see that the alternative syntax that created B_1 is indeed the same as B.

Doing some math with k_units

Next we show doing some simple Math and how the output results are of type k_units. Below we multiply the stress column by a value of 2. The result, C, is a k_units data type. Two other equivalent ways of doing the calculation are shown with C_1 and C_2. Lastly, we then change the ColNames Property of C and place the contents of C into the fourth column of B.

 

C = 2 * B('stress')

% Equivalent syntax approaches to compute C
C_1 = 2 * B(:,'stress');
C_2 = B(:,2) * 2;

% Modify ColName of C and place onto end of B
C.Props.ColNames = 'Double stress';
B(:,4) = C

 

The result from the initial calculation of C is shown below as well as the B variable after C was placed in its 4th column.

Please note the following from the above code and results:

  1. The calculation of C (and C_1 and C_2) were derived by multiplying the stress column of B and the numeric value of 2. The order of the multiplication, 2 in front of B or after B is irrelevant. Because Kornucopia has overloaded the MATLAB math operators, MATLAB knows to pass the multiplication calculation to Kornucopia since a k_units data type was involved. The result of the math calculation is a k_units data type, the variable C. It is noted that Kornucopia has overloaded over 80 MATLAB functions and operators including many of the typical math operators such as arithmetic math operators and functions, relational operators, trigonometry, log and exponent functions, and more!

  2. The variable C inherited some of the Properties from B during the calculation, namely the Description Property and ColNames for the stress column. See Props Inheritance to learn more about how Kornucopia handles such meta-info behaviors.

  3. The Units for variable C changed, they are not N/m^2, as was the case for B, but rather they are now Pa for C. This is because we did math and our Units Preference was set to 'SI_partial'; remember the initial notice that was echoed at the beginning of this demonstration. In Kornucopia, whenever any math is done on a variable, the results are returned in whatever units are set as the Active Units Preference, which in this case was the 'SI_partial' system. In this units system, quantities of load/area are converted to the unit of Pa. If you want a different Units Preference active, simply use the k_unitsPreferenceActivate command in your script or calculations.

The next set of calculations compute a force from the 'double stress' and  'Vert Length' columns of B, and the variable Lx, which we defined earlier.

 

F2 = B('Double stress') .* (B('Vert Length') * Lx)

B = [B, F2]

B.Props.ColNames(1,end) = 'Force';
display(B)

 

 Important items to note:

  1. The two warnings that appear first are telling us that when we did some multiplication operations (which occurred when computing the variable F2) that none of the Props were inherited. This means that none of the Props Properties, of B('Vert Length'), Lx, nor B('Double stess') are being inherited by F2.  As a result, F2 has not inherited any column names from these quantities and thus F2 has an empty ColNames Property.  To be clear, all the numeric values and Units from the Data and Units Properties are properly processed, it is only the meta-info Properties in Props that are not carried through the calculation.  This behavior, in total, is reasonable because there is no consistent logic to apply to derive a column name for F2 based on the entities used to create it. Bottom line, in this case, everything is fine and the warnings can be ignored. See the help page on Props Inheritance to learn more, including how to suppress this particular type of warning.

  2. Because F2 does not have a column name, when we append it to the end of B (which has column names), the new result of B automatically fills-in the last column with a default column name. Once a variable (or entity) of data type k_units has ColNames, then any additional columns added to it must have column names. If they do not, Kornucopia assigns a default one for you. In the final version of B displayed above, we have changed the ColNames content of only the last column to be a more reasonable name, 'Force'.

  3. As for the actual calculation of the force variable, F2, Kornucopia automatically handled all the Units-related conversions and simplifications needed.  Note that the 'Vert Length' column was in units of in where as Lx was in units of mm and 'Double stress' was in Pa.  The final result was in N because the Active Units Preference was 'SI_partial'.

Converting the units of variables to other units

The calculations below show a few of the ways you can easily convert the units of a whole variable, or specific columns, to other specific units or a different Units Preference.

 

% Convert all columns using Active Units Preference
B = B.convert()

% Convert Specific columns to a particular units
B('stress, Double stress') = B('stress, Double stress').convert('lbf/ft^2')
B('Time, Force, Vert Length') = B('Time, Force, Vert Length').convert('min, lbf, ft')

% Convert to a particular Units Preference
B = B.convert('mm_N_s')

 

The result from the four different uses of the convert Method are shown below.  

As you can see, the syntax and capabilities are very flexible. You can learn more about converting units on the convert Method's help page. If you are curious about the displayed precision of Kornucopia variables, click here to learn more.

Putting it all together - Example of creating a decaying sinusoidal velocity vs time curve

We now switch to a slightly more elaborate demonstration. The calculations below create a decaying velocity vs. time curve using some analytical equations and then plot the result.

 

k_cleanup()

k_unitsPreferenceActivate('mm_N_ms')
k_set('inheritPropsAutoWarning', 'off')

% This is easy way to obtain some variables representing units
k_unitsVariables('s, msec, Hz, m')

% Define a linearly-spaced time vector
nPoints = 501;
t = k_vectorByPoints(0*s, 50*msec, nPoints);
t.Props.ColNames = 'Time';

fs = k_samplingFreq(t) % Compute sampling rate of t

% Define sine wave that exponentially decays toward zero
f = 250*Hz
vo = 20*m/s
v = vo*sin(2*pi*f*t) .* k_window('exponential', nPoints);
v.Props.ColNames = 'Vel';

display(t), display(v)

% Plot the results
figure
k_plot(t, v)

 

Several things are occurring in the commands presented (click on the hyperlinked entities to learn more as needed):

  1. First, the function k_cleanup is used to provide interactive pop-up offering to clean-up the workspace.

  2. The Units Preference 'mm_N_ms'  is activated via k_unitsPreferenceActivate.

  3. A global Kornucopia setting is modified to turn off Props Inheritance warnings. Click these links to learn more about the k_set function and Props Inheritance.

  4. The function k_unitsVariables is utilized to create the variables s, msec, Hz, and m in the MATLAB workspace.

  5. k_units(1, 's'); k_units(1, 'msec'); k_units(1, 'Hz'); k_units(1, 'm');

  6. The variables representing units are then used in calculations to compute several items. Since these Units Variables are of data type k_units, all the math operations using them automatically creates other variables of data type k_units.  

  7. To calculate the decaying sinusoid, the k_window function was used (an actual equation for an exponential decay could also be used, but this was easier). It is noted that the element-by-element multiplication syntax of ".*" was needed since the result of the sin function (due to variable t) and k_window function are both column vectors and we do NOT want to compute a matrix dot product.

  8. The k_plot function not only plotted the data, but it leveraged our earlier efforts of adding a few descriptive properties to also automatically label and title the plot!

Depicted first is the clean-up pop-up and a view of the variables in the workspace after the commands were run.

The image below shows the output echoed to the MATLAB command window and the figure that was plotted.

 

 

 Important items to note:

  1. Because of the Activated Units Preference, computed variables are converted to the units associated with that preference. The image shown below this section of notes depicts many of the Units Preferences available in Kornucopia and the specific one of mm_N_ms that was activated.  In brief, any calculation results are converted to the units listed in the specified preference. Click here to learn more.

  2. No Props inheritance warnings appear above because we turned them off. Had we not, a warning would have been generated by the multiplication operations related to calculating  the variable v.  

  3. The display of variables t and v did NOT go scrolling off the screen, but instead displayed a few lines and then ended with a note of how many rows are not shown along with a tip of how to see more rows. This unique Kornucopia behavior makes it very easy to take a quick view at variables and their contents in the MATLAB window without them scrolling off the screen.  

  4. With little effort on the user's part, the plot is created that includes automatically created, well-labeled axes and a title.

Displayed below is the result of using the k_unitsPreferenceList function at the MATLAB command prompt.

 

 

Using several other Kornucopia features

The calculations below differentiate and integrate the velocity vs time curve created previously to obtain curves of acceleration and displacement. All the important variables are then concatenated into a single array which is then plotted.

 

adv = k_adv();

a = k_derivative(t, v);
a.Props.ColNames = 'Accel'
a = a.convert('G')

d = k_integrate(t, v, 0*m)
d.Props.ColNames = 'Disp'

B = [t, d, v, a]
B.Props.Description = 'Study of decaying sinusoidal velocity';

figure('position', k_figZoom(1, 1.75))

subplot(3,1,1)
k_plot(B('Time'), B('Disp'))

subplot(3,1,2)
k_plot(B(:,1), B(:,3))

subplot(3,1,3)
k_plot(B, [], ...
   
'independentCol', 'Time', ...
    
'depend', 'Accel', ...
    
adv.k_plot.unitsConvertTo, 'ms, 1000*G', ...
   
adv.k_plot.grid.major)

 

Some important items to note about the calculations above are:

  1. A special variable, adv, was defined using the k_adv function. This function returns a structure of all the Kornucopia functions that have ADV options and the various options for each function. This adv variable is then easily used to obtain a scrollable selection list of ADV options for any function (which is done in the last k_plot use at the end of the set of commands shown below).  Users find this adv variable technique extremely handy.

  2. Just like math (via Kornucopia's k_units data type), the Kornucopia functions of k_derivative and k_integrate know how to handle all the units-related conversions involved in the calculations.

  3. Grouping all the variables of t, d, v, and a into a single array is natural and easy by using normal MATLAB concatenation syntax.

  4. Since the fundamental Units Signatures of displacement, velocity, and acceleration are different, we must use three different plots to graphically show all the data in the same figure window. The MATLAB function subplot helps easily divide the Figure window into three axes (regions) for the plots.

  5. When we create the figure window, we use the 'position' option of the MATLAB function figure and supply the Kornucopia function k_figZoom as the value argument. This allows us to easy change the figure window size without having to specify pixel locations on the screen. The arguments of k_figZoom are the zoom factors for the width and height.

  6. The three different instances of k_plot used below are showing a variety of syntax options, including Flexible XY Data Input Syntax to plot all the variables. Plotting with Kornucopia is very flexible. You can learn more here.

  7. In the last plot of B (the acceleration vs time curve), we utilized a handy option of converting units just for the plot.

Presented below is the combined result variable B and the final plot of the results.

 

Obtaining the size of contents inside k_units data type

To close-out the demonstration, we show a how to obtain the size of the primary data array within a k_units data type and also how to work with MATLAB functions that do not support the k_units data type.  The snippet of commands below and resulting output presented after the commands shows four different ways to obtain size information.

 

size(B)
size(B.Data)
B.dataSize
k_summary(B)

 

Items of note regarding the four approaches and their results:

  1. The MATLAB function size returned the size of 1,1 (meaning 1 row and 1 column). This result occurs because the size function looks at the k_units data type as a whole entity, it does not know to look at just the Data Property to determine size. It is noted that while the size function could have been overloaded by Kornucopia to return the size of the Data Property, such an overload is NOT implemented because it would have very undesirable results on the MATLAB variable editor behavior with k_units data types. This is why variables of data type k_units appear as 1x1 k_units in the MATLAB Workspace window.

  2. The second command leveraged dot notation to directly access the Data Property of B. This returns the numeric array from the primary data container of B on which the function size then computes the desired result.

  3. The third command shows how you can also use the Method dataSize to obtain the array size of the Primary data container of B.

  4. The last command uses the k_summary function to obtain a concise summary of the variable and its Properties.

Using a MATLAB function that does not support k_units data type

For many commonly used MATLAB functions, Kornucopia has overloaded these MATLAB functions so that they natively understand how to take input arguments of type k_units. Having said this, MATLAB has thousands of functions, so there quite a few MATLAB functions that are not overloaded by Kornucopia, and thus those functions will not directly take input arguments of type k_units. This is easily to get around by sending in only the numeric data portion of the input arguments using the .Data property of any variable of type k_units. Below is a simple example demonstrating the technique.

Consider the case where you have a vector of velocity values that are represented via a k_units data type. Below is the echo of the variable v (created previously in this example) in the MATLAB command window.

We desire to compute a moving median of this data with a window length of 10 data points. MATLAB's movmedian function does just what we want, so we try the following but MATLAB throws an error:

MATLAB is complaining that it does not understand how to process the 1st argument, v, which is of data type k_units. To solve this issue, we need to send in only numeric data that represents the variable v, essentially removing units (or stripping units) from the variable. This is easily done by using the .Data property of the variable which holds only the numeric portion of the variable. Notice the following:

Thus we can easily compute the moving median as:

The result depicted above holds the desired calculation, BUT it is now just numbers. There are no Units, colNames, etc.  Below is a better implementation where we still use the .Data approach, but also put the result back into a k_units data type.

In the few extra lines used above, the 2nd line takes the numeric result tmp and puts it into a k_units data type using the .Units from v. The last 2 lines add an appropriate column name to the output variable b and a description too.

Next steps

To learn more about the k_units data type and using Kornucopia in general, consider the following links.