Copyright © 1995-2001 MZA Associates Corporation
tempus m-system User's Guide
Introduction
How m-systems work
Overview of the m-system interface comment
Example of an m-system interface comment for an m-file
function without states
Example of an m-system interface comment using advanced
features
m-system output evaluation scheduling
m-system interface comment format
msystem command syntax
m-system input argument mapping
m-system output argument mapping
m-system interface tempus object types
m-system internal states
m-system API methods
m-system
Efficiency
tempus provides a robust mechanism for incorporating routines written in Matlab's m-file language as simple systems within a tempus system. Such systems are called m-systems. To use this feature, the user must take the following steps:
tempus employs three separate Matlab API techniques through which m-files are executed as tempus subsystems. When tempus is executed as a standalone program, m-systems are either executed through the Matlab engine interface or as separately compiled procedures created by the Matlab compiler. When executed as mex-files (or s-functions), m-systems call m-files through the Matlab API mexCallMATLAB routine.
The general logic of the tempus-Matlab interface is as follows:
Overview of the m-system interface comment
To implement the m-system logic, a tempus system must be created which contains the following information:
To communicate this information to tempus, the user must add a m-system interface comment line to the m-file. This comment is parsed and compared with the m-file function declaration to generate the tempus system description (.tsd) file and the source code necessary to interface with the function. The comment is intended to immediately follow the "Usage:" comment which has become standard in well-documented m-file functions.
Example of an m-system interface comment for an m-file function without states
The best way to illustrate the m-system interface comment is by example. Suppose we have an m-file function which computes a thresholded centroid with the following specification:
function [centroid, peakpix, maxval] = gcentroid(g,
relthresh, thresh, type)
% Usage: [centroid, peakpix, maxval] = gcentroid(g, relthresh, thresh, type)
% tempus: [Vector<float>, Vector<float>, float] = gcentroid(input
Grid<float>, input float, parameter float, parameter int)
% Inputs:
% g: A structure containing a 2-D real array to be centroided.
The fields
% of g are g.x, g.y, and g.g. Where
g.g is a mxn 2-D real array to be
% centroided, g.x and g.y contain the
real x and y coordinates of the
% points in g.g. g.x is dimensioned
1xm and g.y is dimensioned 1xn.
% relthresh: The relative threshold to be used expressed as a
real fraction
% of the peak value of g.g.
% thresh: The absolute threshold to be used expressed as the
minimum
% real value to used in centroiding
g.g.
% type: The type of threshold to be performed (either 1 or 2).
% Outputs:
% centroid: A 1x2 real vector containing the coordinates of
the centroid
% of g.g. The coordinates are
expressed in terms of the units of g.x
% and g.y. centroid(1) is the x
coordinate and centroid(2) is the y
% coordinate.
% peakpix: A 1x2 real vector containing the coordinates of the
peak
% element of g.g. The coordinates are
expressed in terms of the units
% of g.x and g.y. peakpix(1) is the x
coordinate and peakpix(2) is the y
% coordinate.
% maxval: A real scalar containing the value of the maximum
element
% of g.g.
% see gcentroid.m for the rest of the function.
Suppose further that we wish to use this function as a dynamic tempus system. We want g and relthresh to be dynamic inputs and we want to specify thresh and type as parameters. The proper m-system interface comment will be:
% tempus: [Vector<float>, Vector<float>, float] = gcentroid(input Grid<float>, input float, parameter float, parameter int)
For output arguments the m-system interface comment specifies to which tempus object type the argument should be converted. For input arguments the comment specifies whether or not the argument is an input or parameter and the tempus object type through which the values will be communicated. The m-system interface comment is positional. It provides information on an argument-by-argument basis and maps directly to the position of each argument on the function specification.
The choice of the tempus object types above are not arbitrary. They will generally be suggested by the nature of the interfaces that the user wants to set up in the tempus block diagram. For example, it is natural for g to be mapped to a Grid<float> because it is through objects of this type that sensor and image information is moved around in tempus. Vector<float> is a good candidate for the centroid output because 2-D positional and angular information is passed around in tempus using 2-element vectors.
Usually the choice of whether or not an input argument is treated as a parameter or input is dependent on just how the user wishes to set up the interface with the system. Parameters are used for static inputs which are specified only at the beginning of system execution. Inputs are used for dynamically changing entities. Because inputs can be assigned default values, it is generally more powerful to allow the input arguments to be specified as inputs to the system. If the user specifies only a type without specifying parameter or input, input is assumed.
Once the m-file is written and the m-system interface comment included, the user can create the m-system by executing the following command from the Windows DOS or Command Line interface:
C> msystem gcentroid.m
Successfully executed, this will generate the following files:
The .tsd file is added to a tempus system using the EditAdd Subsystem... command in the tve system editor. When a runset is created for a tempus system containing the m-system, the .h file will be used during the compilation.
By default m-systems are output-driven. That is, the m-file functions are only executed the first time that an output is requested for any given simulation virtual time. The user can also make the m-system be input-driven and/or executed at regular simulation virtual time intervals. See the section "m-system output evaluation scheduling" for information on the logic used to determine when the m-files are called.
Example of an m-system interface comment using advanced features
Suppose we have the following contrived m-file function which computes time-dependent outputs:
function [st, sdt, tprev, dt] = tdepmfile(t, p, w, tprev)
% Usage: [st, sdt, tprev, dt] = tdepmfile(t, p, w, tprev)
% tempus: [float, float, state, null] = tdepmfile(expression now(), parameter
float, input float, state) @ 0.001
% Inputs:
% t: The current simulation time.
% p: The intial phase angle.
% w: The frequency.
% tprev: The previous simulation time. [ ] if first call.
% Outputs:
% st: sin(p+w*2*pi*t)
% sdt: sin(w*2*pi*(t-tprev))
% tprev: t
% dt: t-tprev (0 if tprev is empty)
%
st = sin(p+w*2*pi*t)
if (isempty(tprev))
dt = 0;
else
dt = t - tprev;
end;
sdt = sin(w*2*pi*dt)
tprev = t
Repeating the above m-system interface comment:
% tempus: [float, float, state, null] = tdepmfile(expression now(), parameter float, input float, state) @ 0.001
For the first input argument we use the expression keyword to pass the current simulation time to the function as the input argument t. In this case, "now()" is the standard tempus function call which is made to obtain the current time. Users can specify any valid C++ expression using any of the C++ identifiers known to be in scope as long as the expression evaluates to a tempus object type which has a valid conversion to a Matlab data type.
The state keyword is used on both an input and output argument to allow the user to keep state information independent of tempus. The rules for this are that an input argument state must have a corresponding output argument state of the same name. tempus will simply make this argument available to the m-file without paying attention to its contents in any way. tempus object types do not need to be specified with states because the system always maintains the state in its native Matlab data structure and has no need to convert it for use in tempus. On the first call to a m-system m-file function, state input arguments are be set to the Matlab empty matrix.
Programmers can also use the Matlab persistent command to maintain state information. However, this should be used carefully since it can result in errors when more than one instance of the related m-system is to be used within a tempus system.
The null keyword is used to specify an output which the user does not want mapped to a tempus system output. Use of null allows proper execution of the m-file, but will not go to the trouble of converting the particular output to an tempus system output. This could be very useful for m-file functions which generate diagnostic outputs for which there is no reasonable conversion to a tempus object type.
Finally, the above m-system interface comment makes use of the optional specification of an execution interval. After the close parenthesis, the user may specify the minimum interval at which the m-file function is to be executed. In this case, the m-file is executed at least once every millisecond using "@ 0.001". By default, m-systems are output driven. That is, they are only executed the first time that an output is requested for any given simulation virtual time. The specification of an execution interval ensures that the m-file will be executed at least at all time i*dt where i is a non-negative integer (including zero) and dt is the specified interval (in this case, 0.001 seconds). The user can also make the m-system be input-driven. See the section "m-system output evaluation scheduling" for information on the logic used to determine when the m-files are called.
Once the m-file is written and the m-system interface comment included, the user can create the m-system by executing the following command from the Windows DOS or Command Line interface:
C> msystem tdepmfile.m
Successfully executed, this will generate the following files:
The .tsd file is incorporated into a tempus system using the EditAdd Subsystem... command in the tve system editor. When a runset is created for a tempus system containing the m-system, the .h file will be used during the compilation.
m-system output evaluation scheduling
By default, tempus m-systems are output driven. That is, they are only executed the first time that any output is requested for any given simulation virtual time. This is generally the most efficient behavior for a typical system, but it is not always the desired behavior. By editing the generated .h file and adjusting #define statements, the user can cause the system to be any combination of input-driven, output-driven, and time-driven.
output-driven: In an m-system which is output-driven the m-file is executed and its outputs evaluated the first time that any system output is requested for any given simulation virtual time. During the same simulation virtual time, subsequent output requests do not result in a call to the m-file function, instead the current values of the outputs are provided. If an m-system is purely output-driven and not input-driven and/or time-driven, its outputs will not be computed if its outputs are not connected to another subsystem or if they are connected only to input-driven systems such as recorders which record data only when their inputs are changed.
To make an m-system output-driven, uncomment the #define MLI*MFILEOUTPUTDRIVEN statement in the .h file before the associated runset is compiled. Here "*" is the name of the m-file function in all capital letters.
input-driven: In an m-system which is input-driven the m-file is executed and its outputs evaluated the first time that any system input changes for any given simulation virtual time. During the same simulation virtual time, subsequent input changes or output requests will not result in a call to the m-file, instead the current values of the outputs are provided.
To make an m-system input-driven, uncomment the #define MLI*MFILEINPUTDRIVEN statement in the .h file before the associated runset is compiled. Here "*" is the name of the m-file function in all capital letters.
time-driven: In an m-system which is time-driven the m-file is executed and its outputs evaluated at regular intervals as specified by the user.
To cause an m-system to be time-driven, uncomment the #define MLI*MFILETIMESTEP statement in the .h file and change the text "timestep" to an expression which evaluates to the interval at which the m-file should be executed. This should be done before the associated runset is compiled. Here "*" is the name of the m-file in all capital letters. An m-system can be made time-driven by including the "@ interval" qualifier on the m-system interface comment.
hybrid systems: In an m-system which is a combination of output-driven, input-driven, and/or time-driven, the m-file is executed at all of the times suggested by each method. In any case the m-file is only executed once per simulation virtual time.
Hybrid systems can have any combination of #define MLI*MFILEOUTPUTDRIVEN, #define MLI*MFILEINPUTDRIVEN, and #define MLI*MFILETIMESTEP uncommented.
Reading an m-file, the msystem utility parses the function definition and m-system interface comment lines to generate the tempus system .h and .tsd files which allow the m-file's execution as a tempus subsystem. This section describes the details of using the msystem command which can be executed from the Windows command line or directly from Matlab.
In the syntax descriptions below, items in bold type are to be entered verbatim, items in italics are substituted with more specific information, and items in braces ({ }) are optional.
Executed from a Windows DOS or Command Prompt window, the format of the msystem command is:
msystem mfile {compile}
Executed from within Matlab, the format of the msystem command is:
msystem(mfile, {"compile"})
where
mfile is the name of the file containing the m-file function to be analyzed. The m-file must contain a valid function definition line and a m-system interface comment. The file name may be specified with or without the ".m".
compile or "compile" is specified when it is desired to use the Matlab compiler for execution of the m-system rather than the Matlab engine. The compile option affects the default code which is generated and invokes the Matlab compiler which must be properly installed on the system. In Matlab the quotation marks must be included.
Upon successful completion, msystem generates the following files:
When the compile is used, msystem will generate the following additional files:
See the section "m-system API methods" for more detailed information on how the compiler option works.
m-system interface comment format
The m-system interface comment should appear after the typical m-file function "Usage:" comment. This is usually the third text line of the m-file.
In the syntax description below, items in bold type are to be entered verbatim, items in italics are substituted with more specific information, items preceding ellipses (...) can be repeated, items contained in quotation marks (" ") must go together and the quotation marks are not to be specified, and items in braces ({ }) are optional. The following is the formal specification format of the tempus interface comment:
% tempus: [outspec, ...] = mfunc(inspec, ...) {@ interval}
where
mfunc must be the name of the m-file function as it appears on the function declaration.
inspec must be one of "inpargtype tempustype", "expression exp", or state. See the section "m-system input argument mapping" for detailed information.
outspec must be one of tempustype, state, or null. See the section "m-system output argument mapping" for detailed information.
inpargtype is either parameter or input. See the section titled "m-system input argument mapping" for detailed information about choosing argument types.
tempustype is one of float, Complex, double, int, bool, Vector<float>, Vector<Complex>, Vector<double>, Vector<int>, Vector<bool>, Array<float>, Array<Complex>, Array<double>, Array<int>, Array<bool>, Grid<float>, Grid<Complex>, or Grid<double>. See the section titled "m-system interface tempus object types" for detailed information about choosing tempus object types.
exp is a C++ expression which returns an object of any of the types allowed by tempustype above. See the section titled "m-system input argument mapping" for detailed information about choosing argument types.
interval is a floating point constant which will be used as the automatic update rate.
There must be as many outspecs as there are output arguments on the m-file function declaration line and there must be as many inspecs as there are input arguments on the m-file function declaration line.
m-system input argument mapping
Input arguments of the m-file can be mapped to one of the following:
inpargtype can be either parameter or input, depending on whether the user wants to specify the value as a tempus system parameter or as a dynamically changing tempus system input. Usually the choice of whether or not an input argument is treated as a parameter or input is dependent on just how the user wishes to set up the interface with the system. Parameters are used for static inputs which are specified only at the beginning of system execution. Inputs are used for dynamically changing entities. Because inputs can be assigned default values, it is generally more powerful to allow the input arguments to be specified as inputs to the system. If the user specifies only a type without specifying parameter or input, input is assumed.
tempustype is one of float, Complex, double, int, bool, Vector<float>, Vector<Complex>, Vector<double>, Vector<int>, Vector<bool>, Array<float>, Array<Complex>, Array<double>, Array<int>, Array<bool>, Grid<float>, Grid<Complex>, or Grid<double>. See the section titled "m-system interface tempus object types" for detailed information about choosing tempus object types.
exp is a C++ expression which evaluates to any of the types allowed by tempustype above. The expression exp syntax is used to specify the value of a parameter or input which can be calculated from available C++ identifiers. The most common example will be the use of the expression now() to pass the current simulation virtual time to an m-file function. This feature allows a fairly advanced use of C++ expressions and will likely be used by more knowledgeable tempus programmers than by casual tempus users.
See the section "m-system internal states" for information on the use of the state keyword.
m-system output argument mapping
Output arguments of the m-file can be mapped to one of the following:
tempustype is one of float, Complex, double, int, bool, Vector<float>, Vector<Complex>, Vector<double>, Vector<int>, Vector<bool>, Array<float>, Array<Complex>, Array<double>, Array<int>, Array<bool>, Grid<float>, Grid<Complex>, or Grid<double>. See the section titled "m-system interface tempus object types" for detailed information about choosing tempus object types.
The null keyword is used to specify an output argument which the user does not want mapped to a tempus system output. Use of null allows proper execution of the m-file, but will not go to the trouble of converting the particular output to a tempus system output. This could be very useful for m-file functions which generate diagnostic outputs for which there is no available conversion to a tempus object type.
See the section "m-system internal states" for information on the use of the state keyword.
m-system interface tempus object types
Figuring out exactly which tempus object types ought to be used for m-system inputs and outputs is probably the trickiest part of setting up the m-system interface comment. Its not too difficult assuming that you have in mind to interface with specific systems which are already written. In this case, you must structure the m-file so that its input and output types correspond to the types of those tempus system inputs and outputs to which they are to be connected. Nonetheless, m-system authors can be assisted by a fuller understanding of the tempus object types. The following paragraphs describe the basic purpose and contents of the tempus object types which can be specified as the tempustype shown in the section titled "Format of the m-system interface comment."
float is a single precision floating-point number with approximately seven decimal digits of accuracy. It is the most common scalar type used in tempus systems. Its corresponding Matlab type is a 1x1 double with a real value. In the conversion from double to single precision, precision is lost.
Complex is a pair single precision floating-point representing the real and imaginary parts of a complex number. Its corresponding Matlab type is a 1x1 double with real and imaginary values. In the conversion from double to single precision, precision is lost.
double is a double precision floating-point number with approximately fifteen decimal digits of accuracy. Its corresponding Matlab type is a 1x1 double with a real value.
int is a 32-bit signed integer. Its corresponding Matlab type is a 1x1 double with a real values. In the conversion from double to int, non-integer values will be truncated toward zero.
bool is a binary switch having either true or false status. Its corresponding Matlab type is a 1x1 double with a real values. In the conversion from double to bool, non-zero values are converted to true and zero values are converted to false. In converting bool to double, true is converted to 1.0 and false is converted to 0.0.
Vector<T> is a one-dimensional array of elements of type T, where T is any of the scalar types listed above. A Vector<T> with n elements is converted to a 1 x n double array within Matlab using the same rules for each scalar above. Any Matlab numerical Array is converted to an n-element Vector<T> where n is the total number of elements in the Array regardless of its rank and dimensionality.
Array<T> is an n-dimensional array of elements of type T, where T is any of the scalar types listed above. An Array<T> can have a rank of up to seven and is converted to a double array within Matlab with the same rank and dimensionality using the same rules for each scalar above. Likewise, any Matlab numerical Array is converted to an Array<T> of the same rank and dimensionality.
Grid<T> is a 2-dimensional array of elements of type float, Complex, or double. Accompanying the array is spatial coordinate information such that each element (i,j) of the array has a physical location of (x(i),y(j)), where x and y are strictly increasing, uniformly spaced single precision reals. When converted to a Matlab data type, it is converted to a structure s having three fields s.g, s.x, and s.y. Where s.g is an m x n double array, s.x is a 1 x m double array, and s.y is a 1 x n double array. Each element of s.g is converted according to the scalar type above. When converting from a Matlab structure, the Grid<T> is created with the same dimensionality and assumes that dx = s.x(2)-s.x(1) and dy = s.y(2)-s.y(1). Remember that the grid is assumed to be uniformly spaced in x and y. If the m-file function returns a structure such that s.x and s.y are not evenly spaced, it is likely that incorrect results will be computed.
The m-system interface comment provides a mechanism for allowing individual instances of m-systems to maintain internal state information. Experienced Matlab m-file programmers may think that this is a trivial issue because Matlab allows the use of persistent and global variables which can generally be used to store state information. However, multiple versions of a tempus m-system can reside in a single tempus system to be executed. Therefore, use of persistent and global risks introducing errors by mixing the state information from two separate m-system instances. For this reason, the state keyword is provided to allow the use of per-instance internal states within m-systems.
To create an internal state variable, the m-file must be structured so that there is one input and one output with exactly the same name and that the keyword state is specified for both the inspec and outspec (see the section "m-system interface comment format" for general syntax information). For example, the following m-file function specification, "Usage:" comment, and m-system interface comment illustrate the specification of the state variable, tprev:
function [st, sdt, tprev, dt] = tdepmfile(t, p, w, tprev)
% Usage: [st, sdt, tprev, dt] = tdepmfile(t, p, w, tprev)
% tempus: [float, float, state, null] = tdepmfile(expression now(), parameter
float, input float, state) @ 0.001
The state keyword is specified for both an input and output argument of the same name to allow the user to keep state information independent of tempus. tempus will simply make this argument available to the m-file without paying attention to its contents in any way. state variables can contain any Matlab data whatsoever. They can be arbitrary Matlab structures, arrays, or cell arrays. tempus object types do not need to be specified with states because the m-system always maintains the state data in its native Matlab data format and has no need to convert it for use in tempus. On the first call to a m-system m-file function, state input arguments are be set to the Matlab empty matrix.
m-file functions can have more than one pair of input and output state variables. However, the need to do so is questionable. This is because a state variable can contain any information and therefore, it can be a structure which contains two separate items of state information.
There are three Matlab Application Program Interface (API) mechanisms which can be used to cause the execution of m-system m-file functions. For runsets executed as a main program (usually from the tve), the Matlab engine or the Matlab compiler interface is used. mex-systems are executed using the Matlab mex-file API. By editing the generated .h file and adjusting #define statements, the user can cause the m-system to be executed with any one of the three API methods.
Matlab engine API: For runsets executed as separate processes, the Matlab engine method is the default mechanism used by m-systems. When the Matlab engine interface is used, data is transferred to and from a separately running Matlab process in which the m-file code is executed. Within a tempus runset, the first time that an m-file is executed, the Matlab engine process is started regardless of whether there is another running Matlab process running on the same system. The user may de-iconify the Matlab engine session and enter commands in the window as he would any other session.
As the runset is executing, data is transferred to the Matlab session, the m-file is executed, and the results transferred back to the tempus runset process. The input and output variables that are used during this process appear in the main workspace of the Matlab session. As m-systems are executed, the user has direct access to their values through the Matlab engine session command line. The user can even employ the debugger within the session to set breakpoints and examine the operation of the m-file.
It is crucial that any m-files to be executed during the Matlab engine session be in the default Matlab path. This is because the tempus runset editor begins the Matlab session process and immediately attempts to execute the m-system m-file. The user is not given an opportunity to change the Matlab path before it begins looking for m-files. See Matlab documentation on how to set the default Matlab path.
The Matlab engine is treated as a special Matlab session. If there is already a running Matlab session on the machine, a separate session is created to run the engine. The user can access it and it appears that it doesn't interfere with the other session. When the runset program which calls the Matlab engine terminates, the Matlab engine session is not terminated. The user can continue to interrogate variables involved in m-system execution. If another runset program containing Matlab engine m-systems is executed, the same Matlab engine session is used.
To cause an m-system to use the Matlab engine API, uncomment the #define MLI*MFILEENGINE statement in the .h file before the associated runset is compiled. Here "*" is the name of the m-file function in all capital letters. The #define MLI*MFILECOMPILED statement ought to be commented.
Matlab compiler API: The Matlab compiler is a separate Mathworks product which can be used to translate m-files into C or C++ code. The benefit of using the compiler is that the resulting tempus runset can be executed on machines where Matlab is not installed or otherwise available. Compiled m-files run more efficiently than in the Matlab engine system because the code is translated to a more efficient language and, in m-systems, the need to transfer data between the tempus runset and the Matlab engine processes is eliminated.
The Matlab compiler product is not always the only product necessary to run code compiled with the Matlab compiler. m-files compiled with the Matlab compiler may call other Matlab libraries (e.g. graphics or math libraries). See the Matlab documentation for information about dependencies between Matlab compiler-generated code and other Matlab libraries.
To use the Matlab compiler to create an m-system the user must specify the compiler option when executing the msystem utility. This will cause the generated code to contain a commented #define MLI*MFILEENGINE statement and an uncommented #define MLI*MFILECOMPILED statement. Furthermore, the msystem utility invokes the Matlab compiler to generate the m-file in source, object, and library form. When the executables for runsets using the m-system are created, the resulting library provides access to the Matlab compiler-generated code.
Matlab mex-file API: When m-systems are included in mex-systems, the mex-file API is used. The API is different in the mex-file case from that in the standalone runset case because the mex-file must call back to the same Matlab session in which it is executing. Because data does not need to be transferred between separately running processes, this API is somewhat more efficient that the Matlab engine API. Furthermore, the mex-file API allows the user to debug and analyze m-systems in the same Matlab session in which the mex-systems are executed.
The .h file generated by the msystem utility is set up such that if the .h file is compiled within a mex-system, the mex-file API is used. In this case, the #define MLI*MFILEENGINE and #define MLI*MFILEENGINE statements are ignored and the #define MLI*MFILEMEX is activated. When compiling the mex-system, it does not matter whether the compile option was used with the msystem command because the mex-file API is always used for m-systems in mex-systems. It is probably possible to use the Matlab engine and/or compiler APIs inside mex-systems, however, it is not directly supported by the tempus utilities.
m-systems will not be as efficient as a functionally-equivalent tempus systems coded in C++. In many cases, the loss of efficiency will be slight and far-outweighed by the convenience of the rapid m-file programming environment. The loss of efficiency results from two interface issues:
Just how much less efficient these processes are is based on the ratio of the time taken by data translation and communication operations versus the amount of time take by all other operations in the simulation run. m-systems which are called very often and perform very little processing would have low overhead-to-processing ratios and therefore would be considered inefficient. However, these same systems executed in a larger simulation where the vast majority of time is taken in other computations make little net difference in the overall efficiency of the system.