Matlab & Simulink Advanced Programming

MATLAB Programming Techniques

1. Introduction


2. Structuring Data

Summary: Overview of MATLAB Data Types

Each array type is intended to store data with a characteristic organization. Some arrays hold data all of the same data type, and others allow storage of different data types.

Homogeneous Arrays

Homogeneous arrays are scalars, vectors, matrices, and higher dimensional arrays whose elements all have the same data type. Elements of an array can be numbers, logical values, dates and times, strings, or one of many other other data types. For instance, a logical matrix would be a rectangular array with elements that are all logical values.

Array TypeIntended Contents
single
double
Floating-point numbers with ~8 (single) or ~16 (double) decimal places of precision

Unless otherwise specified MATLAB stores all numeric variables as type double.
int*
uint*
Integer values of various ranges
char
string
Text
datetime
duration
calendarDuration
Dates, times, durations between dates and times
logicalBoolean (true/false) values
categoricalValues from a finite set of alphanumeric (usually text) labels
function_handleThe definition of a function

Heterogeneous Arrays

Sometimes data are not all the same data type or size. There are specific containers for these heterogeneous data.


Summary – Structuring Data

Character Arrays vs String Arrays

The primary difference between a character array and a string array is that an individual element of a character array is a character and an element of a string array is a piece of text, which consists of several characters.

Organizing Data in Tables

When several variables in your workspace hold data about the same observations, you can use the table function to collect this information into a table.t1 = table(var1,var2, ‘VariableNames’,{‘Thought1′,’OnSecondThought’})t1 = 2×2 table Thought1 OnSecondThought ________ _______________ “Ford” 32.7 “Toyota” 1
You can index into a table using array indexing with parentheses. Columns can be specified either numerically or by name.t2 = t1(2,”Thought1″);t2 = table Thought1 ________ “Toyota”

Organizing Data in Cell Arrays

Create a cell array using curly braces and separating elements with commas and semicolons.car = {‘Ford’,’Expedition’;32.7,true}car = 2×2 cell array {‘Ford’ } {‘Expedition’} {[32.7000]} {[ 1]}
You can index into a cell array using standard MATLAB indexing with parentheses, (). This returns a portion of the original cell array.car(1,1) ans = 1×1 cell array {‘Ford’}
You can access the contents of cells in a cell array by indexing with curly braces, {}, rather than parentheses, ().car{1,1} ans = ‘Ford’

Organizing Data in Structures

This syntax creates a structure named car with a field named make and assigns a value to that field.car.make = “Ford”car = struct with fields: make: “Ford”
The same dot notation can be used to create new fields.car.model = “Expedition”car = struct with fields: make: “Ford” model: “Expedition”
To add an element to a structure array, use parentheses and assign a value to a field of the struct.car(2).model = “Prius”car = 1-by-2 struct makemodel”Ford””Expedition”[]”Prius”
You can use the field name and array indexing to extract the data.car(2).modelans = “Prius”

3. Manipulating Heterogeneous Data

How Do You Collect Output from Comma-separated Lists?

Concatenating Horizontally

Regardless of where the comma-separated list comes from, square brackets concatenate the data into a row vector.

Cell Arrays

The 2-by-2 cell array stored in the x variable contains four scalars.xx = [10] [20] [30] [40]
Using square brackets creates a numeric row vector. The elements of x are concatenated columnwise.[x{:}]ans = 10 30 20 40

Structure Arrays

The structure array stored in the data variable has four elements. data.coords returns the coords field of each element separately.data.coordsans = 0.2081 0.1663 0.5292 ans = 0.0265 0.6137 0.8135 ans = 0.6473 0.7456 0.4188 ans = 0.9763 0.9831 0.0538
Concatenating with square brackets concatenates columnwise, which creates a single 1-by-12 vector from the four 1-by-3 vectors.y = [data.coords]y = Columns 1 through 4 0.2081 0.1663 0.5292 0.0265 Columns 5 through 8 0.6137 0.8135 0.6473 0.7456 Columns 9 through 12 0.4188 0.9763 0.9831 0.0538

Concatenating Vertically

You can use the vertcat function on comma-separated lists to concatenate vertically.

Cell Arrays

The 2-by-2 cell array stored in the x variable contains four scalars.xx = [10] [20] [30] [40]
Extract multiple outputs from x and concatenate vertically.vertcat(x{:})ans = 10 30 20 40

Structure Arrays

