尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

LabVIEW中TDMS文件创建与写入:从入门到工程实践

LabVIEW中TDMS文件创建与写入:从入门到工程实践 做测试测量的人最怕的不是设备不出数而是出了数你却存不下来、存下来又读不回来。早些年我做数据采集习惯把数据直接写成文本或者Excel当时觉得够用了。直到有一次连续采集了一整晚的高频振动信号第二天打开文件一看文本文件膨胀到几个GBExcel直接卡死数据还丢了一段。后来换了LabVIEW里自带的TDMS格式这些问题基本都不再是问题——写入稳定、读取快、自带结构化管理而且LabVIEW对TDMS的支持非常完善创建、写入、读取都有现成的节点不需要你去自己拼接二进制。这篇文章我就围绕“TDMS文件的创建与写入”这条主线把TDMS是什么、为什么选它、在LabVIEW里怎么一步步落地以及我在工程里踩过的坑全部说清楚。无论是刚开始学LabVIEW的新手还是已经用TDMS做项目但想优化写法的工程师这篇应该都能给你一些参考。1. TDMS文件格式到底是个什么东西1.1 三层结构文件、通道组、通道TDMS的全称是Technical Data Management Streaming翻译过来就是“技术数据管理流式格式”。它是NI在TDM格式基础上发展出的二进制数据存储格式从LabVIEW 8.0开始内置支持一直到现在的LabVIEW 2024乃至更新版本地位从来没变过。理解TDMS最快的方式是把它和Excel做类比。一个TDMS文件相当于一个Excel工作簿里面可以有多个工作表每个表就是“通道组”每个工作表里可以有多列数据每一列就是一个“通道”。所以在TDMS里数据的基本组织方式就是三层文件File→ 通道组Group→ 通道Channel。文件my_test.tdms └── 通道组Engine_Test ├── 通道Speed_RPM ├── 通道Temperature_C └── 通道Pressure_kPa这个结构最大的价值在于自描述。文本文件或者裸二进制文件里数据只是“一串数字”你得另外用文档去说明第几列是什么、单位是什么、采样率是多少。TDMS则把这些信息直接绑在数据上每一层都可以挂属性Property比如通道层可以写采样率、量程、传感器灵敏度组层可以写测试工况、测试人员文件层可以写测试编号、日期版本。读数据的人只要打开文件就能看到完整的数据字典不需要你额外再给一份说明文档。1.2 为什么放着文本和Excel不用偏要用TDMS这个问题几乎每个刚接触TDMS的人都会问。我从实际工程对比的角度来讲讲。存储方式写入速度文件膨胀程度是否自描述是否支持流式写入大数据量下的表现文本/CSV慢高数据以ASCII字符存储否勉强但会持续增大文件句柄压力文件巨大读取解析耗时Excel (xlsx)慢较高部分不支持需要在内存中维护整个工作簿数据量一大就卡死自定义二进制快低否支持但需要自己维护格式快但格式兼容性差TDMS很快低是支持且专为流式设计高性能边写边读也无压力具体展开几个点。文本和CSV的问题在于“字符串化”。一个double类型的数值在内存里占8字节转成字符串写进文件可能占十几个字节文件膨胀不说写的时候还涉及数值到字符串的格式化这个格式化是有计算开销的。同样是写10万条数据TDMS可能一两秒就写完了CSV可能要十几秒甚至更久。Excel的问题在于它的底层模型是“在内存中维护一个完整的工作表对象”。这意味着你写入Excel时所有数据其实都堆在内存里保存时才一次性落盘数据量一大内存直接爆掉。我见过不少项目用LabVIEW写Excel报表数据超过几十万行以后写一次要等好几分钟程序还经常无响应。自定义二进制速度确实快但你要自己定义文件头、数据段、结束标记、数据字典等一套东西。开发周期长而且一旦格式定下来以后想加字段、加属性就得设计文件版本兼容逻辑维护成本非常高。TDMS把这些都做好了还提供了从LabVIEW、C/C、Python到DIAdem等跨工具链的支持。我真心建议不要在LabVIEW里自己造二进制格式的轮子直接用TDMS是性价比最高的选择。1.3 tdms和tdms_index两个文件之间的关系你在保存TDMS时会注意到多数情况下磁盘上除了.tdms主文件还会有一个.tdms_index索引文件。这个索引文件不是数据文件的副本它记录的是“数据在哪个文件偏移位置”的映射关系。你可以把它理解成书的目录正文是.tdms目录是.tdms_index。索引文件的作用是加速数据定位。比如你想从某个大文件里读取第100秒到第102秒的数据没有索引文件的话程序就要从头扫描整个文件找到对应的数据段有索引文件定位就是几毫秒级的事。工程里经常出现的一个情况你拿到一个别人拷贝过来的.tdms文件发现只有主文件、没有索引文件。这不需要担心LabVIEW打开.tdms时会自动重新生成索引只是首次打开要稍等一下。反过来也一样如果你只拷贝了索引文件、丢了主文件那才是真的没法用。2. 动手前的准备TDMS函数在哪里2.1 需要的开发环境与函数面板位置做TDMS开发你只需要一个安装了完整版的LabVIEW。我目前在用的是LabVIEW 2021但TDMS相关的函数从老版本到新版长得几乎一模一样函数位置也很稳定所以不管你是LabVIEW 2015还是2023下面的路径和函数名都通用。进入LabVIEW后新建一个VI在程序框图面板空白处右键找到“编程”Programming→“文件 I/O”File I/O→“TDMS”就能看到一整套TDMS函数节点。这一组节点包括TDMS Open、TDMS Close、TDMS Read、TDMS Write、TDMS Flush、TDMS Set Properties、TDMS Get Properties、TDMS File Viewer等。如果你不想一层层翻菜单也可以在框图上按CtrlSpace调出快速搜索栏直接输入“TDMS”所有相关节点就会列出来。对于我这种习惯键盘操作的人来说这个方式比翻菜单快得多。另外多说一句快速搜索栏是个被很多人低估的入口LabVIEW的函数成千上万靠手翻菜单根本不现实学会用搜索栏能大幅提升开发效率。2.2 核心函数一览TDMS相关函数里日常高频使用的主要有五个Open、Write、Read、Close以及Set Properties。我先把它们的作用列出来后面每一节的代码示例都会用到。函数名称作用关键输入/输出TDMS Open创建或打开一个TDMS文件同时设置操作模式文件路径、操作模式create/open/replace等TDMS Write向指定通道组和通道写入数据组名、通道名、数据内容TDMS Read按条件读取某个或多个通道的数据组名、通道名、偏移量、读取数量TDMS Close关闭文件句柄确保缓冲数据落盘错误输入输出TDMS Set Properties为文件/组/通道写入属性目标路径、属性名、属性值TDMS Flush将缓冲区数据强制写入磁盘无需额外参数这里有个使用频率高但很容易被忽略的函数TDMS Flush。默认情况下TDMS写入是有缓冲机制的Write之后数据先在内存缓冲区里攒着等到一定量或者文件关闭时才真正落盘。如果你希望数据实时落到磁盘比如防止程序崩溃丢数据就要在关键位置调用Flush。当然频繁Flush会降低写入性能所以这是一个安全性和性能之间权衡的问题后面我会专门讲。2.3 命名规范给通道起一个能用的名字TDMS在写入时可以指定通道组名和通道名。如果不指定LabVIEW会用默认的“Untitled”作为组名“Channel”作为通道名。开发初期怎么都好说但一旦进入工程化阶段我强烈建议从一开始就设计好命名规范。通道组和通道名的设计直接影响后期数据分析的效率。我一般习惯这样命名通道组名使用“任务编号_设备编号_测试日期”例如“EngineTest_01_20250114”这样在大量TDMS文件归档后只看文件名或者组名就能知道是哪个测试。通道名使用“物理量_单位”例如“Speed_RPM”“Temperature_C”“Pressure_kPa”单位直接写在通道名里读数据的同事不需要再查资料。属性里再补充详细内容例如采样率、传感器序列号、增益系数等。命名禁用特殊字符例如“/”、“\”、“:”、“*”、“?”等这些字符在文件系统层面有特殊含义在各层路径解析时会出问题。另外建议统一使用英文命名避免中文字符编码不一致带来的兼容性麻烦。这个规范建议在团队内形成文档别让每个工程师按自己的习惯来后期数据汇总时你会感谢当初定规范的决定。3. TDMS文件创建与写入从入门到工程化3.1 最简单的一版把10个随机数写进TDMS先说最简单的场景。假设我们产生一个包含10个随机数的一维数组想把这组数据存成TDMS文件。这是绝大多数人学习TDMS写入的第一课。在LabVIEW的程序框图上按下面步骤组织代码放置一个“TDMS Open”节点文件路径接一个字符串常量或路径常量比如“C:\TestData\random_data.tdms”操作模式设置为“create”创建新文件。如果文件已经存在create模式会报错所以实际中我更常用“replace or create”模式意思是“存在就覆盖不存在就新建”这种模式最灵活。放置一个“TDMS Write”节点。在写数据之前需要指定“group name”通道组名和“channel names”通道名。这两个端口是可选的不接就用默认值。为了规范我通常显式连接组名填“Random_Data”通道名填“Value”。数据的来源在框图上放一个“随机数”函数循环10次生成数组或者直接用“数组 → 随机数数组”的方式。简单起见这里可以直接在框图上用“For循环”生成10个随机数组成的数组然后接到TDMS Write的“data”输入端口。放置“TDMS Close”节点关闭文件确保数据落盘。用一条错误线把这些节点串起来形成错误链TDMS Open的error out接到TDMS Write的error inTDMS Write的error out接到TDMS Close的error in。这样保证程序严格按“打开→写入→关闭”的顺序执行。这段逻辑的LabVIEW图形化代码本质上就是TDMS Open(路径create) # 创建空tdms文件 TDMS Write(组名Random_Data, 通道名Value, data随机数数组) TDMS Close()运行这个VI去目标目录就能看到生成的.tdms文件。用“TDMS File Viewer”节点或者后续的读取程序就能把随机数数组原样读回来。现在从第一步开始说明接线方式和看图方法第一步右键框图空白处选择“编程” → “文件 I/O” → “TDMS” → “TDMS Open”。它会出现在框图上默认显示为一个小图标共有几个输入输出端口。把鼠标放到图标上端口名称就会显示出来。第二步双击TDMS Open图标能打开它的配置对话框。在这里可以设置操作模式也可以直接选择文件路径。也可以用路径常量或路径输入控件连接到它的“file path”端口。需要注意“TDMS Open”的file path端口如果留空运行时它会弹出一个文件对话框让你手动选择文件。这在调试时可能没问题但在无人值守的采集程序里是绝对要避免的谁都不希望半夜跑数采的时候弹个对话框卡在那里等人点确定。第三步放置TDMS Write。TDMS Write默认配置下会一次写入一个通道的数据。它的“data”端口可以接受标量、一维数组、二维数组、波形等多种数据形态。我们这里接一个一维数组它就会把整个数组作为一条通道的数据写入。第四步放置TDMS Close并连好错误线。错误线的意义在于保证执行顺序而且一旦前面出错后续节点不会执行避免更严重的连锁问题。LabVIEW的图形化编程中这种“错误链”的写法是标准姿势做数据采集的人都应该养成这个习惯。3.2 加属性让数据自带“说明书”上面那个例子能跑通但存下来的数据信息很不完整。如果过了一个月你再打开这个文件你会问自己这个采样率是多少单位是什么用什么传感器采的这些信息如果没记录数据基本等于废了。这时候就要用到TDMS的属性机制。用“TDMS Set Properties”节点可以给文件、通道组或者通道挂上键值对形式的属性。举个例子给刚才的通道加上采样率、单位、采集时间三个属性。在TDMS Write之后放一个“TDMS Set Properties”节点按下面的方式连接节点的第一个输入端是属性作用目标的路径。如果填“/”就是你写的文件根路径如果填“/Random_Data/Value”就是刚才那个通道。然后用“属性名”和“属性值”两个输入写键值对。属性名可以是字符串数组属性值可以是变体数组LabVIEW会自动帮你转换成变体。实际操作中属性值的类型可以是数值、字符串、布尔、时间戳等。比如属性名“Sample_Rate”属性值“1000”表示1000Hz属性名“Unit”属性值“V”表示电压单位属性名“Acquire_Time”属性值“2025-01-14 10:32:00”这三个属性绑定到通道“/Random_Data/Value”上之后任何人读这个通道时就能通过TDMS Get Properties把这些信息取出来。这个机制对于后期做数据分析、写技术报告、做数据溯源简直不要太方便。要特别提醒一个很多人踩过的坑属性写入的时机。TDMS是支持在任意时刻写入属性的不仅是数据写入前数据写完后再补属性也完全没问题。但是如果你在同一个文件中重复写入同名属性新的值会覆盖旧值。这在某些场景下是隐患比如你在程序里设置了一个“Test_Status”属性表示测试状态如果在循环里不断更新这个属性的值那么文件里最终保存的只是最后一次的状态而不是全过程的记录。如果希望保留每次的变化就把它作为通道数据来写而不是属性属性更适合“一次性、描述性”的元数据。3.3 连续采集场景下的流式写入实际工程里我们面对的数据往往不是10个随机数而是持续几个小时的高频采样数据。这类场景对写入的要求完全不同。以我做过的一个发动机振动测试为例采样率是20kHz3路加速度传感器同时采集单通道每秒产生2万个double类型的数据点一小时的测试下来就是几百MB甚至几个GB的数据量。在这种场景下写入代码的组织方式很关键。我总结的通用流程是在循环外“TDMS Open”打开文件并设置好通道属性。进入采集循环通常是While循环每次循环从采集设备读取一批数据然后通过“TDMS Write”写入文件。循环结束后调用“TDMS Close”关闭文件。核心原则就是打开和关闭只做一次写在循环外写入放在循环内每次写一小批。很多人一开始会犯的一个错误是把“TDMS Open”和“TDMS Close”都放在循环里结果是每采一次数据就重新创建一次文件。这不仅性能极差还会产生几十上百个零散的小TDMS文件。还有的人虽然只开了一次文件但每次循环都重新指定通道名这也会造成通道重复创建或者写入混乱。再讲一个增量写入的关键点TDMS Write对通道是“追加式”写入的。也就是说你第一次往通道“Temperature”里写了1000个点第二次再写500个点这个通道最终就有1500个点顺序就是两次写入的先后顺序。这个特性非常重要因为连续采集情况下你不可能一次把整个数据都构造好而是边采边写、边写边追加。关于批量写入的性能我做个对比。假设要写10万个double类型的数据点一次性写入一个10万元素数组几乎一瞬间完成。循环10万次每次写1个点耗时非常可观实测可以慢几百倍。原因很简单每次TDMS Write都有函数调用、数据封装、类型检查、缓冲区操作等固定开销。所以一定要在内存里先把数据攒成一个数组然后一次性写入。具体的“攒批”策略可以这样在循环里用移位寄存器或队列把采集到的数据累积起来每当累积到一定数量比如1万点就执行一次TDMS Write并清空缓存。这个“攒批写入”的技巧是大数据量写入性能优化的核心。3.4 波形数据的写入与时间轴还原除了裸数组LabVIEW里还有一种很常见的“波形”Waveform数据类型。波形数据本质上包含三个部分起始时间t0、采样时间间隔dt、以及y数组。这类数据在振动、声学、电力分析中非常常见。TDMS Write对波形数据有特殊的支持。当你把一个波形数据接到TDMS Write的data端口时LabVIEW会自动把这个波形拆解为一个数据通道保存y数组。在通道属性中自动写入两个标准属性wf_start_time起始时间和wf_increment采样时间间隔。这意味着你用波形数据写入TDMS再读出来时可以自动还原成波形数据类型时间轴不会丢失。这个设计非常贴心也是我向别人推荐TDMS的一个理由——连波形的时间信息都考虑好了。不过需要注意一个细节如果你把波形数据的一维数组多个波形同时写入每个波形会被当作独立的通道保存。如果你把10万个波形点的二维数组写进去它会按行展开为多个通道。实际使用时要先想清楚数据维度避免写入后通道数量和预期不一致。如果你不是用波形数据类型而是自己维护“时间戳数组数据数组”那就需要自己在通道属性里记录采样率或时间增量并在读取后手动重建时间轴。这也是可以的但就失去了内建支持还得自己保证属性名的一致性所以我更建议能用波形数据类型就用波形类型省很多事。4. 怎么把TDMS文件读出来4.1 LabVIEW里的读取流程数据存了是要读的。在LabVIEW里读取TDMS的流程和写入非常对称TDMS Open → TDMS Read → TDMS Close。TDMS Open读取时操作模式用“open”打开现有文件或者“read-only”只读打开。我更推荐read-only模式因为只读模式能避免意外修改文件内容而且允许多个程序同时共享读取同一个文件。TDMS Read的关键参数有file path文件路径。group name要读哪个通道组。channel names要读组里的哪些通道。offset从第几个数据点开始读。count一共读多少个数据点。data输出的数据。实际编程时有一个比较实用的函数是“TDMS Read”配合“TDMS Get Properties”可以先把文件里的组、通道、属性信息都列出来然后再选择性读取。相当于先浏览文件目录再决定读哪一部分。我经常写给数据后处理同事用的一个读取VI逻辑很简单选择TDMS文件路径。自动列举所有通道组和通道名。选中一个或多个通道。读取全部数据画在波形图上。读取并显示每个通道的属性信息。这个VI只用了大概二十分钟就写好了但团队里做数据分析的人几乎每天都在用。TDMS读数据的门槛就这么低核心逻辑就四五个节点。4.2 TDMS文件用什么软件打开“tdms文件用什么软件打开”是我看到问得最多的问题。我从实用角度整理一下主流的打开方式。打开方式使用场景说明LabVIEWTDMS Read编程读取、二次处理最灵活适合集成到自己的程序里NI DIAdem交互式浏览和分析NI官方的数据分析软件直接拖入TDMS文件即可查看结构并绘图NI MAXTDMS File Viewer快速查看文件结构不需要写代码打开NI MAX就能浏览TDMSMicrosoft Excel插件轻量级查看NI官方提供TDMS Excel Add-In安装后Excel可直接打开TDMSPythonnpTDMS批量数据处理、机器学习第三方开源库npTDMS可以读取TDMS适合做算法或数据挖掘这里单独展开说一下Python的npTDMS。做数据采集的人可能不都用LabVIEW但做数据分析的人大概率会用Python。npTDMS这个库用起来非常简洁import numpy as np from nptdms import TdmsFile tdms_file TdmsFile.read(engine_test.tdms) df tdms_file.as_dataframe() print(df.head())一行代码就能把TDMS读成DataFrame接下来就能用pandas做各种分析了。所以哪怕你的下游同事完全不会LabVIEW把他手里的TDMS文件用Python来处理也完全没有障碍。这个特性是我觉得TDMS生态比较完善的地方。就是要注意read方法会把整个文件读入内存对于超大文件建议用TdmsFile.open在线读取模式按需读取避免内存不够用。我处理过几十GB的TDMS文件用在线模式分段读取可以稳定跑完用一次性读取则会内存爆掉。4.3 读取时的几个坑读取TDMS文件虽然简单但有几个细节值得留个心眼。第一个坑通道顺序不一定和写入顺序一致。在TDMS文件里通道的组织是按名称排序的不是按写入顺序。如果你在读取时依赖“第一个通道是速度、第二个通道是温度”这种顺序逻辑结果可能和你预期不符。正确做法是始终用通道名来定位不要用索引顺序。第二个坑数据类型不匹配。TDMS写入时会记录每个通道的数据类型读取时用“TDMS Read”的“data”输出端接一个类型不匹配的显示控件会直接报错。比如写入的是double数组读取时接了一个整型数组的显示控件LabVIEW会报类型冲突。处理办法是先用属性或者文件信息读取来确定通道的数据类型或者让显示控件使用“通用”的变体类型再动态转换。第三个坑超大文件不要“全量读”。虽然TDMS Read可以一次性输出整个通道的所有数据但如果你读取一个5GB的文件且内存只有8GB那可能直接把内存占满甚至程序崩溃。正确做法是用offset和count参数分段读取比如每次读100万个点处理完再读下一段。这个思路和流式写入是对称的写入时批量写读取时分段读。第四个坑读取前要确认文件状态。如果TDMS文件正在被另一个程序写入你用LabVIEW以read-only模式打开是可以看到已有数据的但可能看不到最新的数据因为写程序还在缓冲区里没落盘。要确保读到完整数据必须等写程序正常关闭文件后再读。这是TDMS缓冲机制带来的必然结果理解它之后就不会觉得奇怪了。5. 工程实战中的排查与避坑记录5.1 文件被占用导致无法写入或删除这是TDMS使用中最常见的问题程序运行了一次写入之后想重新覆盖或者删除这个文件系统提示文件被另一个进程占用无法操作。出现这类问题的原因通常有两个。一是程序在运行中异常终止比如断电、被人为强制停止TDMS文件句柄没有正常关闭操作系统仍认为文件被占用。二是代码没有按顺序关闭文件或者关闭节点的错误线没有连接导致Close节点实际上没有执行。排查方法很简单先查看任务管理器确认是否有残留的LabVIEW进程结束它或者重启LabVIEW重新打开工程这时候文件占用通常会解除。如果是长期采集程序建议给写入代码加上“程序结束时强制关闭文件”的逻辑比如用LabVIEW的“VI属性 → 执行控制 → 在调用时清除”或者事件结构里的“程序关闭事件”来做兜底。更稳妥的做法是配合看门狗或错误处理框架确保异常时也能走完TDMS Close。有人会用删除文件时的“find the process which locks the file”这类工具来排查Windows下可以用资源监视器或者Process Explorer查找占用句柄确认是不是LabVIEW进程占用了文件。这套思路适合定位问题但根治还是要靠代码兜底。5.2 路径写错导致打不开第二个常见坑是路径问题。TDMS Open的file path如果写成这样“C:\TestData\”尾带反斜杠但没带文件名运行时一定会报错因为这是一个目录而不是文件。还有几种情况路径指向的目录不存在。TDMS Open不会自动创建目录。解决办法是先用“创建路径”或“创建文件夹”函数把目录建好再打开TDMS文件。文件名带了非法字符比如“test:1.tdms”Windows不允许冒号出现在文件名里会直接报错。相对路径问题。如果你在VI里用相对路径它会基于“当前VI所在目录”解析。如果你把VI打包成exe或者运行时不改变工作目录相对路径可能解析不到你预期的位置。我的习惯是在采集程序启动时先根据测试编号动态生成完整的绝对路径放到一个全局变量或功能全局变量里后续所有写入读取都从那里取。这样做的好处是路径只生成一次不会被多处零散的路径字符串搞乱。5.3 大批量数据写入的性能优化写大数据量TDMS文件时性能问题绕不开。我实测下来的几个经验一TDMS Write一定要用“大数组”批量写避免逐点写。逐点写的性能损耗不是简单的线性增长而是函数调用开销被无限放大数据量一大写文件的时间会占据程序总运行时间的绝大部分。二缓存区的刷新策略要平衡。TDMS内部有写缓冲数据先写到内存缓冲再异步刷到磁盘。如果你追求极致的写入性能可以减少Flush的调用次数如果你更看重数据安全就要定期Flush。我一般是每写入1秒钟的数据或者每1000次循环就Flush一次这样即使程序崩溃最多丢失最近1秒的数据可接受。三避免把TDMS写入和硬件采集放在同一个循环节拍里抢占资源。采集循环应该尽量及时从硬件缓冲区取数据写入TDMS如果耗时较长会拖慢采集循环导致硬件缓冲区溢出丢数。解决思路有两个一是把TDMS Write放在单独的写入循环里用队列采集数据和写入数据解耦二是采集循环里只做数据搬移批量数据由写入循环统一落盘。对于高频采集这个“读写分离”的架构几乎是必须的。四注意磁盘I/O本身的能力。TDMS写本地SSD很快但写到机械硬盘或者网络共享盘时瓶颈在磁盘本身。实测网络共享盘写TDMS经常出现缓冲堆积这时候要么降低采样率要么本地暂存后采用“后复制”策略先写到本地磁盘再定时同步到网络存储。5.4 TDMS文件损坏与恢复最后说说文件损坏。TDMS写入过程中程序崩溃、断电可能造成文件没有正常写入结束标记。这类文件再用软件打开时可能会提示文件不完整或者无法直接读取。遇到这种情况我的处理优先级是这样的第一尝试用DIAdem打开。DIAdem对不完整TDMS文件的兼容性通常比LabVIEW自带的读取函数更好它会尽力扫描文件中的数据段并恢复大部分数据。第二检查索引文件。如果.tdms_index文件还在有些工具可以利用索引文件辅助恢复如果索引文件也丢了LabVIEW会自动重建索引来读取数据但需要等待文件扫描完成。第三也是最重要的——从源头防止损坏。工业现场取数不易数据反复采集的成本高昂所以我会在采集程序里加三层保护一是前面提到的定期Flush二是循环内加入错误检测一旦写入出错立即进入异常处理分支尽量保证正常关闭文件三是对于关键的、不可复现的试验数据采用“双文件冗余”策略主备两个TDMS文件交替写入避免单文件损坏导致全部测试数据丢失。有人问能不能用十六进制编辑器手工修复TDMS文件理论上可以但TDMS二进制格式的结构细节比较多手工修复的难度很大而且投入产出比非常低。我做过一次类别的底层解析成功恢复了一部分数据但花费了大量时间。从那以后我就把精力放在“写入逻辑不崩溃”这件事上而不是事后去修复文件。一些我坚持了多年的实操习惯最后分享几个我在实际项目里坚持的习惯算是对上面内容的一个补充。第一所有采集程序的TDMS写入部分我都会封装成一个子VI。入口参数只有三个文件路径、采样参数、设备名称。所有的节点连接、属性设置、错误处理都在子VI内部完成主框图永远干干净净。这样做还有一个好处如果后期需要换存储格式只需要改这一个子VI主程序完全不受影响。第二我会在TDMS文件里还写一个“Readme”组。这个组不存测试数据专门用来放测试说明比如测试目的、使用仪器、环境条件等。每个说明文字都是一个独立通道虽然通道里只有一两个字符串但配合TDMS的属性机制整个文件的数据字典就非常完整了。第三属性命名尽量用带下划线的英文不要使用空格。比如“Sample_Rate”比“Sample Rate”好因为某些下游工具会把带空格的属性名处理得很别扭。数据字典里所有属性名必须统一哪怕只是一个拼写错误也会导致整个数据分析脚本报错。我在一个项目里遇到过同事把属性名时而写成“SampleRate”时而写成“Sample_Rate”结果下游Python脚本在处理时一直报KeyError排查了很久才发现是命名不一致。从那以后项目的TDMS属性命名规范就写进了团队文档。关于TDMS写到这里已经把我能想到的工程细节都讲了一遍。对我个人来说TDMS最大的价值不是它的写入速度有多快而是它让“数据”这件事本身变得有结构、可追溯LabVIEW里开箱即用的节点又让这套能力几乎没有学习成本。希望这篇内容能帮你把TDMS的创建和写入用得更加顺手少踩几个我当年踩过的坑。
返回列表