Main Content

Get Started with Writing Timetable Data to MDF-Files

This example shows how to write timetable data into an MDF-file. The MAT-file used in this example MDFTimetables.mat contains two timetables.

  1. Timetable TT1 has variables of numeric data types including uint8, uint16, uint32, uint64, int8, int16, int32, int64, single and double.

  2. Timetable TT2 has variables of string and byte array data types including both fixed-length and variable-length data.

Introduction

A simplified model to represent the structure of an ASAM MDF-file is a three-level hierarchy composed of the file, the channel group and the channel. A file consists of a number of channel groups; a channel group consists of a number of channels.

There are two important elements to the content of an MDF-file: the data and the metadata.

  • Signal or channel data written into an MDF-file is generally either acquired or calculated. Typical signals for an automotive application are sensor data, ECU-internal variables/states, bus traffic in a vehicle network, or internally calculated values. In most applications, data in all channels of a channel group is synchronized by time, but it is also possible for them to be synchronized by angle, distance, or index. In rare cases, there could be no synchronization domain or multiple synchronization domains. Currently, the MDF functions in MATLAB only support one synchronization domain by time.

  • Metadata are additional descriptive information about the measurement environment. They are applicable to the three hierarchical levels: the file, the channel group and the channel. Each level has a set of metadata fields defined by the ASAM MDF standard.

In this example, data in TT1 and TT2 are written into channel group 1 and 2 respectively of a new MDF-file. You should use this workflow if there is no need to custom set metadata at any of the three hierarchical levels.

If you need to custom set metadata when writing to an MDF-file, use the advanced workflow in example Custom Set Metadata When Writing Timetable Data to MDF-Files.

Load Timetables into Workspace

Load the timetable variables, TT1 and TT2, from MDFTimetables.mat into the workspace.

load("MDFTimetables.mat")

Write Timetable Data Directly to a New MDF-File

Use the mdfWrite function with the target MDF-file name and the timetable variable TT1 specified as input arguments. Because the target file TimetableBasic.mf4 does not exist yet, the function creates the file automatically and displays a warning to inform the path of the newly created file. Data in TT1 is written to the first available channel group index of the file, which is channel group 1 since TimetableBasic.mf4 is a newly created file.

mdfWrite("TimetableBasic.mf4", TT1)
Warning: Specified target file did not exist. Created file: 
/tmp/Bdoc22a_1891349_156950/tp07074cff/vnt-ex65847646/TimetableBasic.mf4

Call mdfWrite again to write TT2 to the next available channel group index 2.

mdfWrite("TimetableBasic.mf4", TT2)

Examine the Default File Metadata

Using this workflow, default values for file metadata were applied by mdfWrite while creating the MDF-file. To examine the file metadata of TimetableBasic.mf4, call mdfInfo with the MDF-file name specified.

info = mdfInfo("TimetableBasic.mf4")
info = struct with fields:
                 Name: 'TimetableBasic.mf4'
                 Path: '/tmp/Bdoc22a_1891349_156950/tp07074cff/vnt-ex65847646/TimetableBasic.mf4'
               Author: ''
           Department: ''
              Project: ''
              Subject: ''
              Comment: ''
              Version: '4.20'
    ProgramIdentifier: 'MATLAB'
     InitialTimestamp: 2022-02-26 17:55:45.000000000
              Creator: [1x1 struct]
           Attachment: [0x1 struct]

Query the Creator field of the file information structure info to examine the metadata about creator of the file.

info.Creator
ans = struct with fields:
     VendorName: 'The MathWorks, Inc.'
       ToolName: 'MATLAB'
    ToolVersion: '9.12.0.1884302 (R2022a)'
       UserName: ''
        Comment: ''

Open the MDF-File

Open access to the created MDF-file using the mdf function. You can use the returned object to examine the metadata for channel groups and channels, and to read channel data into MATLAB for verification.

mdfObj = mdf("TimetableBasic.mf4");

Examine the Channel Group Metadata

Examine the metadata for channel group 1. Metadata fields AcquisitionName, Comment and SourceInfo were assigned default values. Other fields such as NumSamples, DataSize and Sorted are dependent on the data.

mdfObj.ChannelGroup(1)
ans = struct with fields:
    AcquisitionName: ''
            Comment: ''
         NumSamples: 100
           DataSize: 5000
             Sorted: 1
         SourceInfo: [1x1 struct]
            Channel: [11x1 struct]

mdfObj.ChannelGroup(1).SourceInfo
ans = struct with fields:
                Name: ''
                Path: ''
             Comment: ''
          SourceType: Unspecified
             BusType: Unspecified
    BusChannelNumber: 0
           Simulated: 0

Similarly, examine the metadata for channel group 2.

mdfObj.ChannelGroup(2)
ans = struct with fields:
    AcquisitionName: ''
            Comment: ''
         NumSamples: 10
           DataSize: 340
             Sorted: 1
         SourceInfo: [1x1 struct]
            Channel: [5x1 struct]

