行业资讯
📅 2026/9/1 15:34:06
COMTRADE文件解析指南:从CFG配置到DAT波形数据还原
简介面向电力系统领域开发者的QTCOMTRADE工具源码用于解析电网录波器生成的COMTRADE标准二进制DAT文件覆盖暂态数据读取、查看与分析全流程适用于故障分析、保护测试与电力系统稳定性研究。压缩包共16个文件其中7个C源文件与6个头文件构成核心解析逻辑实现二进制流操作、通道定义解析、时间戳转换等工程文件、界面文件与用户配置文件则用于构建和维护QT图形界面。整体仅337KB结构紧凑方便定向阅读已有402人学习下载。源码基于QT5.15.2完整展示了COMTRADE模拟量与数字量通道的提取方法、采样数据与波形绘制借助QCustomPlot、异常捕获与日志输出等关键技术同时利用QT跨平台特性可运行于Windows、Linux和macOS。通过学习该源码可深入理解电力暂态数据格式的每个字段含义并掌握QT下文件处理、多线程数据解析和自定义图形界面设计等实用技能对电力系统软件研发与数据分析工作极具参考价值。 搞继电保护、做故障录波分析的工程师手边最常碰到的文件格式就是COMTRADE。全称是Common Format for Transient Data Exchange翻译过来叫“暂态数据交换通用格式”由IEEE标准C37.111定义国内对应的是GB/T 22386。它是变电站里的故障录波器、保护装置、测控设备在电网发生扰动或故障时自动记录下来的整套电流、电压、开关量波形数据。我刚入行的头两年分析录波基本靠厂商自带的上位机软件点鼠标看波形。直到后来需要一次性批量处理几十个站的故障数据才被现实狠狠教育了一课不同厂家导出的文件各搞一套互不兼容只有COMTRADE是大家都能读的“普通话”但“能读”还不等于“会读”。这篇文章我就从解析者的视角把COMTRADE文件的结构、解析逻辑和实际踩坑经验完整梳理一遍。无论你是要写解析工具、做故障复核还是单纯想搞清楚波形文件里到底存了哪些内容都能从中找到能直接落地的思路。1. 为什么电力行业需要一套“通用波形语言”COMTRADE的定位与版本脉络在COMTRADE普及之前录波数据的交换是一件相当痛苦的事情。A厂家的故障录波器下载的数据B厂家的分析软件打不开保护装置里导出的波形要发给网省公司做事故分析时还得先用专用转换工具导成别的格式再手动填一堆说明。这种情况下难免出现信息丢失或解读偏差效率也很低。COMTRADE出现后把“波形数据怎么存、怎么描述”这件事统一了。它定义了一套与厂商无关的文件组织方式用文本文件描述通道配置用数据文件保存采样值再辅以可选的说明文件。这样一来不同装置之间、不同系统之间只要都遵循这个标准就能自由交换和分析暂态数据。现在变电站录波器联网系统、保信子站、故障分析软件几乎都以COMTRADE作为标准事实格式。版本上也经历过几轮演进。最早的IEEE C37.111-1991是基础版1999版本应用最广补充了更清晰的采样率分段描述、二进制格式的细节以及一次/二次值标记方式2013版本又引入了XML格式的配置描述为通道数量扩展、采样率动态变化等新需求留了空间。实际工程中绝大多数文件还是按1999版结构生成的但解析时建议兼容2013版的部分字段因为一些新装置的配置里会多出附加信息。2. 一套完整录波由四个文件组成CFG、DAT、HDR、INF的分工COMTRADE记录不是单文件而是“一组文件”。拿到一份完整的录波数据通常能看到四个后缀配套出现文件后缀角色是否必需内容形态.cfg配置文件描述通道、采样率、换算参数必需纯文本.dat数据文件存放采样值和时间戳必需ASCII文本或二进制.hdr头部说明文件记录人工可读的录波说明可选纯文本.inf信息文件厂商可自定义扩展内容可选文本/私有格式实际解析时大多数场景只需要 .cfg .dat 这两个文件。.hdr 相当于一页“封面说明”里面可能是录波原因、保护动作信息、装置型号等通常是给人看的不参与波形还原。.inf 更偏厂商私有标准没强制规定内容所以跨平台解析时一般直接忽略。值得提醒的是有些厂商会把整套文件重命名或只导出其中两个但只要 .cfg 和 .dat 都齐解析流程就不会卡住。CFG描述的是“这份录波长什么样”DAT才是“采到的波形本体”。没有CFGDAT里的字节流就是毫无意义的数字有了CFG才能真正还原出带单位、带时间、带通道名字的物理波形。所以解析的第一步永远是打开CFG不是DAT。3. 解析的第一步从CFG开始配置逐行拆解与Python读取CFG文件是纯文本用文本编辑器打开就能看。每一行对应一类信息解析逻辑非常规整但字段多容易看花眼。我按行顺序拆开讲。开头两行是“元信息”。第一行是站名、装置ID、录波年份、年积日、启动时间第二行声明通道总数、模拟通道数、数字通道数。注意这里的通道总数是模拟通道数与数字通道数之和不包含序号和时间戳。紧接着第三行开始逐行描述模拟通道。每一行依次是通道编号、通道标识如IA、UB、通道名称、相别、被监视元件、单位、比例因子a、偏移量b、时间偏移skew、最小码值、最大码值、一次值、二次值、一次二次标记。看到这行字段最多但真正用于波形换算的核心是a和b其他更多是描述性信息。模拟通道行全部结束后才是数字通道行。数字通道行相对简单编号、标识、名称、相别、正常状态、skew、最小/最大值。其中“正常状态”很关键表示该开关量在正常运行时的电平是0还是1故障前后状态翻转就是靠它来判断的。通道行之后是系统频率和采样率段数后面跟着每一段采样率的数值和结束时间。最后一行给出整个数据文件的起始时间和结束时间。这两个时间直接决定了DAT里时间戳的绝对时间基准。下面是一段读取CFG关键字段的Python示例能帮你快速拿到解析所需的全部参数def parse_cfg(cfg_path): with open(cfg_path, r, encodingutf-8, errorsreplace) as f: lines f.readlines() head lines[0].strip().split(,) station head[0] trigger_time (int(head[2]), int(head[3]), head[4]) # year, day, time ch_total, ch_analog, ch_digital map(int, lines[1].strip().split(,)[:3]) analog_chs [] idx 2 for _ in range(ch_analog): parts lines[idx].strip().split(,) analog_chs.append({ number: int(parts[0]), channel: parts[1], unit: parts[5], a: float(parts[6]), b: float(parts[7]), skew: float(parts[8]), primary: float(parts[11]), secondary: float(parts[12]), }) idx 1 digital_chs [] for _ in range(ch_digital): parts lines[idx].strip().split(,) digital_chs.append({ number: int(parts[0]), channel: parts[1], normal_state: int(parts[4]), }) idx 1 freq, rate_count lines[idx].strip().split(,) idx 1 rates [] for _ in range(int(rate_count)): rate_parts lines[idx].strip().split(,) rates.append((float(rate_parts[0]), float(rate_parts[1]))) idx 1 time_range lines[idx].strip().split(,) return { station: station, trigger_time: trigger_time, analog_chs: analog_chs, digital_chs: digital_chs, sampling_rates: rates, start_time: time_range[:2], end_time: time_range[2:], }解析CFG时有几个容易踩的细节。一是字符编码老装置导出的CFG可能是GBK或ASCII直接用UTF-8读会报错稳妥的做法是带errorsreplace或者按二进制读再解码二是有些通道字段中间包含空格split(,)之后别忘了strip三是通道行数必须和第2行声明的数量一致遇到过厂商文件少写了一行后面DAT解析时索引全错位这种问题必须加校验。4. DAT文件到底怎么读ASCII、二进制16位、二进制32位的完整解析CFG读完只能算拿到了“地图”真正的波形数据躺在DAT文件里。DAT文件有两种形态ASCII文本和二进制。具体用哪种CFG文件里没有显式说明只能靠打开文件前几个字节来判断或者看厂商文档。我见过不少工程师在这里卡住。ASCII格式的DAT解析起来最直观每一行是一条采样记录字段按逗号分隔。第一个字段是采样序号第二个字段是时间戳单位是微秒之后依次是各模拟通道的原始码值再后面是各数字通道的状态为0或1。把CFG中通道定义顺序和这里一列一一对应逐行读出来就行。二进制格式则分两种16位和32位区别在于模拟通道的码值占用字节数。16位格式下每个模拟通道是2字节有符号整数32位格式下是4字节有符号整数。每条记录的固定布局是4字节采样序号无符号整数 4字节时间戳无符号整数单位微秒 模拟通道数据 数字通道数据。这里特别要留意数字通道的打包方式。数字通道不是每个通道独立占一个字节而是每16个通道打包成一个16位字第一个数字通道的状态存到最低位第二个存到第二位依此类推。如果数字通道数不是16的倍数最后一个16位字的高位补零。解析时先按“向上取整到16的倍数”计算占用的字数再按位拆解取前N个位作为实际通道状态。读取二进制DAT文件的示例import struct def parse_dat_binary(dat_path, analog_ch, digital_ch, bit16True): analog_bytes analog_ch * (2 if bit16 else 4) digital_words (digital_ch 15) // 16 record_size 4 4 analog_bytes digital_words * 2 fmt_ana (h if bit16 else i) * analog_ch fmt_dig H * digital_words with open(dat_path, rb) as f: raw f.read() records [] for offset in range(0, len(raw), record_size): sample_no, timestamp struct.unpack_from(II, raw, offset) ana_raw struct.unpack_from(fmt_ana, raw, offset 8) dig_raw struct.unpack_from(fmt_dig, raw, offset 8 analog_bytes) dig_states [] for w in range(digital_words): for bit in range(16): dig_states.append((dig_raw[w] bit) 1) dig_states dig_states[:digital_ch] records.append({ sample_no: sample_no, timestamp_us: timestamp, analog_raw: ana_raw, digital_states: dig_states, }) return records关于字节序COMTRADE标准本身没有把字节序写死但实际工程里99%的装置生成的文件都是小端序也就是Intel格式所以struct里用前缀。如果你是做跨平台工具最好加一个可配置项遇到异常波形时能切换字节序来排查。5. 从码值到真实波形增益换算、时间基线与多采样率拼接DAT文件里拿到的都是原始码值这些值本身没有物理意义。要把它们变成能直接看图、能算幅值的电压电流波形必须结合CFG里的比例因子a和偏移量b做一次线性换算物理值 原始码值 × a b举个例子某通道CFG中a0.001953、b0原始码值为12000换算下来就是12000 × 0.001953 23.44V。如果这个通道是二次电压通道再结合PT变比还能进一步折算到一次侧数值。做故障分析和保护定值校核时最常用的就是二次侧的瞬时值波形所以这一层换算必须准确。时间轴的处理是另一个容易被忽略的重点。DAT每条记录里的时间戳是相对起始时间的微秒偏移要得到绝对时间必须和CFG最后一行里的录波起始日期时间结合起来。比如起始时间是2024-06-05 08:30:15.500000某条记录时间戳为250000微秒那它的绝对时间就是08:30:15.750000。多采样率拼接是COMTRADE里最有“含金量”的部分。录波器为了兼顾长时记录和高频细节经常在故障前用低采样率比如1000Hz故障后用高采样率比如5000Hz。CFG里“采样率段数各段结束时间”描述的就是这个切换逻辑。实际处理时我会先根据各段采样率和结束时间算出每个采样点应该落在哪个采样率区间。第1段1000Hz、结束时间0.5s那么前0.5秒内大约500个点第2段5000Hz、结束时间0.75s那么0.5秒到0.75秒之间按5000Hz排列。注意这里各段的结束时间是“相对于录波起始点的绝对时间”不是本段的持续时长。计算出每段应有的点数后再按DAT里的时间戳做定位比硬数帧数可靠得多因为有些文件在段切换处的时间戳并不是严格连续的。6. 实战排坑我处理COMTRADE时遇到过的五类问题写了这么多年解析代码COMTRADE文件的“坑”我基本都踩过一遍。挑几个典型问题记录一下希望能帮你少走弯路。第一类通道数对不上。有次批量转换某型号保护装置的CFG声明了12个模拟通道但DAT每条记录里只能解析出11个值波形图凭空少了一相电流。排查后发现是CFG生成逻辑里把备用通道也算进去了DAT却没有实际写入。这种情况下直接按CFG声明数去读取二进制数据会把通道位置全部错位。稳妥做法是解析时校验DAT记录长度发现不一致就及时报警不要盲目继续。第二类二进制格式的“假波形”。第一次解析某厂家32位格式文件时我按16位格式去读结果波形图上出现了明显的“锯齿”和跳变。这是因为32位格式每个模拟通道占用4字节按2字节读等于把一个数值拆成了两个数。判断方法很简单看文件大小与记录数的比值。如果单条记录长度是“8 通道数×2 数字字×2”就是16位如果是“8 通道数×4 数字字×2”就是32位或者直接对比DAT里前几条记录的时间戳是否规律递增。第三类ASCII文件被当成二进制处理。DAT文件后缀都是.dat不打开看根本不知道是文本还是二进制。有的装置用ASCII格式文件里开头就是“1,0,123,456,...”这样的可读字符。如果直接用二进制解析会得到一堆乱码。我现在的处理习惯是打开文件头判断前几个字节是否为数字和逗号如果是就按ASCII逐行解析否则走二进制分支。第四类数字通道状态位读取顺序搞反。标准规定第一个数字通道在16位字的最低位但有些厂商文档写得不清楚容易按“第一个通道在最高位”去解析导致所有开关量状态全部颠倒。验证方法很简单找一路已知正常状态的开关量比如断路器位置看它在故障前后是否和CFG里声明的正常状态一致。第五类多采样率段的时间轴错乱。有的文件在采样率切换点附近时间戳会有一个微小的跳变或重叠如果代码里按“每段固定点数”强行切分拼接出来的波形会错位。最好以DAT里的时间戳为主分段配置只用来辅助判断采样率不要在时间轴上做绝对假设。最后再分享一点个人体会。解析COMTRADE的工具设计上一定要坚持“配置驱动一切”的原则通道数、采样率、换算系数、数字通道状态全部从CFG读取代码里不写死任何厂商相关的假设。这样以后遇到新装置的文件最多就是调一下兼容字段而不用重写核心逻辑。这几年我经手的录波文件加起来有几万份能这么省心靠的就是一开始把解析器的地基打对了。本文还有配套的精品资源点击获取