The structure array stored in the data variable has four elements.data.coordsans = 0.2081 0.1663 0.5292 ans = 0.0265 0.6137 0.8135 ans = 0.6473 0.7456 0.4188 ans = 0.9763 0.9831 0.0538
Stack the data verticallyx = vertcat(data.coords)x = 0.2081 0.1663 0.5292 0.0265 0.6137 0.8135 0.6473 0.7456 0.4188 0.9763 0.9831 0.0538

Concatenating into a Cell Array

If your comma-separated list contains data that cannot be combined into a homogeneous array, then you can combine it into a cell array using curly braces.

y is a 3-element structure with fields name and priceyy = 1×3 struct array with fields: name price
The name fields contains the name of fruits.y.nameans = ‘Banana’ ans = ‘Apple’ ans = ‘Orange’
Those names can be put into cells and concatenated into a cell array using curly braces.{y.name}ans = {‘Banana’} {‘Apple’} {‘Orange’}

How Do You Create and Use a Function Handle?

Create a Function Handle to a Defined Function

Use the @ symbol to create a function handle referencing an existing function. You can reference a MATLAB function, a local function, or a function defined in a function file.

Create a Function Handle to a Specific Command

These are called anonymous functions. Again, you use the @ symbol. Specify inputs with parentheses.

Here, the function handle g has three inputs: ab, and .

Using Function Handles

Once defined, the function handles f and g can be used the same way. They can be called with inputs or passed as an input to another function.

Construct a function handle with an @ sign.h = @sin;
Call the function handle in the same way that you would call the function directly.h(0)ans = 0h(pi/2)ans = 1
Some functions, such as integral, require an input function. In this case, pass a function handle as an input.integral(h,0,pi)ans = 2.0000integral(@log,1,2)ans = 0.3863

How Do You Apply Functions to Arrays?

Apply a Function to Each Element of an Array

You can apply a function to each element of an array with arrayfun. The arrayfun function works on any array.

>> B = arrayfun(func,A)
BAn array whose elements are the output of func operating on each element of A.
funcA function handle
AAn array

If func returns scalars of the same data type, then B is an array of that data type. If the outputs of func are non-scalar or non-uniform, set the "UniformOutput" property to false. In this case, B is a cell array.

  B = arrayfun(func,A,"UniformOutput",false)
    

Applying a Function to the Contents of a Cell Array

You can apply a function to the contents of each element of a cell array with cellfun.

>> B = cellfun(func,C)
BAn array whose elements are the output of func operating on each element of C.
funcA function handle
CA cell array

Use the "UniformOutput" property to specify that the output of func is either not a scalar or non-uniform.

  B = cellfun(func,C,"UniformOutput",false)
    

Applying Functions to Rows or Variables of a Table

The varfun and rowfun functions allow you to apply a function to columns or rows of a table, respectively. They have very similar syntax.

Applying a Function to the Rows of a Table

rowfun allows you to perform calculations on rows.Table Functions

>> B = rowfun(func,tbl)
BA table or timetable where the ith row is equal to func(A{i,:}).
funcA function to apply to rows of the table.
tblA table or timetable.

The following name-value pairs can be used with both rowfun.

  • "InputVariables": Specify which variables to pass to func as a string array. These elements are passes as separate inputs to the function.
  • "GroupingVariables": Specify one or more variables that define groups of rows as a string array.
  • "OutputVariableNames": Specify the names for the outputs of func.

Applying a Function to the Variables of a Table

varfun allows you to perform calculations on specific variables.Table Functions

>> B = varfun(func,tbl)
BA table or timetable containing the calculations on the specified columns.
funcA function to apply to columns of the table.
tblA table or timetable.

The following name-value pairs can be used with both varfun.

  • "InputVariables": Specify which variables to pass to func as a string array. These elements are passes as separate inputs to the function.
  • "GroupingVariables": Specify one or more variables that define groups of rows as a string array.

  • Structuring Heterogeneous Data
  • Extracting Multiple Elements from Cell and Structure Arrays
  • Function Handles
  • Applying Scalar Functions to Arrays
  • Converting Data Types

Converting Data Types

MATLAB provides conversion functions of the form typeA2typeB to convert between datatypes.

 The table below summarizes most of the functions available in MATLAB to convert between data types.


4. Optimizing Your Code

Data Types and Memory

Data Types with Fixed Memory Requirement

Some homogeneous data types require a fixed amount of memory per element.

The amount of memory required by a data type increases
with the range or precision of values that the data type can express.

Container Data Types