mdfObj.ChannelGroup(2).SourceInfo
ans = struct with fields:
                Name: ''
                Path: ''
             Comment: ''
          SourceType: Unspecified
             BusType: Unspecified
    BusChannelNumber: 0
           Simulated: 0

Examine the Channel Metadata

To examine the metadata for channels in channel group 1, convert the channel metadata structure into a table for easier visualization. Row times of the timetable were written into a time channel, while variables of the timetable were written into respective data channels.

Metadata fields Type, DataType and NumBits were derived from the data stored in the corresponding timetable variable by mdfWrite. For instance, variable named uint8_data in TT1 contains 8-bit unsigned integers, so Type of the channel is asam.mdf.ChannelType.FixedLength (0), DataType is asam.mdf.ChannelDataType.IntegerUnsignedLittleEndian (0), and NumBits is 8.

Other metadata fields were assigned default values by mdfWrite. In the case of the time channel, Unit is known to be second, so it was assigned value 's'.

struct2table(mdfObj.ChannelGroup(1).Channel(:))
ans=11×13 table
         Name          DisplayName    ExtendedNamePrefix    Description     Comment         Unit          Type                 DataType              NumBits    ComponentType    CompositionType    ConversionType    SourceInfo
    _______________    ___________    __________________    ___________    __________    __________    ___________    ___________________________    _______    _____________    _______________    ______________    __________

    {'uint8_data' }    {0x0 char}         {0x0 char}        {0x0 char}     {0x0 char}    {0x0 char}    FixedLength    IntegerUnsignedLittleEndian       8           None              None               None         1x1 struct
    {'uint16_data'}    {0x0 char}         {0x0 char}        {0x0 char}     {0x0 char}    {0x0 char}    FixedLength    IntegerUnsignedLittleEndian      16           None              None               None         1x1 struct
    {'uint32_data'}    {0x0 char}         {0x0 char}        {0x0 char}     {0x0 char}    {0x0 char}    FixedLength    IntegerUnsignedLittleEndian      32           None              None               None         1x1 struct
    {'uint64_data'}    {0x0 char}         {0x0 char}        {0x0 char}     {0x0 char}    {0x0 char}    FixedLength    IntegerUnsignedLittleEndian      64           None              None               None         1x1 struct
    {'int8_data'  }    {0x0 char}         {0x0 char}        {0x0 char}     {0x0 char}    {0x0 char}    FixedLength    IntegerSignedLittleEndian         8           None              None               None         1x1 struct
    {'int16_data' }    {0x0 char}         {0x0 char}        {0x0 char}     {0x0 char}    {0x0 char}    FixedLength    IntegerSignedLittleEndian        16           None              None               None         1x1 struct
    {'int32_data' }    {0x0 char}         {0x0 char}        {0x0 char}     {0x0 char}    {0x0 char}    FixedLength    IntegerSignedLittleEndian        32           None              None               None         1x1 struct
    {'int64_data' }    {0x0 char}         {0x0 char}        {0x0 char}     {0x0 char}    {0x0 char}    FixedLength    IntegerSignedLittleEndian        64           None              None               None         1x1 struct
    {'single_data'}    {0x0 char}         {0x0 char}        {0x0 char}     {0x0 char}    {0x0 char}    FixedLength    RealLittleEndian                 32           None              None               None         1x1 struct
    {'double_data'}    {0x0 char}         {0x0 char}        {0x0 char}     {0x0 char}    {0x0 char}    FixedLength    RealLittleEndian                 64           None              None               None         1x1 struct
    {'time'       }    {0x0 char}         {0x0 char}        {0x0 char}     {0x0 char}    {'s'     }    Master         RealLittleEndian                 64           None              None               None         1x1 struct

Similarly, examine the metadata for channels in channel group 2. Metadata fields Type, DataType and NumBits were also derived from the data stored in the corresponding timetable variable by mdfWrite.

  • Data samples in variables fixed_length_string_data and fixed_length_byte_array_data of TT2 are fixed-length, so Type of these two channels are asam.mdf.ChannelType.FixedLength (0). Variables variable_length_string_data and variable_length_byte_array_data contain data samples with variable lengths, so Type of these two channels are asam.mdf.ChannelType.VariableLength (1).

  • For the two variables that have string data, fixed_length_string_data and variable_length_string_data, DataType is asam.mdf.ChannelDataType.StringASCII (6). For the two variables that have byte array data, fixed_length_byte_array_data and variable_length_byte_array_data, DataType is asam.mdf.ChannelDataType.ByteArray (10).

  • NumBits for a fixed-length channel is derived from the data. For a variable-length channel, NumBits has a default value of 64.

