Generate Code That Reads Data from a File
This example shows how to generate C code from a MATLAB® function that reads data from a file.
Inspect Data File
In this example, you generate code to read mydata.csv
, a file in comma-separated values (CSV) format. This file contains measurements of the temperature of a furnace (in degrees Celsius) at various times over the course of several days. The file contains several lines of description followed the data in CSV format.
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
Create and Test Entry-Point Function
Create a MATLAB function my_readtable
to read the data file mydata.csv
. The function ignores the initial description lines and creates a MATLAB table
containing datetime
and numeric values. Because the MATLAB function readtable
is not supported for code generation, the my_readtable
function uses low-level file I/O functions like fopen
, fgetl
, fscanf
, feof
, and fclose
to open, read, and close the file.
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
This entry-point function (top-level MATLAB function for which you generate code) uses these coding patterns that make it suitable for code generation:
The size of the character vector
line
changes as the function reads each line of the initial description. Thecoder.varsize
directive instructs the code generator to produce code that dynamically allocates memory for the variableline
.The function hardcodes the column header names
'time'
and'temp'
instead of reading them from the CSV file at run time. This is because code generation requires table variable names to be compile-time constants.The variable
months
is defined as a character array instead of a string array because code generation does not support string arrays.The function preinitializes the arrays
dateAndTime
andtemperature
before populating them with actual data (in thewhile
loop).
Run the MATLAB entry-point function.
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
Use MEX Function to Test Generated Code
To test the output of code generation inside the MATLAB environment, generate and run a MEX (MATLAB executable) function. A MEX function is a compiled C/C++ function that runs in the MATLAB environment. Use the codegen
command to generate a MEX function at the command line.
In the codegen
command, specify the following data types for the input arguments to the function my_readtable
:
filename
is an unbounded variable-length stringnumRecords
is a double scalar
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')
The code generator produces the MEX function my_readtable_mex
. Run the generated MEX function using the same value you used to test the MATLAB function.
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
Generate Standalone C Code
Use the codegen
command to generate a static C library for my_readtable
. The generated library can be deployed on the target hardware.
codegen -config:lib my_readtable -args {t,0} -report
Code generation successful: To view the report, open('codegen/lib/my_readtable/html/report.mldatx')
The file I/O functions are implemented differently between the MEX function and the standalone code. For example, during MEX code generation, the code generator automatically treats fscanf
as an extrinsic function. This means that the generated MEX function dispatches the fscanf
calls to the MATLAB engine for execution. In contrast, when you generate standalone code, the code generator generates C/C++ code for the body of the fscanf
function.
If you generate a MEX function but want to generate C/C++ code for extrinsic functions, disable extrinsic function calls by setting the ExtrinsicCalls
property of the coder.MexCodeConfig
object to false
. Alternatively, in the MATLAB Coder app, on the More Settings tab, set Keep extrinsic calls to No
.
If you have Embedded Coder®, you can verify the generated standalone code by using Software-In-the-Loop (SIL) or Processor-In-the-Loop (PIL) execution before deployment. See SIL and PIL Verification for Deployment on Raspberry Pi (Embedded Coder).
See Also
load
| save
| coder.load
| coder.read
| coder.write