Container variables (tables, cell arrays, and structure arrays) require overhead in addition to the data they store. This additional memory is used to store information about the contents of the variable. The amount of the overhead depends on the size of the variable.

Each cell of a cell array requires memory overhead.

Product or brand names of cars are trademarks or registered trademarks of their respective holders.

In the example below, you can see how to calculate the total memory of a cell array of character vectors.

headquarters = 'Natick, MA';

Data Type – 

char

Memory – 20 Bytes
(10 characters, 2 bytes each)

headquarters = {'Natick, MA'};

Data Type – 

cell

Memory – 132 Bytes
(112 bytes for cell array element,
20 bytes for characters)

headquarters = {'Natick' 'MA'}

Data Type – 

cell

Memory – 240 Bytes
(112 bytes for each element of the cell array,
12 + 4 bytes for the character vectors)


Preallocation

Preallocating Numeric Arrays

You can use the functions zeros and ones to preallocate numeric arrays.

By default, zeros and ones create an array having the datatype double.x = zeros(1,50000);
You can create an array having other datatypes by specifying an additional input.x = zeros(1,50000,’single’); y = zeros(1,50000,’int16′);
Another way to preallocate an array is to assign a value to the last element of the array.x(8) = 3; x = 0 0 0 0 0 0 0 3

Preallocating Cells and Structures

You can also preallocate non-numeric data types, such as cell arrays and structure arrays.Think of these arrays as consisting of the containers (cells and structures) and the contents (any datatype and size).

Preallocating a cell array or a structure array assigns space for the containers themselves, not the contents. This means that preallocation of the container variables is most beneficial when the container array itself is large, regardless of the size of the contents of the individual containers.You can preallocate a cell array using the function cell.

C = cell(1,4);                                     cell array headers

 To preallocate a structure array, start by defining the last element of the array. MATLAB will automatically replicate the field names to all of the preceding elements in the array.

S(5) = struct(‘field1′,6,’field2’,7)structure array

Summary – Optimizing Your Code

Measuring Performance and Finding Bottlenecks

To measure the execution time of MATLAB code, you can use the tic and toc functions.

Start timertic
Run codex = rand(1000);
Stop timer, report resultstocElapsed time is 1.206429 seconds.

To improve the performance of your code, you should first understand what parts of it take the most time. The MATLAB Profiler analyzes where your code spends the most time.

Using Vectorized Operations

Vectorized code is more concise and faster than the non-vectorized solutions.Using a for loop

nonVectorized.mlx

% Generate datar = rand(1,5000); % Compute the difference between% the adjacent elementsd = zeros(1,4999);for i=1:4999d(i) = r(i+1)-r(i);end

Using vectorization

vectorized.mlx

% Generate datar = rand(1,5000); % Compute the difference between% the adjacent elementsd = diff(r);

Improving Memory Usage in Functions

Scripts and functions that call each other often need to share data. Passing inputs to functions is one way functions can share data.


5. Creating Flexible Functions

Allowing Different Input Types

In some cases, you can leave inputs in their original type. For example, many mathematical operations will work on any numeric type. MATLAB also performs some conversions as needed. For example, numeric variables can be used in logical contexts, in which case they are automatically converted to logical (with zero becoming false and all non-zero becoming true).In other cases, you can use conversion functions to force any allowed input type into the desired type.

Representations of Data Types

Multiple data types that can hold the same piece of information.

DataPotential representations
TextChar, string, cell array of char vectors
NumbersAny numeric type (doublesingleint*uint*)
DatesDatetime, numeric array (representing components, such as day, month, year), text
Discrete categoriesCategorical, text, logical (for only two categories), numeric

Converting Between Data Types

DataConversion functions
Textcharcellstrstring
convertCharsToStrings,convertStringsToChars
Numbersdoublesingleint*uint*
Datesdatetime
Discrete categoriescategorical

Note that these functions all leave the inputs unchanged if they are already in the desired type.
That is, if t is a datetime variable, t = datetime(t); will have no effect.

Converting Text Inputs

The convertCharsToStrings and convertStringsToChars functions convert all text inputs to one uniform type with a single function call.

[a,b,c,d] = convertCharsToStrings({‘hello’,’world’},42,[“this”;”is”;”text”],’so is this’) a = 1×2 string array “hello” “world” b = 42 c = 3×1 string array “this” “is” “text” d = “so is this”

Only the text data types were converted to strings. The variable b is type double.


Querying Inputs

