Custom Set Metadata When Writing Timetable Data to MDF-Files
This example shows how to custom set file, channel group, and channel metadata when writing timetable data to an MDF-file. The MAT-file used in this example MDFTimetables.mat
contains two timetables.
Timetable
TT1
has variables of numeric data types including uint8, uint16, uint32, uint64, int8, int16, int32, int64, single and double.Timetable
TT2
has variables of string and byte array data types including both fixed-length and variable-length data.
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 advanced workflow if there is a need to custom set metadata when writing to an MDF-file.
Before proceeding further in this example, it is recommended that you first learn about the MDF-file structure and the basic workflow demonstrated in example Get Started with 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")
Create a New MDF-File with Custom Set File Metadata
Obtain a structure that contains default file metadata using function mdfInfo
with no input argument. Note that the returned structure only contains a subset of file metadata fields that are settable.
info = mdfInfo
info = struct with fields:
Author: ''
Department: ''
Project: ''
Subject: ''
Comment: ''
Version: '4.20'
InitialTimestamp: NaT
Creator: [1×1 struct]
Set the Author
and Comment
fields to provide more information about the file.
info.Author = 'Alice Author'; info.Comment = 'Demonstrate how to set file metadata when creating an MDF-file';
Change Version
from default to '4.10'
.
info.Version = '4.10';
Set the Comment
field of Creator
to provide more information about the file creation.
info.Creator.Comment = 'Created using MATLAB for demonstration';
View the updated structure.
info
info = struct with fields:
Author: 'Alice Author'
Department: ''
Project: ''
Subject: ''
Comment: 'Demonstrate how to set file metadata when creating an MDF-file'
Version: '4.10'
InitialTimestamp: NaT
Creator: [1×1 struct]
info.Creator.Comment
ans = 'Created using MATLAB for demonstration'
Use function mdfCreate
with optional argument FileInfo
set to the file information structure with updated values. This creates a new skeleton MDF-file TimetableAdvanced.mf4
on disk. The updated metadata values are applied for the custom set fields, while default values are applied for the rest.
mdfCreate("TimetableAdvanced.mf4", FileInfo=info)
ans = "C:\Users\michellw\OneDrive - MathWorks\Documents\MATLAB\ExampleManager\michellw.MDFExamples2\vnt-ex42503333\TimetableAdvanced.mf4"
Examine the File Metadata
To confirm that the created MDF-file has file metadata correctly applied, call mdfInfo
again with the MDF-file name specified and examine the returned structure.
info1 = mdfInfo("TimetableAdvanced.mf4")
info1 = struct with fields:
Name: 'TimetableAdvanced.mf4'
Path: 'C:\Users\michellw\OneDrive - MathWorks\Documents\MATLAB\ExampleManager\michellw.MDFExamples2\vnt-ex42503333\TimetableAdvanced.mf4'
Author: 'Alice Author'
Department: ''
Project: ''
Subject: ''
Comment: 'Demonstrate how to set file metadata when creating an MDF-file'
Version: '4.10'
ProgramIdentifier: 'MATLAB'
InitialTimestamp: 2021-12-20 21:31:42.000000000
Creator: [1×1 struct]
Attachment: [0×1 struct]
info1.Creator.Comment
ans = 'Created using MATLAB for demonstration'
Custom Set Channel Group and Channel Metadata
Function mdfAddChannelGroupMetadata
adds default or inferred channel group and channel metadata to an input timetable as custom properties and returns the resulting timetable. Use this function to set up default metadata that serves as a basis for further customization.
Add channel group and channel metadata to TT1
and assign the resulting timetable to a new variable TT1WithMetadata
.
TT1WithMetadata = mdfAddChannelGroupMetadata(TT1)
TT1WithMetadata=100×10 timetable
Time uint8_data uint16_data uint32_data uint64_data int8_data int16_data int32_data int64_data single_data double_data
_______ __________ ___________ ___________ ___________ _________ __________ __________ __________ ___________ ___________
0 sec 0 200 600 1400 -99 -198 -396 -794 -9.8 -19.6
0.1 sec 2 204 608 1416 -97 -194 -388 -778 -9.6 -19.2
0.2 sec 4 208 616 1432 -95 -190 -380 -762 -9.4 -18.8
0.3 sec 6 212 624 1448 -93 -186 -372 -746 -9.2 -18.4
0.4 sec 8 216 632 1464 -91 -182 -364 -730 -9 -18
0.5 sec 10 220 640 1480 -89 -178 -356 -714 -8.8 -17.6
0.6 sec 12 224 648 1496 -87 -174 -348 -698 -8.6 -17.2
0.7 sec 14 228 656 1512 -85 -170 -340 -682 -8.4 -16.8
0.8 sec 16 232 664 1528 -83 -166 -332 -666 -8.2 -16.4
0.9 sec 18 236 672 1544 -81 -162 -324 -650 -8 -16
1 sec 20 240 680 1560 -79 -158 -316 -634 -7.8 -15.6
1.1 sec 22 244 688 1576 -77 -154 -308 -618 -7.6 -15.2
1.2 sec 24 248 696 1592 -75 -150 -300 -602 -7.4 -14.8
1.3 sec 26 252 704 1608 -73 -146 -292 -586 -7.2 -14.4
1.4 sec 28 256 712 1624 -71 -142 -284 -570 -7 -14
1.5 sec 30 260 720 1640 -69 -138 -276 -554 -6.8 -13.6
⋮
Examine the custom properties of the new timetable. Note that the properties ChannelType
, ChannelDataType
, and ChannelNumBits
were inferred by mdfAddChannelGroupMetadata
from the data stored in the corresponding timetable variable. The remaining properties were set to default values.
The first three properties displayed are metadata that apply to the entire timetable, and the remaining properties are metadata that apply to each variable. Consider a timetable represents a channel group and a variable represents a channel, the first three properties represent channel group metadata and the rest represent channel metadata.
TT1WithMetadata.Properties.CustomProperties
ans = CustomProperties with properties: ChannelGroupAcquisitionName: "" ChannelGroupComment: "" ChannelGroupSourceInfo: [1×1 struct] ChannelDisplayName: ["" "" "" "" "" "" "" "" "" ""] ChannelComment: ["" "" "" "" "" "" "" "" "" ""] ChannelUnit: ["" "" "" "" "" "" "" "" "" ""] ChannelType: [FixedLength FixedLength FixedLength FixedLength FixedLength FixedLength FixedLength FixedLength FixedLength FixedLength] ChannelDataType: [IntegerUnsignedLittleEndian IntegerUnsignedLittleEndian IntegerUnsignedLittleEndian IntegerUnsignedLittleEndian IntegerSignedLittleEndian IntegerSignedLittleEndian IntegerSignedLittleEndian … ] ChannelNumBits: [8 16 32 64 8 16 32 64 32 64] ChannelComponentType: [None None None None None None None None None None] ChannelCompositionType: [None None None None None None None None None None] ChannelSourceInfo: [1×10 struct] ChannelReadOption: [Missing Missing Missing Missing Missing Missing Missing Missing Missing Missing]
Set property ChannelGroupComment
for the timetable to provide more information about this channel group.
TT1WithMetadata.Properties.CustomProperties.ChannelGroupComment = "This channel group contains numeric data of various types.";
Set property ChannelComment
for each variable in the timetable to provide more information about each channel. You can use either the variable index or the variable name to index into the ChannelComment
property.
TT1WithMetadata.Properties.CustomProperties.ChannelComment(1) = "Unsigned 8-bit integer"; TT1WithMetadata.Properties.CustomProperties.ChannelComment(2) = "Unsigned 16-bit integer"; TT1WithMetadata.Properties.CustomProperties.ChannelComment(3) = "Unsigned 32-bit integer"; TT1WithMetadata.Properties.CustomProperties.ChannelComment(4) = "Unsigned 64-bit integer"; TT1WithMetadata.Properties.CustomProperties.ChannelComment("int8_data") = "Signed 8-bit integer"; TT1WithMetadata.Properties.CustomProperties.ChannelComment("int16_data") = "Signed 16-bit integer"; TT1WithMetadata.Properties.CustomProperties.ChannelComment("int32_data") = "Signed 32-bit integer"; TT1WithMetadata.Properties.CustomProperties.ChannelComment("int64_data") = "Signed 64-bit integer"; TT1WithMetadata.Properties.CustomProperties.ChannelComment(9) = "32-bit floating-point number"; TT1WithMetadata.Properties.CustomProperties.ChannelComment(10) = "64-bit floating-point number";
View the updated metadata for channel group and channels.
TT1WithMetadata.Properties.CustomProperties
ans = CustomProperties with properties: ChannelGroupAcquisitionName: "" ChannelGroupComment: "This channel group contains numeric data of various types." ChannelGroupSourceInfo: [1×1 struct] ChannelDisplayName: ["" "" "" "" "" "" "" "" "" ""] ChannelComment: ["Unsigned 8-bit integer" "Unsigned 16-bit integer" "Unsigned 32-bit integer" "Unsigned 64-bit integer" "Signed 8-bit integer" "Signed 16-bit integer" "Signed 32-bit integer" … ] ChannelUnit: ["" "" "" "" "" "" "" "" "" ""] ChannelType: [FixedLength FixedLength FixedLength FixedLength FixedLength FixedLength FixedLength FixedLength FixedLength FixedLength] ChannelDataType: [IntegerUnsignedLittleEndian IntegerUnsignedLittleEndian IntegerUnsignedLittleEndian IntegerUnsignedLittleEndian IntegerSignedLittleEndian IntegerSignedLittleEndian IntegerSignedLittleEndian … ] ChannelNumBits: [8 16 32 64 8 16 32 64 32 64] ChannelComponentType: [None None None None None None None None None None] ChannelCompositionType: [None None None None None None None None None None] ChannelSourceInfo: [1×10 struct] ChannelReadOption: [Missing Missing Missing Missing Missing Missing Missing Missing Missing Missing]
Similarly, add channel group and channel metadata to TT2
and assign the resulting timetable to a new variable TT2WithMetadata
.
TT2WithMetadata = mdfAddChannelGroupMetadata(TT2)
TT2WithMetadata=10×4 timetable
Time fixed_length_string_data fixed_length_byte_array_data variable_length_string_data variable_length_byte_array_data
_____ ________________________ ____________________________ ___________________________ _______________________________
0 sec "abcd" {[255 255 255 255 255]} "zero" {[ 255 255]}
1 sec "efgh" {[ 18 35 52 69 86]} "one" {[ 18 35 52 69 86]}
2 sec "ijkl" {[ 0 1 2 3 4]} "two" {[ 0 1 2 3 4 5 6 7]}
3 sec "mnop" {[ 4 3 2 1 0]} "three" {[ 4 3 2 1 0]}
4 sec "qrst" {[255 254 253 252 251]} "four" {[ 253 252 251]}
5 sec "uvwx" {[250 249 248 247 246]} "five" {[250 249 248 247 246]}
6 sec "yzAB" {[245 244 243 242 241]} "six" {[245 244 243 242 241]}
7 sec "CDEF" {[240 239 238 237 236]} "seven" {[ 240 238 236]}
8 sec "GHIJ" {[235 234 233 232 231]} "eight" {[ 235 233 231]}
9 sec "KLMN" {[255 255 255 255 255]} "nine" {[255 255 255 255 255]}
Examine the custom properties of the new timetable.
TT2WithMetadata.Properties.CustomProperties
ans = CustomProperties with properties: ChannelGroupAcquisitionName: "" ChannelGroupComment: "" ChannelGroupSourceInfo: [1×1 struct] ChannelDisplayName: ["" "" "" ""] ChannelComment: ["" "" "" ""] ChannelUnit: ["" "" "" ""] ChannelType: [FixedLength FixedLength VariableLength VariableLength] ChannelDataType: [StringASCII ByteArray StringASCII ByteArray] ChannelNumBits: [40 40 64 64] ChannelComponentType: [None None None None] ChannelCompositionType: [None None None None] ChannelSourceInfo: [1×4 struct] ChannelReadOption: [Missing Missing Missing Missing]
Set property ChannelGroupComment
for the timetable to provide more information about this channel group.
TT2WithMetadata.Properties.CustomProperties.ChannelGroupComment = "This channel group contains string and byte array data of both fixed and variable length.";
Set property ChannelComment
for each variable in the timetable to provide more information about each channel.
TT2WithMetadata.Properties.CustomProperties.ChannelComment(1) = "String data where each sample has the same number of characters"; TT2WithMetadata.Properties.CustomProperties.ChannelComment(2) = "Byte array data where each sample has the same number of bytes"; TT2WithMetadata.Properties.CustomProperties.ChannelComment(3) = "String data where samples have varying numbers of characters"; TT2WithMetadata.Properties.CustomProperties.ChannelComment(4) = "Byte array data where samples have varying numbers of bytes";
View the updated metadata for channel group and channels.
TT2WithMetadata.Properties.CustomProperties
ans = CustomProperties with properties: ChannelGroupAcquisitionName: "" ChannelGroupComment: "This channel group contains string and byte array data of both fixed and variable length." ChannelGroupSourceInfo: [1×1 struct] ChannelDisplayName: ["" "" "" ""] ChannelComment: ["String data where each sample has the same number of characters" "Byte array data where each sample has the same number of bytes" "String data where samples have varying numbers of characters" … ] ChannelUnit: ["" "" "" ""] ChannelType: [FixedLength FixedLength VariableLength VariableLength] ChannelDataType: [StringASCII ByteArray StringASCII ByteArray] ChannelNumBits: [40 40 64 64] ChannelComponentType: [None None None None] ChannelCompositionType: [None None None None] ChannelSourceInfo: [1×4 struct] ChannelReadOption: [Missing Missing Missing Missing]
Write Data to MDF-File with Custom Set Channel Group and Channel Metadata
Now TT1WithMetadata
not only carries the data to be written into channel group 1, but also the metadata to be configured for this channel group and its channels. Same for TT2WithMetadata
.
Write the two timetables with custom set metadata to the skeleton file TimetableAdvanced.mf4
created from previous steps.
mdfWrite("TimetableAdvanced.mf4", TT1WithMetadata) mdfWrite("TimetableAdvanced.mf4", TT2WithMetadata)
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("TimetableAdvanced.mf4");
Examine the Channel Group Metadata
Examine the metadata for channel group 1 and 2.
mdfObj.ChannelGroup(1)
ans = struct with fields:
AcquisitionName: ''
Comment: 'This channel group contains numeric data of various types.'
NumSamples: 100
DataSize: 5000
Sorted: 1
SourceInfo: [1×1 struct]
Channel: [11×1 struct]
mdfObj.ChannelGroup(1).SourceInfo
ans = struct with fields:
Name: ''
Path: ''
Comment: ''
SourceType: Unspecified
BusType: Unspecified
BusChannelNumber: 0
Simulated: 0
mdfObj.ChannelGroup(2)
ans = struct with fields:
AcquisitionName: ''
Comment: 'This channel group contains string and byte array data of both fixed and variable length.'
NumSamples: 10
DataSize: 340
Sorted: 1
SourceInfo: [1×1 struct]
Channel: [5×1 struct]
mdfObj.ChannelGroup(2).SourceInfo
ans = struct with fields:
Name: ''
Path: ''
Comment: ''
SourceType: Unspecified
BusType: Unspecified
BusChannelNumber: 0
Simulated: 0
Examine the Channel Metadata
Examine the metadata for channels in channel group 1 and 2.
struct2table(mdfObj.ChannelGroup(1).Channel(:))
ans=11×13 table
Name DisplayName ExtendedNamePrefix Description Comment Unit Type DataType NumBits ComponentType CompositionType ConversionType SourceInfo
_______________ ___________ __________________ ________________________________ ________________________________ __________ ___________ ___________________________ _______ _____________ _______________ ______________ __________
{'uint8_data' } {0×0 char} {0×0 char} {'Unsigned 8-bit integer' } {'Unsigned 8-bit integer' } {0×0 char} FixedLength IntegerUnsignedLittleEndian 8 None None None 1×1 struct
{'uint16_data'} {0×0 char} {0×0 char} {'Unsigned 16-bit integer' } {'Unsigned 16-bit integer' } {0×0 char} FixedLength IntegerUnsignedLittleEndian 16 None None None 1×1 struct
{'uint32_data'} {0×0 char} {0×0 char} {'Unsigned 32-bit integer' } {'Unsigned 32-bit integer' } {0×0 char} FixedLength IntegerUnsignedLittleEndian 32 None None None 1×1 struct
{'uint64_data'} {0×0 char} {0×0 char} {'Unsigned 64-bit integer' } {'Unsigned 64-bit integer' } {0×0 char} FixedLength IntegerUnsignedLittleEndian 64 None None None 1×1 struct
{'int8_data' } {0×0 char} {0×0 char} {'Signed 8-bit integer' } {'Signed 8-bit integer' } {0×0 char} FixedLength IntegerSignedLittleEndian 8 None None None 1×1 struct
{'int16_data' } {0×0 char} {0×0 char} {'Signed 16-bit integer' } {'Signed 16-bit integer' } {0×0 char} FixedLength IntegerSignedLittleEndian 16 None None None 1×1 struct
{'int32_data' } {0×0 char} {0×0 char} {'Signed 32-bit integer' } {'Signed 32-bit integer' } {0×0 char} FixedLength IntegerSignedLittleEndian 32 None None None 1×1 struct
{'int64_data' } {0×0 char} {0×0 char} {'Signed 64-bit integer' } {'Signed 64-bit integer' } {0×0 char} FixedLength IntegerSignedLittleEndian 64 None None None 1×1 struct
{'single_data'} {0×0 char} {0×0 char} {'32-bit floating-point number'} {'32-bit floating-point number'} {0×0 char} FixedLength RealLittleEndian 32 None None None 1×1 struct
{'double_data'} {0×0 char} {0×0 char} {'64-bit floating-point number'} {'64-bit floating-point number'} {0×0 char} FixedLength RealLittleEndian 64 None None None 1×1 struct
{'time' } {0×0 char} {0×0 char} {0×0 char } {0×0 char } {'s' } Master RealLittleEndian 64 None None None 1×1 struct
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' } {0×0 char} {0×0 char} {'String data where each sample has the same number of characters'} {'String data where each sample has the same number of characters'} {0×0 char} FixedLength StringASCII 40 None None None 1×1 struct
{'fixed_length_byte_array_data' } {0×0 char} {0×0 char} {'Byte array data where each sample has the same number of bytes' } {'Byte array data where each sample has the same number of bytes' } {0×0 char} FixedLength ByteArray 40 None None None 1×1 struct
{'variable_length_string_data' } {0×0 char} {0×0 char} {'String data where samples have varying numbers of characters' } {'String data where samples have varying numbers of characters' } {0×0 char} VariableLength StringASCII 64 None None None 1×1 struct
{'variable_length_byte_array_data'} {0×0 char} {0×0 char} {'Byte array data where samples have varying numbers of bytes' } {'Byte array data where samples have varying numbers of bytes' } {0×0 char} VariableLength ByteArray 64 None None None 1×1 struct
{'time' } {0×0 char} {0×0 char} {0×0 char } {0×0 char } {'s' } Master RealLittleEndian 64 None None None 1×1 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