Main Content

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

この例では、CSV ファイルからデータを読み取って table に保存する MATLAB® コードから C コードを生成する方法を示します。

データ ファイルの検査

この例の目標は、数日間にわたってさまざまな時刻に取得された炉の温度の測定値 (摂氏単位) を含むコンマ区切り値 (CSV) ファイルを読み取るコードを生成することです。このファイルの先頭には数行の説明があります。この後に、データが table 形式のコンマ区切り値としてリストされています。

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

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

ファイル mydata.csv を読み取って最初の説明行を無視し、datetimeと数値を含む MATLAB tableを作成する MATLAB® 関数 my_readtable を記述します。MATLAB 関数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 環境内でコード生成の出力をテストするには、codegenコマンドを使用して 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: To view the report, open('codegen/mex/my_readtable/html/report.mldatx')

コード ジェネレーターが MEX 関数 my_readtable_mex を生成します。生成された 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 

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

ターゲット ハードウェアに展開する my_readtable の静的な C ライブラリを生成します。

codegen -config:lib my_readtable -args {t,0} -report
Code generation successful: To view the report, open('codegen/lib/my_readtable/html/report.mldatx')

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

MEX ターゲットで、MATLAB 関数 fscanf の本体の C/C++ コードを生成する場合は、coder.MexCodeConfigオブジェクトの ExtrinsicCalls プロパティを false に設定して外部関数呼び出しを無効にします。あるいは、MATLAB Coder アプリの [詳細設定] タブで、[外部呼び出しを維持]No に設定します。

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