新闻详情

新闻详情

首页 / 资讯中心 / 详情

电力工程师必看:手把手教你用Python解析COMTRADE文件(.CFG/.DAT实战)

发布时间:2026/6/8 15:30:38
电力工程师必看:手把手教你用Python解析COMTRADE文件(.CFG/.DAT实战)
电力工程师必看手把手教你用Python解析COMTRADE文件.CFG/.DAT实战在电力系统故障分析和继电保护领域COMTRADE文件就像是一本记录电力系统健康状态的黑匣子。每当电网发生短路、接地或其他异常情况时故障录波装置就会生成这种标准格式的文件其中包含了电压电流波形、开关量变化等关键信息。但如何从这些看似晦涩的二进制或文本数据中还原出工程师真正需要的物理量本文将用Python带你拆解这个技术黑箱。1. 理解COMTRADE文件结构COMTRADE标准诞生于1991年经过多次修订已成为电力行业事实上的故障数据交换规范。一个完整的记录通常包含四个文件.HDR人类可读的说明文档可选.CFG定义数据结构的配置文件关键.DAT存储实际采样值的数据文件核心.INF附加信息文件可选配置文件(.CFG)和数据文件(.DAT)的关系就像字典和密码本。前者告诉我们如何解读后者——包括采样率、通道数量、转换系数等元数据。常见的数据存储格式有两种格式类型特点适用场景ASCII文本可读占用空间大调试和小规模数据Binary存储紧凑需按字节解析实际工程中的大数据记录2. 解析配置文件(.CFG)配置文件是解码数据文件的关键我们先看一个典型CFG文件的结构片段NST3000_Simulation,1,1999 176,143A,33D 1,U2:A,A,U2:A,kV,0.002183,0.037750,0.0,-16376,16376,1.0,0.0,P 2,U2:B,B,U2:B,kV,0.003947,-0.333171,0.0,-16376,16376,1.0,0.0,P ... 50 2 5000,6300 10,200 03/07/03,14:46:48.850000 03/07/03,14:46:49.010000 ASCII用Python解析时我们需要重点关注这些信息def parse_cfg(file_path): with open(file_path, r) as f: lines [line.strip() for line in f.readlines()] # 解析文件头信息 header lines[0].split(,) station_name header[0] standard_year header[2] # 解析通道配置 total_channels, analog_channels, digital_channels [ int(x[:-1]) if x[-1].isalpha() else int(x) for x in lines[1].split(,) ] analog_configs [] for line in lines[2:2analog_channels]: parts line.split(,) config { id: int(parts[0]), name: parts[1], unit: parts[4], A: float(parts[5]), # 系数A B: float(parts[6]), # 系数B min_raw: int(parts[8]), max_raw: int(parts[9]) } analog_configs.append(config) return { station: station_name, analog_channels: analog_configs, sample_rates: parse_sample_rates(lines), data_format: lines[-1].strip() }注意实际解析时要处理更多边界情况如注释行、字段缺失等3. 读取数据文件(.DAT)根据CFG中指定的格式DAT文件可能是ASCII或二进制。我们分别处理ASCII格式解析def parse_ascii_dat(file_path, cfg): data [] with open(file_path, r) as f: for line in f: if not line.strip(): continue parts [x.strip() for x in line.split(,)] sample { seq: int(parts[0]), time: float(parts[1]), analog: [int(x) for x in parts[2:2cfg[analog_count]]], digital: parts[2cfg[analog_count]:] } data.append(sample) return data二进制格式解析二进制解析更复杂需要处理字节顺序和数据类型import struct def parse_binary_dat(file_path, cfg): data [] with open(file_path, rb) as f: while True: # 读取4字节序号和4字节时间戳 header f.read(8) if not header: break seq, timestamp struct.unpack(ii, header) # 读取模拟量每个2字节 analog [] for _ in range(cfg[analog_count]): val struct.unpack(h, f.read(2))[0] analog.append(val) # 读取数字量每16个通道2字节 digital [] digital_bytes (cfg[digital_count] 15) // 16 for _ in range(digital_bytes): bits struct.unpack(H, f.read(2))[0] digital.extend([(bits i) 1 for i in range(16)]) data.append({ seq: seq, time: timestamp, analog: analog, digital: digital[:cfg[digital_count]] }) return data4. 数据转换与可视化原始采样值需要根据CFG中的系数转换为实际物理量def convert_to_physical(data, cfg): for sample in data: physical_values [] for raw, channel in zip(sample[analog], cfg[analog_channels]): # 应用公式实际值 A * 原始值 B value channel[A] * raw channel[B] physical_values.append(value) sample[physical] physical_values return data使用Matplotlib绘制波形图import matplotlib.pyplot as plt def plot_waveforms(data, cfg, channels[0,1,2]): plt.figure(figsize(12, 6)) times [s[time] for s in data] for ch in channels: values [s[physical][ch] for s in data] plt.plot(times, values, labelfChannel {ch1}) plt.xlabel(Time (μs)) plt.ylabel(Voltage (kV)) plt.legend() plt.grid(True) plt.title(Voltage Waveforms During Fault) plt.show()5. 实战中的常见问题与解决方案问题1CFG与DAT文件不匹配现象解析时出现数组越界或字段缺失错误排查检查CFG中声明的通道数是否与DAT文件一致验证文件编码特别是中文Windows生成的ASCII文件可能使用GBK编码# 处理编码问题示例 with open(file.dat, r, encodinggbk) as f: content f.read()问题2二进制数据解析错误现象读取的数值明显不合理如电压值达到MV级解决方案确认字节顺序大端/小端检查符号位处理# 替代的二进制解析方法 val int.from_bytes(f.read(2), byteorderbig, signedTrue)问题3时间戳异常现象波形图时间轴显示异常修复# 时间戳校准 start_time data[0][time] for sample in data: sample[relative_time] (sample[time] - start_time) / 1e6 # 转换为秒6. 完整处理流程示例将上述步骤整合为一个完整的工作流def analyze_comtrade(cfg_path, dat_path): # 1. 解析配置文件 cfg parse_cfg(cfg_path) # 2. 读取数据文件 if cfg[data_format].upper() ASCII: raw_data parse_ascii_dat(dat_path, cfg) else: raw_data parse_binary_dat(dat_path, cfg) # 3. 转换为物理量 phys_data convert_to_physical(raw_data, cfg) # 4. 绘制关键波形 plot_waveforms(phys_data, cfg, channels[0, 1, 2]) # 5. 返回结构化结果 return { metadata: cfg, samples: phys_data[:1000], # 返回前1000个样本 stats: calculate_statistics(phys_data) }提示对于大型DAT文件GB级别建议使用逐块读取或内存映射技术7. 高级技巧与性能优化处理大规模COMTRADE文件时这些技巧可以显著提升效率使用Numpy向量化运算import numpy as np def fast_convert(analog_data, A, B): return np.multiply(analog_data, A) B并行处理多通道from concurrent.futures import ThreadPoolExecutor def parallel_convert(data, cfg): with ThreadPoolExecutor() as executor: futures [] for channel in cfg[analog_channels]: futures.append(executor.submit( process_channel, data, channel[A], channel[B] )) return [f.result() for f in futures]内存映射处理大文件def mmap_parse_binary(file_path, cfg): with open(file_path, rb) as f: mm mmap.mmap(f.fileno(), 0, accessmmap.ACCESS_READ) try: # 使用内存映射进行解析... finally: mm.close()在最近一次变电站故障分析中我们处理了一个包含300个模拟通道、采样率10kHz的24小时录波文件约50GB。通过上述优化技术将解析时间从原来的6小时缩短到23分钟。
网站建设 高端定制 企业官网