MATLAB Examples

Use Generated Code to Accelerate an Application Deployed with MATLAB Compiler

This example shows how to use generated code to accelerate an application that you deploy with MATLAB® Compiler. The example accelerates an algorithm by using MATLAB® Coder™ to generate a MEX version of the algorithm. It uses MATLAB Compiler to deploy a standalone application that calls the MEX function. The deployed application uses the MATLAB® Runtime which enables royalty-free deployment to someone who does not have MATLAB.

This workflow is useful when:

  • You want to deploy an application to a platform that the MATLAB Runtime supports.
  • The application includes a computationally intensive algorithm that is suitable for code generation.
  • The generated MEX for the algorithm is faster than the original MATLAB algorithm.
  • You do not need to deploy readable C/C++ source code for the application.

The example application uses a DSP algorithm that requires the DSP System Toolbox™.

Contents

Create the MATLAB Application

For acceleration, it is a best practice to separate the computationally intensive algorithm from the code that calls it.

In this example, myRLSFilterSystemIDSim implements the algorithm. myRLSFilterSystemIDApp provides a user interface that calls myRLSFilterSystemIDSim.

myRLSFilterSystemIDSim simulates system identification by using recursive least-squares (RLS) adaptive filtering. It uses dsp.VariableBandwidthFIRFilter to model the unidentified system and dsp.RLSFilter to identify the FIR filter.

myRLSFilterSystemIDApp provides a user interface that you use to dynamically tune simulation parameters. It runs the simulation for a specified number of time steps or until you stop the simulation. It plots the results on scopes.

For details about this application, see docid:dsp_examples.example-RLSFilterSystemIdentificationExample in the DSP System Toolbox documentation.

In a writable folder, create myRLSFilterSystemIDSim and myRLSFilterSystemIDApp. Alternatively, to access these files, click Open Script.

myRLSFilterSystemIDSim

function [tfe,err,pauseSim,stopSim,cutoffFreq,ff] = ...
    myRLSFilterSystemIDSim()
% myRLSFilterSystemIDSim implements the algorithm used in
% myRLSFilterSystemIDApp.
% This functions instantiates, initializes and steps through the System
% objects used in the algorithm.
%
% You can tune the cutoff frequency of the desired system and the
% forgetting factor of the RLS filter through the GUI that appears when
% myRLSFilterSystemIDApp is executed.

%   Copyright 2013-2016 The MathWorks, Inc.

%#codegen

% Instantiate and initialize System objects. The objects are declared
% persistent so that they are not recreated every time the function is
% called inside the simulation loop.
persistent rlsFilt sine unknownSys transferFunctionEstimator
if isempty(rlsFilt)
    % FIR filter models the unidentified system
    unknownSys = dsp.VariableBandwidthFIRFilter('SampleRate',1e4,...
        'FilterOrder',30,...
        'CutoffFrequency',.48 * 1e4/2);
    % RLS filter is used to identify the FIR filter
    rlsFilt = dsp.RLSFilter('ForgettingFactor',.99,...
        'Length',28);
    % Sine wave used to generate input signal
    sine = dsp.SineWave('SamplesPerFrame',1024,...
        'SampleRate',1e4,...
        'Frequency',50);
    % Transfer function estimator used to estimate frequency responses of
    % FIR and RLS filters.
    transferFunctionEstimator = dsp.TransferFunctionEstimator(...
        'FrequencyRange','centered',...
        'SpectralAverages',10,...
        'FFTLengthSource','Property',...
        'FFTLength',1024,...
        'Window','Kaiser');
end

[paramNew, simControlFlags] = HelperUnpackUDP();

tfe = 0;
err = 0;
cutoffFreq = 0;
ff = 0;
pauseSim = simControlFlags.pauseSim;
stopSim = simControlFlags.stopSim;

if simControlFlags.stopSim
    return;  % Stop the simulation
end
if simControlFlags.pauseSim
    return; % Pause the simulation (but keep checking for commands from GUI)
end

% Generate input signal - sine wave plus Gaussian noise
inputSignal = sine() +  .1 * randn(1024,1);

% Filter input though FIR filter
desiredOutput = unknownSys(inputSignal);

% Pass original and desired signals through the RLS Filter
[rlsOutput , err] = rlsFilt(inputSignal,desiredOutput);

% Prepare system input and output for transfer function estimator
inChans = repmat(inputSignal,1,2);
outChans = [desiredOutput,rlsOutput];

