メインコンテンツ

ファイルからデータを読み取るコードの生成

この例では、ファイルからデータを読み取る MATLAB® 関数から C コードを生成する方法を示します。

データ ファイルの検査

この例では、コンマ区切り値 (CSV) 形式のファイル mydata.csv を読み取るコードを生成します。このファイルには、数日間のさまざまな時点における炉の温度 (摂氏単位) の測定値が含まれています。このファイルには、CSV 形式のデータの前に数行の説明が含まれています。

type mydata.csv
Temperature of a furnace in degrees Celsius
measured at various times over a course of 
one week
time, temp
19-Aug-2021 10:32:35, 81
20-Aug-2021 10:40:28, 72
22-Aug-2021 10:19:36, 98
23-Aug-2021 11:00:02, 70
24-Aug-2021 10:54:27, 90
25-Aug-2021 11:03:00, 87

エントリポイント関数の作成とテスト

データ ファイル mydata.csv を読み取る MATLAB 関数 my_readtable を作成します。関数は最初の説明の行を無視し、datetimeと数値を含む MATLAB tableを作成します。MATLAB 関数readtableはコード生成でサポートされていないため、my_readtable 関数はfopenfgetlfscanffeoffcloseなどの低水準ファイル I/O 関数を使用してファイルを開き、読み取って、閉じます。

type my_readtable.m
function T = my_readtable(filename,numRecords) %#codegen

f = fopen(filename,"r");

% Scan and ignore a variable number of description lines at the beginning
% of the CSV file.
line = fgetl(f);
coder.varsize("line");
while(~ismember(',',line))
    line = fgetl(f);
end

% Table variable names.
names = {'time' 'temp'};

% Initialize variables. Define 'months' cell array that is used to convert
% name of month to serial number of month in the next code block.
i = 1;
months = {'Jan' 'Feb' 'Mar' 'Apr' 'May' 'Jun' 'Jul' 'Aug' 'Sep' 'Oct' 'Nov' 'Dec'};

dateAndTime = repmat(datetime,1,numRecords);
temperature = zeros(1,numRecords);

% Read each line in the CSV file till you reach EOF. Construct an array of
% datetime and double values (for time and temp columns).
while(~feof(f))
    day = fscanf(f,'%u-');
    month_name = string(fscanf(f,'%3c',1));
    month_number = find(month_name == months);
    [result,count] = fscanf(f,'-%u %u:%u:%u, %u');

    % Check that the last fscanf call read all remaining data in the line
    assert(count == 5) 

    year = result(1);
    hour = result(2);
    minute = result(3);
    second = result(4);
    dateAndTime(i) = datetime(year,month_number,day,hour,minute,second);
    temperature(i) = result(5);
    i = i + 1;
end

% Construct the table from the values read in the previous code block.
T = table(dateAndTime',temperature','VariableNames',names);
fclose(f);

end

このエントリポイント関数 (コードを生成する最上位の MATLAB 関数) では、関数をコード生成に適したものにする次のコーディング パターンを使用します。

  • 関数によって最初の各説明行が読み取られると、文字ベクトル line のサイズが変化します。coder.varsize命令により、コード ジェネレーターは、変数 line のメモリを動的に割り当てるコードを生成します。

  • 関数は、列ヘッダー名 'time' および 'temp' を、実行時に CSV ファイルから読み取るのではなくハードコードします。これは、コード生成では table 変数名がコンパイル時の定数である必要があるためです。

  • コード生成では string 配列がサポートされないため、変数 months は string 配列ではなく文字配列として定義されます。

  • 関数は、配列 dateAndTime および temperature を事前に初期化してから、それらの配列に実際のデータを格納します (while ループ内)。

MATLAB エントリポイント関数を実行します。

T_matlab = my_readtable("mydata.csv",6)
T_matlab=6×2 table
            time            temp
    ____________________    ____

    19-Aug-2021 10:32:35     81 
    20-Aug-2021 10:40:28     72 
    22-Aug-2021 10:19:36     98 
    23-Aug-2021 11:00:02     70 
    24-Aug-2021 10:54:27     90 
    25-Aug-2021 11:03:00     87 

MEX 関数を使用した、生成されたコードのテスト

MATLAB 環境内でコード生成の出力をテストするには、MEX (MATLAB 実行可能) 関数を生成し実行します。MEX 関数は、MATLAB 環境で実行されるコンパイル済みの C/C++ 関数です。コマンド ラインでcodegenコマンドを使用して MEX 関数を生成します。

codegen コマンドで、関数 my_readtable の入力引数に次のデータ型を指定します。

  • filename は制限のない可変長 string

  • numRecords は double スカラー

s = "mystring";
t = coder.typeof(s);
t.Properties.Value = coder.typeof('a',[1 inf]);

codegen my_readtable -args {t,0} -report
Code generation successful: View report

コード ジェネレーターが MEX 関数 my_readtable_mex を生成します。MATLAB 関数のテストに使用したのと同じ値を使用して、生成された MEX 関数を実行します。

T_mex = my_readtable_mex("mydata.csv",6)
T_mex=6×2 table
            time            temp
    ____________________    ____

    19-Aug-2021 10:32:35     81 
    20-Aug-2021 10:40:28     72 
    22-Aug-2021 10:19:36     98 
    23-Aug-2021 11:00:02     70 
    24-Aug-2021 10:54:27     90 
    25-Aug-2021 11:03:00     87 

スタンドアロン C コードの生成

codegen コマンドを使用して、my_readtable の C のスタティック ライブラリを生成します。生成されたライブラリはターゲット ハードウェアに展開できます。

codegen -config:lib my_readtable -args {t,0} -report
Code generation successful: View report

ファイル I/O 関数の実装は MEX 関数とスタンドアロン コードで異なります。たとえば、MEX コード生成時に、コード ジェネレーターは自動的に fscanf を外部関数として扱います。つまり、生成された MEX 関数は、実行のために MATLAB エンジンの fscanf 呼び出しをディスパッチします。対照的に、スタンドアロン コードを生成した場合、コード ジェネレーターは fscanf 関数の本体の C/C++ コードを生成します。

MEX 関数を生成するが、外部関数の C/C++ コードも生成する場合は、coder.MexCodeConfigオブジェクトの ExtrinsicCalls プロパティを false に設定して外部関数呼び出しを無効にします。あるいは、[コード生成設定] ダイアログ ボックスで外部呼び出しを維持パラメーターをオフにします。

Embedded Coder® を利用している場合、展開前にソフトウェアインザループ (SIL) またはプロセッサインザループ (PIL) 実行を使用して、生成されたスタンドアロン コードを検証できます。SIL and PIL Verification for Deployment on Raspberry Pi (Embedded Coder)を参照してください。

参考

| | | |

トピック