TDMSファイルは、3階層のオブジェクトでデータを組織化します。最上位は、作成者やタイトルなどファイル特有の情報を持つ単一オブジェクトによって構成されています。各ファイルは無制限数のグループを持つことができ、各グループは無制限数のチャンネルを持つことが可能です。以下の図に示すexample events.tdmsファイルでは、2グループに2チャンネルずつ含まれています。
各TDMSオブジェクトは、パスによって一意に識別されます。パスは、オブジェクト名およびTDMS階層内の所有者名が含まれた、/(スラッシュ)で区切られている文字列です。各名前は、'(シングル引用符)記号で囲まれます。オブジェクト名に含まれる'記号は、"(ダブル引用符)記号で置換されます。以下の表は、各種TDMSオブジェクトにおけるパス形式の例を示しています。
オブジェクト名 | オブジェクト | パス |
-- | ファイル | / |
Measured Data | グループ | /'Measured Data' |
Amplitude Sweep | チャンネル | /'Measured Data'/'Amplitude Sweep' |
Dr. T's Events | グループ | /'Dr. T''s Events' |
Time | チャンネル | /'Events'/'Time' |
すべてのTDMSクライアントアプリケーションが適切に動作するためには、各TDMSファイルにファイルオブジェクトが含まれている必要があります。また、チャンネルパスで使用されるグループ名のために、グループオブジェクトが含まれている必要があります。さらに、チャンネルを含まない任意の数のグループオブジェクトを含めることもできます。
各TDMSオブジェクトには無制限数のプロパティを付与できます。TDMSプロパティは、名前(常に文字列)、タイプ識別子、値を組み合わせたもので構成されます。プロパティの一般的なデータタイプには、整数や浮動小数点などの数値タイプ、タイムスタンプ、または文字列が挙げられます。TDMSプロパティは配列や複合データタイプはサポートしません。TDMSファイルがNIデータファインダの検索範囲内にある場合、すべてのプロパティは自動的に検索対象となります。
未処理データの配列を含むことができるのは、TDMSファイル内のチャンネルオブジェクトのみです。現在のTDMSバージョンでは、1次元配列のみがサポートされています。
各TDMSファイルには、メタデータと未処理データの2種類のデータが含まれます。メタデータは、オブジェクトまたはプロパティに含まれる説明用のデータです。チャンネルオブジェクトに追加されるデータ配列が、未処理データと呼ばれます。TDMSファイルに含まれるのは、連続したブロックの1つにおける複数チャンネル用未処理データです。TDMSファイルは、未処理データの指標を使用してそのブロックから未処理データを抽出します。未処理データ指標には、データに対応するチャンネルなどのデータブロック構成情報や、そのチャンネル用にブロックに含まれる値の数、データの格納順序に関する情報が含まれます。
データはTDMSにセグメント単位で書き込まれます。データがTDMSファイルに追加されるたびに、セグメントが新規作成されます。この規則の例外については、この記事の「未処理データ」セクションを参照してください。セグメントは、以下の3つの部分で構成されます。
この記事では、DAQmxデータのデコード方法については説明しません。TDMSはネイティブサポートされていますが、ナショナルインスツルメンツが提供する任意のコンポーネントを使用していないソフトウェアでTDMSファイルを読み取る必要がある場合、このデータを読み取ることはできません。
TDMSファイルにおけるすべての文字列(オブジェクトパス、プロパティ名、プロパティ値、未処理データ値など)は、UTF-8 Unicodeでコーディングされています。未処理データ値を除き、これらの文字列の前には、長さの値自体は含めない文字列長をビットで表した32ビット符号なし整数が付与されます。TDMS内における文字列の終端文字はNULLである場合もありますが、長さ情報が格納されているため、ファイルから読み出す際はNULL終端文字は無視されます。
TDMSのタイムスタンプは2つのコンポーネント構造で保持されています。
ブール値はそれぞれ1バイトで保持されます。1がTRUEを、0がFALSEを表します。
リードインには、セグメントの検証に使用される情報が含まれます。また、TDMSファイルへのランダムアクセスに使用される情報も含まれます。以下の例は、TDMSファイルのリードイン部分のバイナリフットプリントを示しています。
バイナリレイアウト(16進法) | 説明 |
54 44 53 6D | "TDSm"タグ |
0E 00 00 00 | ToCマスク0x1110(セグメントにはオブジェクトリスト、メタデータ、未処理データが含まれる) |
69 12 00 00 | バージョン番号(4713) |
E6 00 00 00 00 00 00 00 | 次のセグメントのオフセット(値:230) |
DE 00 00 00 00 00 00 00 | 未処理データのオフセット(値:222) |
上の表のリードイン部分には、以下の情報が含まれます。
フラグ | 説明 |
#define kTocMetaData (1L<<1) | セグメントにメタデータが含まれる |
#define kTocRawData (1L<<3) | セグメントに未処理データが含まれる |
#define kTocDAQmxRawData (1L<<7) | セグメントにDAQmx未処理データが含まれる |
#define kTocInterleavedData (1L<<5) | セグメント内の未処理データをインタリーブする(フラグが設定されない場合、データは連続的) |
#define kTocBigEndian (1L<<6) | セグメント内のすべての数値(プロパティ、未処理データなど)がビッグエンディアン形式である(フラグが設定されない場合、データはリトルエンディアン) |
#define kTocNewObjList (1L<<2) | セグメントに新規オブジェクトリストが含まれる(例:このセグメントのチャンネルが前のセグメントに含まれるチャンネルと同じでない) |
TDMSのメタデータは、ファイル、グループ、チャンネルなどデータオブジェクトの3階層で構成されます。これらのオブジェクトタイプはそれぞれ任意数のプロパティを含むことができます。メタデータセクションは、ディスク上で以下のバイナリレイアウトを取ります。
ディスク上の単一TDMSオブジェクトのバイナリレイアウトは、以下の順序のコンポーネントで構成されます。特定のセグメントに格納される情報によっては、これらのコンポーネントのサブセットのみがオブジェクトに含まれる場合もあります。
以下の表は、1つのグループと1つのチャンネル用のメタ情報の例を示しています。グループには2つのプロパティ(1つの文字列と1つの整数)が含まれています。チャンネルには未処理データ指標が含まれていますが、プロパティは含まれていません。
バイナリフットプリント(16進法) | 説明 |
02 00 00 00 | オブジェクト数 |
08 00 00 00 | 最初のオブジェクトパスの長さ |
2F 27 47 72 6F 75 70 27 | オブジェクトパス(/'Group') |
FF FF FF FF | 未処理データ指標("FF FF FF FF"は、オブジェクトに未処理データが割り当てられていないことを示す) |
02 00 00 00 | /'Group'のプロパティ数 |
04 00 00 00 | 最初のプロパティ名の長さ |
70 72 6F 70 | プロパティ名(prop) |
20 00 00 00 | プロパティ値のデータタイプ(tdsTypeString) |
05 00 00 00 | プロパティ値の長さ(文字列の場合のみ) |
76 61 6C 75 65 | propプロパティの値(値) |
03 00 00 00 | 2番目のプロパティ名の長さ |
6E 75 6D | プロパティ名(num) |
03 00 00 00 | プロパティ値のデータタイプ(tdsTypeI32) |
0E 00 00 00 | numプロパティの値(10) |
13 00 00 00 | 2番目のオブジェクトパスの長さ |
2F 27 47 72 6F 75 70 27 2F 27 43 68 61 6E 6E 65 6C 31 27 | 2番目のオブジェクトパス(/'Group'/'Channel1') |
14 00 00 00 | 指標情報の長さ |
03 00 00 00 | このオブジェクトに割り当てられた未処理データのデータタイプ |
01 00 00 00 | 未処理データ配列の次元(1である必要がある) |
02 00 00 00 00 00 00 00 | 未処理データ値の数 |
00 00 00 00 | /'Group'/'Channel1'のプロパティ数(プロパティなし) |
前のセグメント内のメタ情報と合致するメタ情報は、後続のセグメントで省略可能です。省略はオプションですが、冗長なメタ情報を省略することでファイルの読み取り速度が大幅に増加します。冗長な情報を書き込む場合、LabVIEW、LabWindows/CVI、またはMeasurementStudioで「TDMSを最適化(TDMS Defragment)」関数を使用することにより後で削除することができます。
以下の例は、上述したセグメントのすぐ後に続くセグメントのメタデータセクションのバイナリフットプリントを示しています。新規セグメントに書き込まれるメタ情報は、プロパティの新規値のみです。
バイナリレイアウト(16進法) | 説明 |
01 00 00 00 | 新規/変更オブジェクト数 |
08 00 00 00 | オブジェクトパスの長さ |
2F 27 47 72 6F 75 70 27 | オブジェクトパス(/'Group') |
FF FF FF FF | 未処理データ指標(オブジェクトに割り当てられた未処理データなし) |
01 00 00 00 | 新規/変更プロパティ数 |
03 00 00 00 | プロパティ名の長さ |
6E 75 6D | プロパティ名(num) |
03 00 00 00 | プロパティ値のデータタイプ(tdsTypeI32) |
07 00 00 00 | numプロパティの新規値(7) |
最後に、セグメントには各チャンネルに関連付けられた未処理データが含まれます。各チャンネルのデータ配列は、セグメントのメタ情報部分にチャンネルが現れる順番通りに連結されます。数値データは、リードインのリトルエンディアン/ビッグエンディングフラグに従ってフォーマットする必要があります。いったん書き込まれると、チャンネルはエンディアン形式やデータタイプを変更できない点に注意してください。
文字列タイプのチャンネルは、高速ランダムアクセス用にあらかじめ処理されます。すべての文字列は連続メモリに連結されます。連続メモリ内の各文字列における最初の文字オフセットは、符号なし32ビット整数の配列に保存されます。オフセット値の配列が最初に保存され、その後に連結された文字列値が続きます。このレイアウトによって、クライアントアプリケーションは最大3回までファイルポインタの位置を変えることにより、不要なデータを読み取ることなくファイル内のどこからでも任意の文字列値にアクセスすることができます。
セグメント間でメタ情報に変更がない場合、リードインとメタ情報の部分を完全に省略し、未処理データのみをファイルの最後に追加できます。後続の未処理データチャンクのバイナリレイアウトは同じになり、チャンク数は以下の手順でリードインとメタ情報から計算されます。
未処理データはインタリーブするものと、インタリーブしないものの2種類に分類されます。セグメントのリードイン内のToCビットマスクは、セグメント内データをインタリーブするかどうかを指定します。例:チャンネル1(1、2、3)とチャンネル2(4、5、6)に32ビット整数値を保存する場合、以下のレイアウトのようになります。
データレイアウト | バイナリフットプリント(16進法) |
インタリーブしない | 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 06 00 00 00 |
インタリーブする | 01 00 00 00 04 00 00 00 02 00 00 00 05 00 00 00 03 00 00 00 06 00 00 00 |
以下の列挙体タイプは、TDMSファイル内のプロパティやチャンネルのデータタイプを示しています。プロパティの場合、データタイプ値は名前とバイナリ値の間に保存されます。チャンネルの場合、データタイプは未処理データ指標の一部になります。
typedef enum {
tdsTypeVoid,
tdsTypeI8,
tdsTypeI16,
tdsTypeI32,
tdsTypeI64,
tdsTypeU8,
tdsTypeU16,
tdsTypeU32,
tdsTypeU64,
tdsTypeSingleFloat,
tdsTypeDoubleFloat,
tdsTypeExtendedFloat,
tdsTypeSingleFloatWithUnit=0x19,
tdsTypeDoubleFloatWithUnit,
tdsTypeExtendedFloatWithUnit,
tdsTypeString=0x20,
tdsTypeBoolean=0x21,
tdsTypeTimeStamp=0x44,
tdsTypeDAQmxRawData=0xFFFFFFFF
} tdsDataType;
メモ:
TDMSがどのように作成されるかの詳細については、TDMSファイルに書き込むVIベースのAPI(英語)を参照してください。
LabVIEW波形はTDMS内で数値チャンネルとして表されますが、波形の属性はプロパティとしてチャンネルに追加されます。
ここまで述べたきたように、フォーマット定義を適用すれば、有効なTDMSファイルを作成することはできます。ただしTDMSでは、LabVIEW、LabWindows/CVI、またはMeasurementStudioなどのNIソフトウェアで一般的も使用される多彩な最適化を行うことが可能です。NIソフトウェアで書き込んだデータの読み取りを実行するアプリケーションでは、このパラグラフで述べる最適化の仕組みをサポートする必要があります。
オブジェクトパス、プロパティ、未処理データ指標などのメタ情報は、変更があった場合のみセグメントに追加されます。増分メタ情報は、以下の例で最もよく説明できます。
最初のセグメントには、チャンネル1と2が書き込まれます。各チャンネルには、3つの32ビット整数値(1、2、3および4、5、6)といくつかの説明用プロパティが含まれます。最初のセグメントのメタ情報部分には、チャンネル1と2のパス、プロパティ、および未処理データ指標が含まれます。ToCビットフィールドのフラグであるkTocMetaData、kTocNewObjList、およびkTocRawDataが設定されます。最初のセグメントのバイナリフットプリントは下記のようになります。
部分 | バイナリフットプリント(16進法) |
リードイン | 54 44 53 6D 0E 00 00 00 68 12 00 00 8F 00 00 00 00 00 00 00 77 00 00 00 00 00 00 00 |
オブジェクト数 | 02 00 00 00 |
メタ情報(オブジェクト1) | 13 00 00 00 2F 27 67 72 6F 75 70 27 2F 27 63 68 61 6E 6E 65 6C 31 27 14 00 00 00 03 00 00 00 01 00 00 00 03 00 00 00 00 00 00 00 01 00 00 00 04 00 00 00 70 72 6F 70 20 00 00 00 05 00 00 00 76 61 6C 69 64 |
メタ情報(オブジェクト2) | 13 00 00 00 2F 27 67 72 6F 75 70 27 2F 27 63 68 61 6E 6E 65 6C 32 27 14 00 00 00 03 00 00 00 01 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 |
未処理データ(チャンネル1) | 01 00 00 00 02 00 00 00 03 00 00 00 |
未処理データ(チャンネル2) | 04 00 00 00 05 00 00 00 06 00 00 00 |
2番目のセグメントでは、プロパティに変更はなく、チャンネル1と2には依然として各3つの値が含まれ、追加のチャンネルはセグメントに書き込まれません。このセグメントにはメタデータは含まれません。前のセグメントからのメタデータが依然として有効です。未処理データビットのみがToCビットフィールドに設定されます。2番目のセグメントのバイナリフットプリントは下記のようになります。
部分 | バイナリフットプリント(16進法) |
リードイン | 54 44 53 6D 08 00 00 00 68 12 00 00 18 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
未処理データ(チャンネル1) | 01 00 00 00 02 00 00 00 03 00 00 00 |
未処理データ(チャンネル2) | 04 00 00 00 05 00 00 00 06 00 00 00 |
3番目のセグメントでは、さらに3つの値を各チャンネルに追加します。チャンネル1は、最初のセグメントでstatusプロパティをvalidに設定しましたが、今度はerrorに設定する必要があります。3番目のセグメントのメタデータセクションには、このプロパティ用のチャンネル、名前、タイプ、および値のオブジェクトパスが含まれます。今後ファイルが読み取られると、前に書き込まれたvalidという値がerrorという値で上書きされます。ただし、前のvalid値はデフラグされない限りファイル内に残ります。3番目のセグメントのバイナリフットプリントは下記のようになります。
部分 | バイナリフットプリント(16進法) |
リードイン | 54 44 53 6D 0A 00 00 00 68 12 00 00 60 00 00 00 00 00 00 00 48 00 00 00 00 00 00 00 |
オブジェクト数 | 01 00 00 00 |
メタ情報(オブジェクト1) | 13 00 00 00 2F 27 67 72 6F 75 70 27 2F 27 63 68 61 6E 6E 65 6C 31 27 14 00 00 00 03 00 00 00 01 00 00 00 03 00 00 00 00 00 00 00 01 00 00 00 04 00 00 00 70 72 6F 70 20 00 00 00 05 00 00 00 65 72 72 6F 72 |
未処理データ(チャンネル1) | 01 00 00 00 02 00 00 00 03 00 00 00 |
未処理データ(チャンネル2) | 04 00 00 00 05 00 00 00 06 00 00 00 |
4番目のセグメントでは、5つの値(7、8、9、10、11)を含む別のチャンネル(voltage)を追加します。前のセグメントからの他のすべてのメタデータは依然として有効であるため、4番目のセグメントのメタデータセクションにはvoltageチャンネル用のみのオブジェクトパス、プロパティ、指標情報が含まれます。未処理データセクションには、チャンネル1の3つの値、チャンネル2の3つの値、voltageチャンネルの5つの値が含まれます。4番目のセグメントのバイナリフットプリントは下記のようになります。
部分 | バイナリフットプリント(16進法) |
リードイン | 54 44 53 6D 0A 00 00 00 68 12 00 00 5E 00 00 00 00 00 00 00 32 00 00 00 00 00 00 00 |
オブジェクト数 | 01 00 00 00 |
メタ情報(オブジェクト3) | 12 00 00 00 2F 27 67 72 6F 75 70 27 2F 27 76 6F 6C 74 61 67 65 27 14 00 00 00 03 00 00 00 01 00 00 00 05 00 00 00 00 00 00 00 00 00 00 00 |
未処理データ(チャンネル1) | 01 00 00 00 02 00 00 00 03 00 00 00 |
未処理データ(チャンネル2) | 04 00 00 00 05 00 00 00 06 00 00 00 |
未処理データ(チャンネル3) | 07 00 00 00 08 00 00 00 09 00 00 00 0A 00 00 00 0B 00 00 00 |
5番目のセグメントでは、チャンネル2に27個の値が含まれます。他のチャンネルには変更はありません。メタデータセクションには、チャンネル2のオブジェクトパス、チャンネル2の新規未処理データ指標が含まれますが、チャンネル2のプロパティは含まれません。5番目のセグメントのバイナリフットプリントは下記のようになります。
部分 | バイナリフットプリント(16進法) |
リードイン | 54 44 53 6D 0A 00 00 00 68 12 00 00 BF 00 00 00 00 00 00 00 33 00 00 00 00 00 00 00 |
オブジェクト数 | 01 00 00 00 |
メタ情報(オブジェクト2) | 13 00 00 00 2F 27 67 72 6F 75 70 27 2F 27 63 68 61 6E 6E 65 6C 32 27 14 00 00 00 03 00 00 00 01 00 00 00 1B 00 00 00 00 00 00 00 00 00 00 00 |
未処理データ(チャンネル1) | 01 00 00 00 02 00 00 00 03 00 00 00 |
未処理データ(チャンネル2) | 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 05 00 00 00 06 00 00 00 07 00 00 00 08 00 00 00 09 00 00 00 0A 00 00 00 0B 00 00 00 0C 00 00 00 0D 00 00 00 0E 00 00 00 0F 00 00 00 10 00 00 00 11 00 00 00 12 00 00 00 13 00 00 00 14 00 00 00 15 00 00 00 16 00 00 00 17 00 00 00 18 00 00 00 19 00 00 00 1A 00 00 00 1B 00 00 00 |
未処理データ(チャンネル3) | 07 00 00 00 08 00 00 00 09 00 00 00 0A 00 00 00 0B 00 00 00 |
6番目のセグメントでは、チャンネル2への書き込みを停止します。チャンネル1とvoltageチャンネルへの書き込みのみを継続します。これによりチャンネル順序の変更が発生するため、チャンネルパスの新規リストを書くことが必要になります。ToC bit kTocNewObjListを設定する必要があります。新規セグメントのメタデータセクションはすべてのパスの完全なリストを含む必要がありますが、プロパティと未処理データ指標は変更が発生していない限り含まれません。6番目のセグメントのバイナリフットプリントは下記のようになります。
部分 | バイナリフットプリント(16進法) |
リードイン | 54 44 53 6D 0E 00 00 00 68 12 00 00 81 00 00 00 00 00 00 00 61 00 00 00 00 00 00 00 |
オブジェクト数 | 02 00 00 00 |
メタ情報(オブジェクト1) | 13 00 00 00 2F 27 67 72 6F 75 70 27 2F 27 63 68 61 6E 6E 65 6C 31 27 14 00 00 00 03 00 00 00 01 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 |
メタ情報(オブジェクト2) | 12 00 00 00 2F 27 67 72 6F 75 70 27 2F 27 76 6F 6C 74 61 67 65 27 14 00 00 00 03 00 00 00 01 00 00 00 05 00 00 00 00 00 00 00 00 00 00 00 |
未処理データ(チャンネル1) | 01 00 00 00 02 00 00 00 03 00 00 00 |
未処理データ(チャンネル3) | 07 00 00 00 08 00 00 00 09 00 00 00 0A 00 00 00 0B 00 00 00 |
TDMSに書き込まれるすべてのデータは.tdms拡張子のファイルに保存されます。*.tdms_indexという指標ファイルもオプションで付随します。指標ファイルは*.tdmsファイルからの読み取りを高速化するために使用されます。ナショナルインスツルメンツのアプリケーションから指標ファイルなしのTDMSファイルを開くと、自動的に指標ファイルが作成されます。LabVIEWやLabVIEW Windows/CVIなどのナショナルインスツルメンツアプリケーションからTDMSファイルに書き込む場合、メインの*.tdmsファイルと指標ファイルが同時に作成されます。
指標ファイルは*.tdmsファイルのコピーですが、未処理データは含まず、すべてのセグメントがTDSmタグではなくTDShタグで開始します。指標ファイルには、*.tdmsファイル内の任意のチャンネルの任意の値を正しく検索するためのすべての情報が含まれます。
このように、TDMSファイル形式は、説明用の情報の階層システムを維持しながら非常に高速に計測データの書き込み/読み取りを行なうために設計されています。バイナリレイアウト自体はシンプルですが、メタデータを増分的に書き込んで最適化することにより、非常に洗練されたファイル構成にすることができます。
LabWindowsという商標は、Microsoft Corporationからの使用許諾を得て使用しています。Windowsは、Microsoft Corporationの米国およびその他の国における登録商標です。