% Estimate transfer function
tfe = transferFunctionEstimator(inChans,outChans);

% Save the cutoff frequency and forgetting factor
cutoffFreq = unknownSys.CutoffFrequency;
ff = rlsFilt.ForgettingFactor;

% Tune FIR cutoff frequency and RLS forgetting factor
if ~isempty(paramNew)
    unknownSys.CutoffFrequency  = paramNew(1);
    rlsFilt.ForgettingFactor = paramNew(2);
    if simControlFlags.resetObj % reset System objects
        reset(rlsFilt);
        reset(unknownSys);
        reset(transferFunctionEstimator);
        reset(sine);
    end
end

end

myRLSFilterSystemIDApp

function scopeHandles = myRLSFilterSystemIDApp(numTSteps)
% myRLSFilterSystemIDApp initialize and execute RLS Filter
% system identification example. Then, display results using
% scopes. The function returns the handles to the scope and UI objects.
%
% Input:
%   numTSteps - number of time steps
% Outputs:
%   scopeHandles    - Handle to the visualization scopes            .

% Copyright 2013-2016 The MathWorks, Inc.


if nargin == 0
    numTSteps = Inf; % Run until user stops simulation.
end

% Create scopes
tfescope = dsp.ArrayPlot('PlotType','Line',...
    'Position',[8 696 520 420],...
    'YLimits',[-80 30],...
    'SampleIncrement',1e4/1024,...
    'YLabel','Amplitude (dB)',...
    'XLabel','Frequency (Hz)',...
    'Title','Desired and Estimated Transfer Functions',...
    'ShowLegend',true,...
    'XOffset',-5000);

msescope = dsp.TimeScope('SampleRate',1e4,'TimeSpan',.01,...
    'Position',[8 184 520 420],...
    'YLimits',[-300 10],'ShowGrid',true,...
    'YLabel','Mean-Square Error (dB)',...
    'Title','RLSFilter Learning Curve');

screen = get(0,'ScreenSize');
outerSize = min((screen(4)-40)/2, 512);
tfescope.Position = [8, screen(4)-outerSize+8, outerSize+8,...
    outerSize-92];
msescope.Position = [8, screen(4)-2*outerSize+8, outerSize+8, ...
    outerSize-92];

% Create UI to tune FIR filter cutoff frequency and RLS filter
%  forgetting factor
Fs = 1e4;
param = struct([]);
param(1).Name = 'Cutoff Frequency (Hz)';
param(1).InitialValue = 0.48 * Fs/2;
param(1).Limits = Fs/2 * [1e-5, .9999];
param(2).Name = 'RLS Forgetting Factor';
param(2).InitialValue = 0.99;
param(2).Limits = [.3, 1];
hUI = HelperCreateParamTuningUI(param, 'RLS FIR Demo');
set(hUI,'Position',[outerSize+32, screen(4)-2*outerSize+8, ...
    outerSize+8, outerSize-92]);

clear HelperUnpackUDP

% Execute algorithm
while(numTSteps>=0)
    
    drawnow limitrate;   % needed to process UI callbacks
    
    [tfe,err,pauseSim,stopSim] = myRLSFilterSystemIDSim();
    
    if stopSim     % If "Stop Simulation" button is pressed
        break;
    end
    if pauseSim
        continue;
    end
    
    % Plot transfer functions
    tfescope(20*log10(abs(tfe)));
    % Plot learning curve
    msescope(10*log10(sum(err.^2)));
    numTSteps = numTSteps - 1;
end

if ishghandle(hUI)  % If parameter tuning UI is open, then close it.
    delete(hUI);
    drawnow;
    clear hUI
end

scopeHandles.tfescope = tfescope;
scopeHandles.msescope = msescope;
end

Test the MATLAB Application

Run the system identification application for 100 time steps. The application runs the simulation for 100 time steps or until you click Stop Simulation. It plots the results on scopes.

scope1 = myRLSFilterSystemIDApp(100);
release(scope1.tfescope);
release(scope1.msescope);

Prepare Algorithm for Acceleration

When you use MATLAB Coder to accelerate a MATLAB algorithm, the code must be suitable for code generation.

1. Make sure that myRLSFilterSystemIDSim.m includes the %#codegen directive after the function signature.

This directive indicates that you intend to generate code for the function. In the MATLAB Editor, it enables the code analyzer to detect code generation issues.

2. Screen the algorithm for unsupported functions or constructs.