MATLAB includes numerous functions that test a particular attribute of a variable and return a logical result. These function names typically start with the word is.

Querying Data Type

FunctionReturns
isnumericTrue if input is numeric (single, double, int*, uint*)
isfloatTrue if input is of floating point type (single or double)
isintegerTrue if input is of integer type (int* or uint*)
ischarTrue if input is of char type
isstringTrue if input is of string type
iscellstrTrue if input is a cell array of char vectors
isdatetimeTrue if input is a datetime
isdurationTrue if input is a duration
iscalendardurationTrue if input is a calendar duration
islogicalTrue if input is of logical type
iscategoricalTrue if input is of categorical type
istableTrue if input is a table
istimetableTrue if input is a timetable
iscellTrue if input is a cell array
isstructTrue if input is a structure
isaTrue if input is of a specified data type
className of the input data type

Querying Size and Shape

FunctionReturns
sizeArray size
lengthLength of largest array dimension
numelTotal number of array elements
ndimsNumber of array dimensions
isemptyTrue if input is empty
isscalarTrue if input is a scalar
isvectorTrue if input is a vector
ismatrixTrue if input is a matrix
isrowTrue if input is a row vector
iscolumnTrue if input is a column vector

Summary – Creating Flexible Functions

Creating Multiple Interfaces

Use multiple wrapper functions that use the same underlying algorithm. Each wrapper function can present a different interface to users for different applications.

Most users can use interface2. Advanced users can use advancedInterface (or call the algorithm directly).

Setting Default Inputs

To check if all the inputs were provided in the function call, you can use the function nargin. When called within the function body, nargin returns the number of inputs that were passed when the function was called.narginNumber of input arguments
To allow the users to specify certain inputs (but not others), use an empty array [].

  • In the function body – check if the input is empty using the function isempty. If it is empty, assign a default value.
  • In the function call – use an empty array [] instead of the input value.
Function Callloanint = interest(500,[],3.1,”compound”)Editorfunction int = interest(p,n,r,type) if isempty(n) n = 12; end

Variable Length Input Arguments

You can map multiple input arguments (e.g. a set of name-value pairs) to a single input variable varargin in the function definition.

Function CallanalyzeAndPlot(time,position,”LineWidth”,3,”Color”,”r”)Editorfunction analyzeAndPlot(x,y,varargin)

Matching Text Inputs

Use validatestring to ensure that any user input is exactly as you expect (including type and capitalization), without overly constraining your user. If the input text does not unambiguously match any of the valid strings, validatestring generates an error.

str = validatestring(“distribution”,[“DistanceMetric”,”DistributionName”,”NumSamples”]) str = “DistributionName”
str = validatestring(“dist”,[“DistanceMetric”,”DistributionName”,”NumSamples”]) Expected input to match one of these values: “DistanceMetric”, “DistributionName”, “NumSamples” The input, dist, matched more than one valid value.
str = validatestring(“Algorithm”,[“DistanceMetric”,”DistributionName”,”NumSamples”]) Expected input to match one of these values: “DistanceMetric”, “DistributionName”, “NumSamples” The input, “Algorithm”, did not match any of the valid values.

Variable Number of Outputs

Similar to how you handle a variable number of inputs, you can use nargout to determine how many outputs were requested when a function was called. You can use varargout to represent any number of output arguments.

Function Call[x,y,z] = myfun(1,2,3)Editorfunction [a,varargout] = myfun(p,q,r)


6. Creating Robust Applications

Summary – Creating Robust Applications

Private Functions

To prevent your application’s internal functions from being accessible outside the application, you can place them in a folder named private.

A private folder is just a regular folder with the name private

Local Functions

To create local functions, place them below the primary function in the same code file.findShapes.mlx

function findShapes %Primary function...end function detectCircle %Local function...end function detectSquare %Local function...end

Generating Custom Warning and Errors

You can use the warning and error functions to generate custom warnings and errors.warningGenerate a custom warning messageerrorGenerate a custom error message
Error

error(“MyProject:invalidValue”,… “The value must be numeric.”);
The value must be numeric.

Warning

warning(“MyProject:ValueOutOfRange”,… “The value must be between 1 and 10.”)
The value was expected to be between 1 and 10.

Validating Function Inputs

To check multiple attributes of a given input, use the function validateattributes.validateattributesCheck multiple attributes of a given variable.

Command Windowint = calculateInterest(500,2,-0.03) Expected input to be a scalar with value >= 0.Editorfunction interest = calculateInterest(p,n,r) validateattributes(“r”,”numeric”,… {‘scalar’,’>=’,0}) …

