Unit Test External C Code with MATLAB Coder
This example shows how to test external C code by using MATLAB® unit tests with MATLAB® Coder™.
If you want to test C code, you can use MATLAB Coder to bring the code into MATLAB. You can then write unit tests by using the MATLAB testing framework. You can write richer, more flexible tests by taking advantage of the advanced numerical computing and visualization capabilities of MATLAB.
This example shows how to:
Bring your C code into MATLAB as a MEX function that you generate with MATLAB Coder.
Write a unit test by using the MATLAB testing framework.
Run the test on the MEX function.
如果你有嵌入ded Coder®, you can run unit tests on generated standalone code (static library or shared library) by using the unit tests with software-in-the-loop (SIL) execution or processor-in-the-loop (PIL) execution.
Examine the Files
To access the files that this example uses, clickOpen Script.
kalmanfilter.c
kalmanfilter.c
is the C function that the example tests. It estimates the position of a moving object based on its past positions.
kalmanfilter.h
kalmanfilter.h
is the header file forkalmanfilter.c
.
position.mat
position.mat
contains the positions of the object.
callKalmanFilter.m
callKalmanFilter
callskalmanfilter
by usingcoder.ceval
.
function[a,b] = callKalmanFilter(position)% Copyright 2014 - 2016 The MathWorks, Inc.numPts = size(position,2); a = zeros(2,numPts,'double');b = zeros(2,numPts,'double');y = zeros(2,1,'double');% Main loopforidx = 1: numPts z = position(:,idx);% Get the input data% Call the initialize functioncoder.ceval('kalmanfilter_initialize');% Call the C functioncoder.ceval('kalmanfilter',z,coder.ref(y));% Call the terminate functioncoder.ceval('kalmanfilter_terminate');(:, idx) = [z (1);z (2)];b (:, idx) = [y (1);y (2)];endend
TestKalmanFilter.m
TestKalmanFilter
tests whether the error between the predicted position and actual position exceeds the specified tolerance. The unit tests are class-based unit tests. For more information, seeAuthor Class-Based Unit Tests in MATLAB.
Although you want to test the MEX function, the unit tests inTestKalmanFilter
call the original MATLAB function from which you generated the MEX function. When MATLAB Coder runs the tests, it replaces the calls to the MATLAB function with calls to the MEX function. You cannot run these tests directly in MATLAB because MATLAB does not recognize thecoder.ceval
calls incallKalmanFilter
.
classdefTestKalmanFilter < matlab.unittest.TestCase% Copyright 2014 - 2016 The MathWorks, Inc.methods( Test )functionSSE_LessThanTolerance( testCase ) loadposition.mat; [z,y] = callKalmanFilter( position ); tolerance = 0.001;% tolerance of 0.0001 will breakA = z-1000*y; error = sum(sum(A.^2)); testCase.verifyLessThanOrEqual( error, tolerance);% For debuggingplot_kalman_filter_trajectory(z,1000*y);endfunctionSampleErrorLessThanTolerance( testCase ) loadposition.mat; [z,y] = callKalmanFilter( position ); tolerance = 0.01;% tolerance of 0.001 will breakA = z-1000*y; testCase.verifyEqual(1000*y, z,'AbsTol', tolerance);% For debuggingplot_kalman_filter_trajectory(z,1000*y); [value, location] = max(A(:)); [R,C] = ind2sub(size(A),location); disp(['Max value 'num2str(value)' is located at ['num2str(R)','num2str(C)']']);endendend
run_unit_tests_kalman.m
run_unit_tests_kalman
callsruntests
to run the tests inTestKalmanFilter.m
.
% Run unit tests% Copyright 2014 - 2016 The MathWorks, Inc.runtests('TestKalmanFilter')
plot_kalman_filter_trajectory.m
plot_kalman_filter_trajectory
plots the trajectory of the estimated and actual positions of the object. Each unit test calls this function.
Generate MEX and Run Unit Tests in the MATLAB Coder App
To open the MATLAB Coder app, on the MATLAB ToolstripAppstab, underCode Generation, click the MATLAB Coder app icon.
To prepare for code generation, advance through the app steps.
On theSelect Source Filespage, specify that the entry-point function is
callKalmanFilter
.On theDefine Input Typespage, specify that the input argument
x
is a 2-by-310 array of doubles.
The unit tests load the variableposition
fromposition.mat
and passposition
tocallKalmanFilter
. Therefore, the input tocallKalmanFilter
must have the properties thatposition
has. In the MATLAB workspace, if you loadposition.mat
, you see thatposition
is a 2-by-310 array of doubles.
Skip theCheck for Run-Time Issuesstep for this example.
Configure the app for MEX code generation. Specify the names of the C source and header files becausecallKalmanFilter
integrates external C code.
ForBuild type, specify
MEX
.ClickMore Settings.
On theCustom Codetab:
UnderCustom C Code for Generated Files, selectHeader file. In the custom code field, enter
#include "kalmanfilter.h"
.In theAdditional source filesfield, enter
kalmanfilter.c
.
To generate the MEX function, clickGenerate.
Run the unit tests on the generated MEX.
ClickVerify Code.
In the field for the test file, specify
run_unit_tests_kalman
.Make sure that you setRun usingtoGenerated code.
ClickRun Generated Code.
When the app runs the test file, it replaces calls tocallKalmanFilter
in the unit test with calls tocallKalmanFilter_mex
. The unit tests run on the MEX function instead of the original MATLAB function.
The app displays the test output on theTest Outputtab. The unit tests pass.
From the plots, you can see that the trajectory of the estimated position converges with the trajectory of the actual position.
Run Unit Tests After Modifying C Code
When you modify the C code, to run the unit tests:
Regenerate the MEX function for the MATLAB function that calls the C code.
Repeat the verification step.
For example, modifykalmanfilter.c
so that the value assigned toy[r2]
is multiplied by 1.1.
y[r2] += (double)d_a[r2 + (i0 << 1)] * x_est[i0] * 1.1;
Editkalmanfilter.c
outside of the app because you can use the app to edit only MATLAB files listed in the源代码pane of the app.
To generate the MEX function for the modified function, clickGenerate.
To run the unit tests:
ClickVerify Code.
Make sure that you set the test file to
run_unit_tests
andRun usingtoGenerated codeClickRun Generated Code.
The tests fail because the error exceeds the specified tolerance.
The plots show the error between the trajectory for the estimated position and the trajectory for the actual position.
Generate MEX and Run Unit Tests by Using the Command-Line Workflow
You can use the command-line workflow to run unit tests on external C code by usingcoder.runTest
. Specify a test file that runs the unit tests on the MATLAB function that calls your C code.
Generate a MEX function for the MATLAB function that calls your C code. For this example, generate MEX forcallKalmanFilter
.
Create a configuration object for MEX code generation.
cfg = coder.config('mex');
Specify the external source code and header file.
cfg.CustomSource ='kalmanfilter.c'; cfg.CustomHeaderCode ='#include "kalmanfilter.h"';
To determine the type for the input tocallKalmanFilter
, load the position file.
loadposition.mat
To generate the MEX function, runcodegen
. Specify that the input tocallKalmanFilter
有相同的类型position
.
codegen-configcfgcallKalmanFilter-argsposition
Code generation successful.
Run the units tests on the MEX function. Specify that the test file isrun_unit_tests_kalman
and that the function iscallKalmanfilter
. Whencoder.runTest
runs the test file, it replaces calls tocallKalmanFilter
in the unit test with calls tocallKalmanFilter_mex
. The unit tests run on the MEX function instead of the original MATLAB function.
coder.runTest('run_unit_tests_kalman','callKalmanFilter')
Running TestKalmanFilter Current plot held .Current plot held Max value 0.0010113 is located at [2,273] . Done TestKalmanFilter __________ ans = 1x2 TestResult array with properties: Name Passed Failed Incomplete Duration Details Totals: 2 Passed, 0 Failed, 0 Incomplete. 31.1085 seconds testing time.