coder.screener('myRLSFilterSystemIDSim');

The code generation readiness tool does not find code generation issues in this algorithm.

Accelerate the Algorithm

To accelerate the algorithm, this example use the MATLAB Coder codegen command. Alternatively, you can use the MATLAB Coder app.

Generate a MEX function for myRLSFilterSystemIDSim.

codegen myRLSFilterSystemIDSim;

codegen creates the MEX function myRLSFilterSystemIDSim_mex in the current folder.

Compare MEX Function and MATLAB Function Performance

1. Time 100 executions of myRLSFilterSystemIDSim.

clear myRLSFilterSystemIDSim
disp('Running the MATLAB function ...')
tic
nTimeSteps = 100;
for ind = 1:nTimeSteps
     myRLSFilterSystemIDSim();
end
tMATLAB = toc;
Running the MATLAB function ...

2. Time 100 executions of myRLSFilterSystemIDSim_mex.

clear myRLSFilterSystemIDSim
disp('Running the MEX function ...')
tic
for ind = 1:nTimeSteps
    myRLSFilterSystemIDSim_mex();
end
tMEX = toc;

disp('RESULTS:')
disp(['Time for original MATLAB function: ', num2str(tMATLAB),...
     ' seconds']);
disp(['Time for MEX function: ', num2str(tMEX), ' seconds']);
disp(['The MEX function is ', num2str(tMATLAB/tMEX),...
    ' times faster than the original MATLAB function.']);
Running the MEX function ...
RESULTS:
Time for original MATLAB function: 8.8206 seconds
Time for MEX function: 0.42183 seconds
The MEX function is 20.9104 times faster than the original MATLAB function.

Optimize the MEX code

You can sometimes generate faster MEX by using a different C/C++ compiler or by using certain options or optimizations. See docid:coder_ug.bsx_ir0.

For this example, the MEX is sufficiently fast without further optimization.

Modify the Application to Call the MEX Function

Modify myRLSFilterSystemIDApp so that it calls myRLSFilterSystemIDSim_mex instead of myRLSFilterSystemIDSim.

Save the modified function in myRLSFilterSystemIDApp_acc.m.

Test the Application with the Accelerated Algorithm

clear myRLSFilterSystemIDSim_mex;
scope2 = myRLSFilterSystemIDApp_acc(100);
release(scope2.tfescope);
release(scope2.msescope);

The behavior of the application that calls the MEX function is the same as the behavior of the application that calls the original MATLAB function. However, the plots update more quickly because the simulation is faster.

Create the Standalone Application

1. To open the Application Compiler App, on the Apps tab, under Application Deployment, click the app icon.

2. Specify that the main file is myRLSFilterSystemIDApp_acc.

The app determines the required files for this application. The app can find the MATLAB files and MEX-files that an application uses. You must add other types of files, such as MAT-files or images, as required files.

3. In the Packaging Options section of the toolstrip, make sure that the Runtime downloaded from web check box is selected.

This option creates an application installer that downloads and installs the MATLAB Runtime with the deployed MATLAB application.

4. Click Package and save the project.

5. In the Package window, make sure that the Open output folder when process completes check box is selected.

When the packaging is complete, the output folder opens.

Install the Application

1. Open the for_redistribution folder.

2. Run MyAppInstaller_web.

3. If you connect to the internet by using a proxy server, enter the server settings.

4. Advance through the pages of the installation wizard.

  • On the Installation Options page, use the default installation folder.
  • On the Required Software page, use the default installation folder.
  • On the License agreement page, read the license agreement and accept the license.
  • On the Confirmation page, click Install.

If the MATLAB Runtime is not already installed, the installer installs it.

5. Click Finish.

Run the Application

1. Open a terminal window.

2. Navigate to the folder where the application is installed.

  • For Windows®, navigate to C:\Program Files\myRLSFilterSystemIDApp_acc.
  • For macOS, navigate to /Applicatons/myRLSFilterSystemIDApp_acc.
  • For Linux, navigate to /usr/myRLSFilterSystemIDApp_acc.

3. Run the application by using the appropriate command for your platform.

  • For Windows, use application\myRLSFilterSystemIDApp_acc.
  • For macOS, use myRLSFilterSystemIDApp_acc.app/Contents/MacOS/myRLSFilterSystemIDApp_acc.
  • For Linux, use /myRLSFilterSystemIDApp_acc.

Starting the application takes approximately the same amount of time as starting MATLAB.