このページの内容は最新ではありません。最新版の英語を参照するには、ここをクリックします。
MATLAB Coder を使用した外部 C コードのユニット テスト
この例では、MATLAB® Coder™ で MATLAB® ユニット テストを使用して外部 C コードをテストする方法を示します。
C コードをテストする場合、MATLAB Coder を使用して MATLAB にコードを取り込みます。次に、MATLAB テスト フレームワークを使用してユニット テストを記述します。MATLAB の高度な数値計算や可視化機能を利用して、柔軟で豊富なテストを作成できます。
以下の例では、次のような操作方法を説明します。
C コードを MATLAB Coder を使用して生成する MEX 関数として MATLAB に取り込みます。
MATLAB テスト フレームワークを使用してユニット テストを記述します。
MEX 関数上でテストを実行します。
Embedded Coder® をお持ちの方は、ソフトウェアインザループ (SIL) またはプロセッサインザループ (PIL) 実行によるユニット テストを使用して、生成されたスタンドアロン コード (スタティック ライブラリまたは共有ライブラリ) 上でテストを実行できます。
ファイルの確認
この例で使用するファイルにアクセスするには、[Open Script] をクリックします。
kalmanfilter.c
kalmanfilter.c
は、例でテストされる C 関数です。移動するオブジェクトの位置を、その過去の位置に基づいて推定します。
kalmanfilter.h
kalmanfilter.h
は、kalmanfilter.c
のヘッダー ファイルです。
position.mat
position.mat
には、オブジェクトの位置が含まれます。
callKalmanFilter.m
callKalmanFilter
は、coder.ceval
を使用して kalmanfilter
を呼び出します。
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 loop for idx = 1: numPts z = position(:,idx); % Get the input data % Call the initialize function coder.ceval('kalmanfilter_initialize'); % Call the C function coder.ceval('kalmanfilter',z,coder.ref(y)); % Call the terminate function coder.ceval('kalmanfilter_terminate'); a(:,idx) = [z(1); z(2)]; b(:,idx) = [y(1); y(2)]; end end
TestKalmanFilter.m
TestKalmanFilter
は、予測位置と実際の位置の間の誤差が指定された許容誤差を超えているかどうかテストします。ユニット テストはクラスベースのユニット テストです。詳細については、MATLAB でのクラスベースのユニット テストの作成を参照してください。
MEX 関数をテストする場合でも、TestKalmanFilter
でのユニット テストは、生成された MEX 関数から元の MATLAB 関数を呼び出します。MATLAB Coder がテストを実行する場合、MATLAB 関数の呼び出しは MEX 関数の呼び出しに置き換えられます。MATLAB は callKalmanFilter
内の coder.ceval
呼び出しを認識しないため、これらのテストを MATLAB で直接実行することはできません。
classdef TestKalmanFilter < matlab.unittest.TestCase % Copyright 2014 - 2016 The MathWorks, Inc. methods ( Test ) function SSE_LessThanTolerance( testCase ) load position.mat; [z,y] = callKalmanFilter( position ); tolerance = 0.001; % tolerance of 0.0001 will break A = z-1000*y; error = sum(sum(A.^2)); testCase.verifyLessThanOrEqual( error, tolerance); % For debugging plot_kalman_filter_trajectory(z,1000*y); end function SampleErrorLessThanTolerance( testCase ) load position.mat; [z,y] = callKalmanFilter( position ); tolerance = 0.01; % tolerance of 0.001 will break A = z-1000*y; testCase.verifyEqual(1000*y, z, 'AbsTol', tolerance); % For debugging plot_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) ']']); end end end
run_unit_tests_kalman.m
run_unit_tests_kalman
は runtests
を呼び出して、TestKalmanFilter.m
でテストを実行します。
% Run unit tests % Copyright 2014 - 2016 The MathWorks, Inc. runtests('TestKalmanFilter')
plot_kalman_filter_trajectory.m
plot_kalman_filter_trajectory
は、オブジェクトの推定位置と実際の位置の軌跡をプロットします。各ユニット テストはこの関数を呼び出します。
MATLAB Coder アプリでの MEX の生成およびユニット テストの実行
MATLAB Coder アプリを開くには、MATLAB のツールストリップの [アプリ] タブの [コード生成] の下で、MATLAB Coder アプリのアイコンをクリックします。
コード生成の準備をするには、アプリの手順を進めます。
[ソース ファイルの選択] ページで、エントリポイント関数に
callKalmanFilter
を指定します。[入力の型を定義] ページで、入力引数
x
に 2 行 310 列の double の配列を指定します。
ユニット テストは変数 position
を position.mat
から読み込み、position
を callKalmanFilter
に渡します。したがって、callKalmanFilter
への入力には position
がもっているプロパティが指定されていなければなりません。MATLAB ワークスペースで、position.mat
を読み込むと、position
が 2 行 310 列の double の配列であることがわかります。
この例では、[実行時の問題の確認] ステップを省略します。
MEX コード生成のアプリを設定します。callKalmanFilter
が外部 C コードを統合しているため、C ソースおよびヘッダー ファイルの名前を指定します。
[ビルド タイプ] には、
MEX
を指定します。[詳細設定] をクリックします。
[カスタム コード] タブで次のように設定します。
[生成されたファイルのカスタム C コード] で、[ヘッダー ファイル] を選択します。カスタム コード フィールドで、
#include "kalmanfilter.h"
と入力します。[追加ソース ファイル] フィールドで、
kalmanfilter.c
と入力します。
MEX 関数を生成するには、[生成] をクリックします。
生成された MEX 上でユニット テストを実行します。
[コードの検証] をクリックします。
テスト ファイルのフィールドで、
run_unit_tests_kalman
を指定します。[次を使用して実行] を [生成コード] に設定していることを確認します。
[生成されたコードの実行] をクリックします。
アプリがテスト ファイルを実行すると、ユニット テストの callKalmanFilter
の呼び出しが callKalmanFilter_mex
の呼び出しに置き換えられます。ユニット テストは元の MATLAB 関数ではなく MEX 関数上で実行されます。
アプリはテスト出力を [テスト出力] タブに表示します。ユニット テストをパスしました。
プロットから、推定位置の軌跡が実際の位置の軌跡に収束することがわかります。
C コード変更後のユニット テストの実行
C コードを変更する場合に、ユニット テストを実行するには、次の手順に従います。
C コードを呼び出す MATLAB 関数の MEX 関数を再生成します。
検証のステップを繰り返します。
たとえば、y[r2]
に割り当てられている値に 1.1 を乗算するように kalmanfilter.c
を変更します。
y[r2] += (double)d_a[r2 + (i0 << 1)] * x_est[i0] * 1.1;
アプリを使用して編集できるのは、アプリの [ソース コード] ペインにリストされている MATLAB ファイルのみであるため、アプリの外部で kalmanfilter.c
を編集します。
変更された関数の MEX 関数を生成するには、[生成] をクリックします。
ユニット テストを実行するには、次の手順に従います。
[コードの検証] をクリックします。
テスト ファイルを
run_unit_tests
に、[次を使用して実行] を [生成コード] に設定していることを確認します。[生成されたコードの実行] をクリックします。
誤差が指定された許容誤差を超えるため、テストに失敗します。
プロットは、推定位置の軌跡と実際の位置の軌跡の間の誤差を示します。
コマンド ライン ワークフローを使用した MEX の生成およびユニット テストの実行
coder.runTest
を使用して外部 C コードでユニット テストを実行するために、コマンド ライン ワークフローを使用できます。C コードを呼び出す MATLAB 関数でユニット テストを実行するテスト ファイルを指定します。
C コードを呼び出す MATLAB 関数の MEX 関数を生成します。この例では、callKalmanFilter
の MEX を生成します。
MEX コード生成用の構成オブジェクトを作成します。
cfg = coder.config('mex');
外部ソース コードおよびヘッダー ファイルを指定します。
cfg.CustomSource = 'kalmanfilter.c'; cfg.CustomHeaderCode = '#include "kalmanfilter.h"';
callKalmanFilter
への入力の型を決定するには、位置ファイルを読み込みます。
load position.mat
MEX 関数を生成するには、codegen
を実行します。callKalmanFilter
への入力に position
と同じ型を指定します。
codegen -config cfg callKalmanFilter -args position
Code generation successful.
ユニット テストを MEX 関数上で実行します。テスト ファイルに run_unit_tests_kalman
を、関数に callKalmanfilter
を指定します。coder.runTest
がテスト ファイルを実行する場合、ユニット テストの callKalmanFilter
の呼び出しが callKalmanFilter_mex
の呼び出しに置き換えられます。ユニット テストは元の MATLAB 関数ではなく MEX 関数上で実行されます。
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. 21.8139 seconds testing time.