Catching and Handling Errors

The try/catch construct attempts to run the code within the try block. If an error condition occurs, then the execution is interrupted and switched immediately into the catch block.

try
    % Attempt code
catch mexc
    % Backup case – something went wrong
    % An MException object called mexc now exists
end

7. Verifying Application Behavior

Writing a Test Script

A test script is a MATLAB script that checks that the outputs of MATLAB files are as you expect. To create a test script, use the assert function to create tests and separate the tests into sections.Code sections allow you to compile multiple tests into a single file. The section header describes the test.

Each section of a test script maintains its own workspace. Thus, in each section, you must define all needed variables.


Creating a Test Function

A test function follows a specific template:

The name of the main function:starts or ends with the case-insensitive word “test”has the same name as the function file.
The main function hasno inputsone output, here testA. The variable testA is a test array created by functiontests with the input localfunctions.
function testA = mainFunctionNameTest testA = functiontests(localfunctions); end
The local functions:contain the testshave names that start or end with the case-insensitive word “test”have a single input, here testCase
Many simple function-based unit tests will not use the input to the local functions, but it should always be included. Tests that verify behavior (e.g. warnings or errors) or allow for shared variables between tests use this input explicitly.
function testName1(testCase) % code for test 1 end function testName2(testCase) % code for test 2 end

Each test goes in its own local function.You run the test function the same way you run a test script.

result = runtests("mainFunctionNameTest");

Verification Functions

There are many qualification functions available in the function-based testing framework.

Verification functions available for function-based tests
verifyClass verifyEmpty verifyEqual verifyError verifyFail verifyFalse verifyGreaterThan verifyGreaterThanOrEqual verifyInstanceOf verifyLength verifyLessThan verifyLessThanOrEqual verifyMatchesverifyNotEmpty verifyNotEqual verifyNotSameHandle verifyNumElements verifyReturnsTrue verifySameHandle verifySize verifySubstring verifyThat verifyTrue verifyWarning verifyWarningFree

The local test functions have a single input, named testcase in the example below. Your test code should use it as the first input to the verification function.


Pre- and Post-Test Tasks

You can add pre- and post-test tasks to your testing function by adding functions with the special names setupOnce and teardownOnce which have the same signature as the other test functions.

In this example, the test code and the application code are in separate locations. You will use the application folder in the teardown function. So, rather than redefining it, you can save it in the testCase variable to the TestData property. This property is a structure variable to which you can add fields as you desire. Any fields that are added to this variable are accessible by all functions in the test function file.function setupOnce(testCase) % save the name of the application folder you will add % to the TestData structure testCase.TestData.appDir = … fullfile(“C:”,”class”,”work”,”ApplicationDirectory”); % add the application folder to the path for testing addpath(testCase.TestData.appDir) end
Now, remove the directory from the path in the teardownOnce function. See that the variable you previously defined, appDir, is accessible through testCase.TestData. Note that the structure TestData is named automatically, whereas you can name the function input, testCase in this example, whatever you want.function teardownOnce(testCase) % removes the added path rmpath(testCase.TestData.appDir) end

8. Debugging Your Code

Suppressing and Fixing Code Analyzer Warnings

For some warnings, the Code Analyzer can help you automatically fix the code.

Mousing over the orange dash or the highlighted portion of the code shows you the code analyzer warning.

When the Code Analyzer does not provide an automatic fix, you can either fix the warning yourself, or suppress it.

Other issues flagged by the code analyzer do not have a simple fix.

Suppressing warnings can be a helpful way to demonstrate that the issue has been considered. This means developers in the future won’t spend time worrying about a nonexistent problem with the code.


Debugging Run-Time Errors

When debugging MATLAB code, a common workflow is as follows.

Note that, before making a fix to your code, you should always stop your debugging session first so that you can save your changes.

If you want to enter debug mode immediately when an uncaught error is generated, you can enable the Pause on Errors option.

Automatically break on an error


9. Organizing Your Projects

Summary – Organizing Your Projects

Running Folder Reports

To run a folder report on the current folder, access the Reports menu from the Current Folder Actions menu.

MATLAB Projects

MATLAB Projects help manage code spread across multiple files. They are also using for sharing code with others.

Source Control

Source control enables you to keep track of and manage previous versions of your project.

This course uses Git with MATLAB Projects.


10. Conclusion

Pages: 1 2 3 4 5

Create Account



Log In Your Account