struct2table(mdfObj.ChannelGroup(2).Channel(:))
ans=5×13 table
                   Name                    DisplayName    ExtendedNamePrefix    Description     Comment         Unit            Type             DataType        NumBits    ComponentType    CompositionType    ConversionType    SourceInfo
    ___________________________________    ___________    __________________    ___________    __________    __________    ______________    ________________    _______    _____________    _______________    ______________    __________

    {'fixed_length_string_data'       }    {0x0 char}         {0x0 char}        {0x0 char}     {0x0 char}    {0x0 char}    FixedLength       StringASCII           40           None              None               None         1x1 struct
    {'fixed_length_byte_array_data'   }    {0x0 char}         {0x0 char}        {0x0 char}     {0x0 char}    {0x0 char}    FixedLength       ByteArray             40           None              None               None         1x1 struct
    {'variable_length_string_data'    }    {0x0 char}         {0x0 char}        {0x0 char}     {0x0 char}    {0x0 char}    VariableLength    StringASCII           64           None              None               None         1x1 struct
    {'variable_length_byte_array_data'}    {0x0 char}         {0x0 char}        {0x0 char}     {0x0 char}    {0x0 char}    VariableLength    ByteArray             64           None              None               None         1x1 struct
    {'time'                           }    {0x0 char}         {0x0 char}        {0x0 char}     {0x0 char}    {'s'     }    Master            RealLittleEndian      64           None              None               None         1x1 struct

Examine the Data

To verify that data was successfully written to file, read from each channel group and examine the result.

chanGrp1 = read(mdfObj, 1)
chanGrp1=100×11 timetable
     Time      uint8_data    uint16_data    uint32_data    uint64_data    int8_data    int16_data    int32_data    int64_data    single_data    double_data    time
    _______    __________    ___________    ___________    ___________    _________    __________    __________    __________    ___________    ___________    ____

    0 sec           0            200            600           1400           -99          -198          -396          -794          -9.8           -19.6         0 
    0.1 sec         2            204            608           1416           -97          -194          -388          -778          -9.6           -19.2       0.1 
    0.2 sec         4            208            616           1432           -95          -190          -380          -762          -9.4           -18.8       0.2 
    0.3 sec         6            212            624           1448           -93          -186          -372          -746          -9.2           -18.4       0.3 
    0.4 sec         8            216            632           1464           -91          -182          -364          -730            -9             -18       0.4 
    0.5 sec        10            220            640           1480           -89          -178          -356          -714          -8.8           -17.6       0.5 
    0.6 sec        12            224            648           1496           -87          -174          -348          -698          -8.6           -17.2       0.6 
    0.7 sec        14            228            656           1512           -85          -170          -340          -682          -8.4           -16.8       0.7 
    0.8 sec        16            232            664           1528           -83          -166          -332          -666          -8.2           -16.4       0.8 
    0.9 sec        18            236            672           1544           -81          -162          -324          -650            -8             -16       0.9 
    1 sec          20            240            680           1560           -79          -158          -316          -634          -7.8           -15.6         1 
    1.1 sec        22            244            688           1576           -77          -154          -308          -618          -7.6           -15.2       1.1 
    1.2 sec        24            248            696           1592           -75          -150          -300          -602          -7.4           -14.8       1.2 
    1.3 sec        26            252            704           1608           -73          -146          -292          -586          -7.2           -14.4       1.3 
    1.4 sec        28            256            712           1624           -71          -142          -284          -570            -7             -14       1.4 
    1.5 sec        30            260            720           1640           -69          -138          -276          -554          -6.8           -13.6       1.5 
      ⋮

chanGrp2 = read(mdfObj, 2)
chanGrp2=10×5 timetable
    Time     fixed_length_string_data    fixed_length_byte_array_data    variable_length_string_data    variable_length_byte_array_data    time
    _____    ________________________    ____________________________    ___________________________    _______________________________    ____

    0 sec            {'abcd'}              {[255 255 255 255 255]}                {'zero' }                 {[            255 255]}         0  
    1 sec            {'efgh'}              {[     18 35 52 69 86]}                {'one'  }                 {[     18 35 52 69 86]}         1  
    2 sec            {'ijkl'}              {[          0 1 2 3 4]}                {'two'  }                 {[    0 1 2 3 4 5 6 7]}         2  
    3 sec            {'mnop'}              {[          4 3 2 1 0]}                {'three'}                 {[          4 3 2 1 0]}         3  
    4 sec            {'qrst'}              {[255 254 253 252 251]}                {'four' }                 {[        253 252 251]}         4  
    5 sec            {'uvwx'}              {[250 249 248 247 246]}                {'five' }                 {[250 249 248 247 246]}         5  
    6 sec            {'yzAB'}              {[245 244 243 242 241]}                {'six'  }                 {[245 244 243 242 241]}         6  
    7 sec            {'CDEF'}              {[240 239 238 237 236]}                {'seven'}                 {[        240 238 236]}         7  
    8 sec            {'GHIJ'}              {[235 234 233 232 231]}                {'eight'}                 {[        235 233 231]}         8  
    9 sec            {'KLMN'}              {[255 255 255 255 255]}                {'nine' }                 {[255 255 255 255 255]}         9  

Close MDF-File

Close access to the MDF-file by clearing its variable from the workspace.

clear mdfObj