comtrade_format.h
1: /*
2: * 分析解析COMTRADE(IEEE文件格式为标准电力系统临态数据交换通用格式)。
3: *
4: * (一)IEEE的COMTRADE数据格式
5: *
6: * COMTRADE是IEEE标准电力系统临时数据交换的一般格式。该标准定义了电力系统或电力系统模型采集的临时波形和事故数据文件的格式。
7: * 该格式旨在提供一于解释的数据交换通用格式。IEEE1991年提出,1999年修订完善。COMTRADE最多有4组记录
8: * 四份文件中的每一份都有不同的信息等级。四份文件如下:
9: *
10: * (1)标题文件(xxxxxxxx.HDR)
11: * 由标题文件COMTRADE由数据原创者建立的可选数据ASCII标题文件的创建者可以按任何需要的顺序创建任何信息。标题文件
12: * 格式为ASCII。
13: *
14: * (2)、 配置文件(xxxxxxxx.CFG)
15: * 一种配置文件ASCII文本文件用于正确解释数据(.DAT)因此,文件的格式必须以特定的格式保存。该文件解释了数据(.DAT)文
16: * 本文包含采样速率、通道数量、频率、通道信息等信息。配置文件第一行中的字段识别文件 COMTRADE标准版
17: * 本年(如1991年、1999年等)。如果字段不存在或空,则假设文件符合标准的初始发行日期(1991年)。配置文件还包括识别伴随
18: * 数据文件是以ASCII格式仍然是以二进制格式存储的字段。 配置文件包括以下信息:
19: * (a)站名,记录装置的特性,COMTRADE 标准修改年
20: * (b)通道的数量和类型
21: * (c)通道名称、单位和转换系数
22: * (d)线路频率
23: * (e)每个速率下的采样速率和采样数量
24: * (f)第一数据点的日期和时间
25: * (g)触发点、日期和时间
26: * (h)数据文件类型
27: * (i)时间标记倍乘系数
28: *
29: * (3)、 数据文件(xxxxxxxx.DAT)
30: * 数据文件包含记录中每个采样所有输入通道的值。数据文件包含一个顺序号和每次采样的时间标志。这些采样值除记录模拟输入的数据之外,
31: * 也记录状态,即输入开/关信号。
32: *
33: * (4)、 信息文件(xxxxxxxx.INF)
34: * 信息文件是创建者希望之对用户有用的信息之外的特别信息。信息文件是可选文件。
35: *
36: * COMTRADE定义的所有文件,都在IEEE 标准电力系统暂态数据交换通用格式Std C37.111-1991或IEEE Std C37.111-1999版本中进行了诠释。
37: *
38: * (二) 电力系统故障动态记录技术准则
39: *
40: * 电力行业标准《220kV~500kV电力系统故障动态记录技术准则》(DL/T 553-94),是故障录波装置研制和开发中必须依据的标准。标准在3.6.5
41: * 条中规定了,输出的动态过程记录数据应符合的标准格式与ANSI/IEEE Std C37.111-1991 COMTRADE兼容。同时,标准规定了电力系统发生故障
42: * 的整个过程中,模拟量采集方式的数据记录按时段顺序进行。
43: * A时段:系统在扰动开始前的状态数据,直接输出原始采集波形,记录时间≥0.04S
44: * B时段:系统大扰动初期的状态数据,直接输出原始采集波形,记录时间≥0.1S
45: * C时段:系统大扰动后的中期状态数据,可输出连续工频有效值,记录时间≥1.0S
46: * D时段:系统动态过程数据,每0.1S输出一个工频有效值,记录时间≥20S
47: * E时段:系统长过程的动态数据,每0.1S输出一个工频有效值,记录时间≥10min
48: * 这里,技术标准的数据记录有两个主要特点,一是分段记录,二是记录的数据不仅可以有按某一采样率的采样数据,而且可按一定间隔记录有效
49: * 值以代替采样值。
50: *
51: *(三) 微机故障录波装置和COMTRADE文件
52: *
53: * 微机故障录波装置,基本配置分为一台采集站和一台分析站,采集站和分析站之间通过高速以太网连接。采集站负责采集、记录故障数据;采集
54: * 站采集的原始数据或记录的原始故障数据,除了存入采集站的硬盘保存外,还将通过网络把数据上传到分析站。分析站程序采用VC 6.0编制,完
55: * 成对数据处理、波形显示、自动分析、与远方通信功能。数据处理中,自动生成符合COMTRADE格式的文件。装置接收故障采样数据后,直接将数
56: * 据处理成COMTRADE数据格式的文件。故障录波装置模拟量采样频率为5000次/秒,采样时段根据电力系统故障动态记录技术准则,做了相应调整,
57: * 将C时段调整为直接输出原始采集波形,记录时间≥1.0S,这样ABC时段采样频率为5000次/秒,存实时的模拟数据;而DE时段采样频率为10次/秒,
58: * 用存最大值数据来代替有效值,这样便于产生包络线波形。我们省略了标题文件和信息文件,并且根据不同的批次和故障次数,定义文件名,生
59: * 成的配置文件( DIR00.CFG )和数据文件( DIR00.DAT ),并同时存放于同一批次文件夹DIR00内。文件示例如下列所示。
60: *
61: * (1)、配置文件( DIR00.CFG )
62: * 城东变电所,03 【注:变电站名称 录波器编号】
63: * 12, 8A, 4D 【注:12格通道,8个模拟通道,4个数字通道】
64: * 1, 1 Ia, A, mx1, A, 8.46830338, 0.00000000, 0, -2048, 2047 【注:模拟量依次为:通道编号,通道名称,通道相,XX,单位,fCoefA[变
65: * 换因子A],fCoefB[变换因子B],fTime[时间偏移],fMin[此模拟量采样记录数据最小值], fMax[此模拟量采样记录数据最大值],
66: * 其中:实际值y与采样记录数据X的关系:y = fCoefA * X + fCoefB, 所以实际的最值:
67: * Min = fCoefA * fMin + fCoefB; Max = fCoefA * fMax~ + fCoefB; 】
68: * 2, 1 Ib, B, mx1, A, 8.46830338, 0.00000000, 0, -2048, 2047
69: * 3, 1 Ic, C, mx1, A, 8.46830338, 0.00000000, 0, -2048, 2047
70: * 4, 1 IN, N, mx1, A, 8.46830338, 0.00000000, 0, -2048, 2047
71: * 5, mx1 Ua, A, , kV, 0.15540126, 0.00000000, 0, -2048, 2047
72: * 6, mx1 Ub, B, , kV, 0.15540126, 0.00000000, 0, -2048, 2047
73: * 7, mx1 Uc, C, , kV, 0.15540126, 0.00000000, 0, -2048, 2047
74: * 8, mx1 UN, N, , kV, 0.15540126, 0.00000000, 0, -2048, 2047
75: * 1,开关1,0 【注:通道编号/序号、通道名称、数字量初始状态】
76: * 2,开关2,0
77: * 3,开关3,0
78: * 4,开关4,1
79: * 50 【注:系统电流电压的频率为50Hz】
80: * 2 【注:有两个采样频率】
81: * 5000, 6300 【注:第一个采样频率: 在采样率为5000Hz下采了6300个点】
82: * 10, 200 【注:第二个采样频率: 在采样率为10Hz下采了200个点】
83: * 03/07/03,14:46:48.850000 【注:采样开始时间】
84: * 03/07/03,14:46:49.010000 【注:采样结束时间】
85: * ASCII 【注:dat文件记录格式为ASCII, 还有一种是BINARY(二进制格式)】
86: *
87: *(2)、 数据文件( DIR00.DAT )
88: * 1, 0, 46, -54, 10, 0, 1204, -734, -442, 60, 0, 1, 0, 1 【注:依次为:序号,采样时间,模拟采样记录值[按cfg文件的顺序],数
89: * 字采样记录值[按cfg文件的顺序],其中模拟量实际值算法:y = fCoefA * X + fCoefB, 同最值计算方法;如:
90: * 对于46表示的实际值y为:y = fCoefA(即8.46830338) * X(即46) + fCoefB(即0.00000000)
91: * 对于-54表示的实际值y为:y = fCoefA(即8.46830338) * X(即-54) + fCoefB(即0.00000000)
92: * 对于10表示的实际值y为:y = fCoefA(即8.46830338) * X(即10) + fCoefB(即0.00000000)
93: * 对于0表示的实际值y为:y = fCoefA(即0.15540126) * X(即0) + fCoefB(即0.00000000)
94: * 对于1024表示的实际值y为:y = fCoefA(即0.15540126) * X(即1024) + fCoefB(即0.00000000) 】
95: * 2, 200, 48, -54, 6, 0, 1218, -682, -504, 60, 0, 1, 0, 1
96: * 3, 400, 50, -52, 4, -2, 1206, -616, -554, 58, 0, 1, 0, 1
97: * 4, 600, 52,-50, -2, 0, 1192, -542, -614, 56, 0, 1, 0, 1
98: *
99: * 注:以上说明文字部分来自网络。
100: *
101: * 另外,对于Binary保存方式的数据文件(dat文件),数据保存格式为:序号[4字节]、采样时间[4字节]、模拟量值[按cfg文件的顺序,两字节
102: * 表示一个模拟量采样值]、数字量组值[按cfg文件的顺序,16个数字量一组,一组用2字节表示,不够一组的空位(高位)补零构成一组,组内
103: * 从低位bit依次到高位bit与cfg文件里的数字量顺序对应]。
104: *
105: * 经验表明,目前大部分comtrade文件中的cfg文件中所表示的通道最值与dat中实际的最值都是不相符(出入很大),所以在读dat的接口中引入
106: * 了最值统计。
107: *
108: * 本代码支持win32平台和linux平台。
109: *
110: * Copyright,lizhi<ibox>
111: *
112: * 2012-10-10 V1.0 lizhi<QQ:252240557,msn:ddgooo@hotmail.com> created
113: *
114: */
115:
116:
117: #ifndef __INCLUDE_COMTRADE_FORMAT_H
118: #define __INCLUDE_COMTRADE_FORMAT_H
119:
120:
121:
122: /*
123: * 头文件
124: */
125: #include "base_type.h"
126:
127:
128: #if defined (__cplusplus)
129: extern "C" {
130: #endif /* defined (__cplusplus) */
131:
132:
133: /*
134: * 宏开关 定义为文件读写
135: */
136: #define CMTR_IOFILE
137:
138:
139:
140: /*
141: * 宏定义文件的读写操作,可以根据需要改写该接口,如重定义
142: * 为网口的recv\send、串口r\w等。
143: *
144: * _my_read_cmtr_bufn/_my_read_cmtr_bufn - cmtr的读写操作
145: * @pfd: 读写地址,可以为文件的fd、或者buffer地址等
146: * @buf: 缓冲区地址
147: * @count: 需要读写的字节数
148: *
149: */
150: #if defined(CMTR_IOFILE)
151: typedef int _my_cmtr_ioptr;
152: #define _my_read_cmtr_bufn(pfd, buf, count) \
153: do { \
154: if (read((pfd), (buf), (count)) <= 0) { \
155: (pfd) = -1; \
156: } \
157: } while(0);
158: #define _my_write_cmtr_bufn(pfd, buf, count) \
159: do { \
160: if (write((pfd), (buf), (count)) <= 0) {\
161: (pfd) = -1; \
162: } \
163: } while(0);
164: #define _my_check_cmtr_ptr(pfd) \
165: (((pfd) != -1) && ((pfd) != 0))
166: #elif defined(CMTR_IOBUFFER)
167: typedef u8* _my_cmtr_ioptr;
168: #define _my_read_cmtr_bufn(pfd, buf, count) \
169: do { \
170: memcpy((buf), (pfd), (count)); \
171: (pfd) += (count); \
172: } while(0);
173: #define _my_write_cmtr_bufn(pfd, buf, count) \
174: do { \
175: memcpy((pfd), (buf), (count)); \
176: (pfd) += (count); \
177: } while(0);
178: #define _my_check_cmtr_ptr(pfd) \
179: (((pfd) != -1) && ((pfd) != 0))
180: #endif
181:
182:
183:
184: /*
185: * 关于comtrade文件配置文件的宏定义。
186: * 在此采用预定义最大个数方法,避免动态内存管理的问题。
187: *
188: * 相关字符串最大字符个数,一般不会超过16个;
189: * 模拟量端口最大个数,一般不会超过64个;
190: * 数字量量端口最大个数,一般不会超过64个;
191: * 采样率最大个数,一般不会超过8个;
192: *
193: */
194: #define CMTR_STRING_MAX_LENGTH 64
195: #define CMTR_ANALOG_MAX_COUNT 255
196: #define CMTR_DIGIT_MAX_COUNT 255
197: #define CMTR_SMPRATE_MAX_COUNT 255
198:
199:
200:
201: /*
202: * cmtr_cfg_analog - 配置文件模拟量信息
203: * @index: 模拟量端口序号(只是编号,解析时不做序号用);
204: * @name: 模拟量端口名称;
205: * @phase: 模拟量端口相标识,值如(A、B、C、N等);
206: * @element:标识(还未知,待补充),一般为空;
207: * @unit: 模拟量端口数值的单位,该单位常用来区分该端口是电流还是电流,值如:kV、V、A、mA等;
208: * @factor_a: 系数a,一般为整数,可以是浮点数;
209: * @factor_b: 系数b,一般为整数,可以是浮点数;
210: * @offset_time: 时间偏移,指第一个点的时间偏移量,一般为0;
211: * @smp_min: 通道的最小采用值,一般为整数,国内有些变态的仪器会生成浮点数(在次不支持);
212: * @smp_max: 通道的最大采用值,一般为整数,国内有些变态的仪器会生成浮点数(在次不支持);
213: *
214: * 通道采样的实际值计算方法:实际值 = factor_a * smp_value + factor_b;所以根据该公式,可以计算
215: * 通道的最小值为:factor_a * smp_min + factor_b,最大值为:factor_a * smp_max + factor_b。
216: *
217: * 注:本来smp_min、smp_max为两个字节的一个数据(即最大为65535),但不同厂家会生成很大的四字节数据,
218: * 所以采用s32类型;factor_a、factor_b用double类型,用float可能会丢精度;为了提供解析程序的适
219: * 应性,以适应国内各种变态的有标准不遵循的厂家的仪器生成的cmtr文件。
220: *
221: */
222: struct cmtr_cfg_analog {
223: s32 index;
224: u8 name[CMTR_STRING_MAX_LENGTH];
225: u8 phase[CMTR_STRING_MAX_LENGTH];
226: u8 element[CMTR_STRING_MAX_LENGTH];
227: u8 unit[CMTR_STRING_MAX_LENGTH];
228: f64 factor_a;
229: f64 factor_b;
230: s32 offset_time;
231: s32 smp_min;
232: s32 smp_max;
233: };
234:
235:
236: /*
237: * cmtr_cfg_digit - 配置文件数字量信息
238: * @index: 数字量端口序号(只是编号,解析时不做序号用);
239: * @name: 数字量端口名称;
240: * @state: 数字量起始状态值,一般为1或者0,很少情况下会为2;
241: *
242: */
243: struct cmtr_cfg_digit {
244: s32 index;
245: u8 name[CMTR_STRING_MAX_LENGTH];
246: s8 state;
247: };
248:
249: /*
250: * cmtr_cfg_smprate_info - 配置文件采样点信息
251: * @rate: 采样率,一般为整数,也有小数表示的;
252: * @point: 该采样率下采样的点数,为整数;
253: *
254: */
255: struct cmtr_cfg_smprate {
256: f32 rate;
257: s32 point;
258: };
259:
260: /*
261: * cmtr_cfg_info - 配置文件信息。
262: * @station_name: 厂站名称;
263: * @kymograph_id: 录波器编号;
264: * @analog_count: 模拟量个数;
265: * @digit_count: 数字量个数;
266: * @analogs: 模拟量信息;
267: * @digits: 数字量信息;
268: * @frequency: 基本频率,一般为额定频率,指的是电网频率;
269: * @smprate_count: 采样率个数;
270: * @smprates: 采样率信息;
271: * @begin_time: 录波开始时间;
272: * @end_time: 录波结束时间;
273: * @file_type: 数据文件类型,可以“ASCII”和“Binary”,ASCII类型为dat文件可以用记事本打开看详
274: * 细的采样信息;binary格式的只能用特殊的工具查看,为二进制数据文件;
275: *
276: */
277: typedef struct cmtr_cfg_info {
278: u8 station_name[CMTR_STRING_MAX_LENGTH];
279: u8 kymograph_id[CMTR_STRING_MAX_LENGTH];
280: s32 analog_count;
281: s32 digit_count;
282: struct cmtr_cfg_analog analogs[CMTR_ANALOG_MAX_COUNT];
283: struct cmtr_cfg_digit digits[CMTR_DIGIT_MAX_COUNT];
284: f32 frequency;
285: s32 smprate_count;
286: struct cmtr_cfg_smprate smprates[CMTR_SMPRATE_MAX_COUNT];
287: u8 begin_time[CMTR_STRING_MAX_LENGTH];
288: u8 end_time[CMTR_STRING_MAX_LENGTH];
289: u8 file_type[CMTR_STRING_MAX_LENGTH];
290: };
291:
292:
293:
294: /*
295: * cmtr_dat_smpdot - 数据文件中的采样点数据信息.
296: * @index: 端口序号(只是编号,解析时不做序号用);
297: * @time: 采样点采样时间偏移量,单位微妙;
298: * @analogs: 模拟量信息,一般为有符号整数,国内有些变态的仪器会生成浮点数(在此不支持);
299: * @digits: 数字量信息,为有符号整数;
300: *
301: */
302: struct cmtr_dat_smpdot{
303: s32 index;
304: s32 time;
305: s32 analogs[CMTR_ANALOG_MAX_COUNT];
306: s8 digits[CMTR_DIGIT_MAX_COUNT];
307: };
308:
309:
310:
311:
312:
313: /*
314: * write_cmtr_cfg_info - 写cmtr配置文件.
315: * @pfd: 输入输出参数,地址
316: * @cfg:输入参数,cmtr(cfg文件)结构体
317: * @counter: 输出参数,写入的字节计数器;
318: *
319: * 返回当前pfd指针,写失败返回NULL
320: *
321: */
322: _my_cmtr_ioptr write_cmtr_cfg_info(_my_cmtr_ioptr pfd,
323: struct cmtr_cfg_info *cfg,
324: int *counter);
325:
326:
327: /*
328: * write_cmtr_dat_smpdot_ascii - 写cmtr采样点数据信息(ascii格式).
329: * @pfd: 输入输出参数,地址
330: * @analog_count: 输入参数,模拟量个数;
331: * @digit_count: 输入参数,数字量个数;
332: * @dot: 输入参数,采样点信息;
333: * @counter: 输出参数,写入的字节计数器;
334: *
335: * 返回当前pfd指针,写失败返回NULL
336: *
337: */
338: _my_cmtr_ioptr write_cmtr_dat_smpdot_ascii(_my_cmtr_ioptr pfd,
339: int analog_count, int digit_count,
340: struct cmtr_dat_smpdot *dot,
341: int* counter);
342:
343: /*
344: * write_cmtr_dat_smpdot_binary - 写cmtr采样点数据信息(binary格式).
345: * @pfd: 输入输出参数,地址
346: * @big_endian_tag: 输入参数,标识文件中数据的字节顺序,为FALSE按照小端写(默认值),True按照大端写;
347: * @analog_count: 输入参数,模拟量个数;
348: * @digit_count: 输入参数,数字量个数;
349: * @dot: 输入参数,采样点信息;
350: * @counter: 输出参数,写入的字节计数器;
351: *
352: * 返回当前pfd指针,写失败返回NULL
353: *
354: */
355: _my_cmtr_ioptr write_cmtr_dat_smpdot_binary(_my_cmtr_ioptr pfd,
356: u8 big_endian_tag,
357: int analog_count, int digit_count,
358: struct cmtr_dat_smpdot *dot,
359: int* counter);
360:
361:
362: /*
363: * read_cmtr_cfg_info - 读cmtr配置文件.
364: * @pfd: 输入输出参数,地址
365: * @cfg:输出参数,cmtr(cfg文件)结构体
366: * @counter: 输出参数,读取的字节计数器;
367: *
368: * 返回当前pfd指针,读失败返回NULL
369: *
370: */
371: _my_cmtr_ioptr read_cmtr_cfg_info(_my_cmtr_ioptr pfd,
372: struct cmtr_cfg_info *cfg,
373: int* counter);
374:
375:
376: /*
377: * read_cmtr_dat_smpdot_ascii - 读ascii格式cmtr采样点数据信息.
378: * @pfd: 输入输出参数,地址
379: * @read_buf: 输入参数,读缓冲,在外部申请内存,避免在内部频繁申请、释放内存;
380: * @buf_size: 输入参数,读缓冲区的大小;
381: * @analog_count: 输入参数,模拟量个数;
382: * @digit_count: 输入参数,数字量个数;
383: * @dot: 输出参数,采样点信息;
384: * @the_smp_mins: 输出参数,统计最小值,为数组,个数至少为analog_count个,值为NULL时忽略统计;
385: * @the_smp_maxs: 输出参数,统计最大值,为数组,个数至少为analog_count个,值为NULL时忽略统计;
386: * @counter: 输出参数,读取的字节计数器;
387: *
388: * 返回当前pfd指针,读失败返回NULL
389: *
390: */
391: _my_cmtr_ioptr read_cmtr_dat_smpdot_ascii(_my_cmtr_ioptr pfd,
392: u8 *read_buf, int buf_size,
393: int analog_count, int digit_count,
394: struct cmtr_dat_smpdot *dot,
395: u16* the_smp_mins, u16* the_smp_maxs,
396: int* counter);
397:
398: /*
399: * read_cmtr_dat_smpdot_binary - 读bin格式cmtr采样点数据信息.
400: * @pfd: 输入输出参数,地址
401: * @big_endian_tag: 输入参数,标识文件中数据的字节顺序,为FALSE按照小端读(默认值),True按照大端读;
402: * @analog_count: 输入参数,模拟量个数;
403: * @digit_count: 输入参数,数字量个数;
404: * @dot: 输出参数,采样点信息;
405: * @the_smp_mins: 输出参数,统计最小值,为数组,个数至少为analog_count个,值为NULL时忽略统计;
406: * @the_smp_maxs: 输出参数,统计最大值,为数组,个数至少为analog_count个,值为NULL时忽略统计;
407: * @counter: 输出参数,读取的字节计数器;
408: *
409: * 返回当前pfd指针,读失败返回NULL
410: *
411: */
412: _my_cmtr_ioptr read_cmtr_dat_smpdot_binary(_my_cmtr_ioptr pfd, u8 big_endian_tag,
413: int analog_count, int digit_count,
414: struct cmtr_dat_smpdot *dot,
415: u32* the_smp_mins, u32* the_smp_maxs,
416: int* counter);
417:
418: /*
419: * print_cmtr_cfg_info - 打印cmtr文件配置数.
420: * @cfg: 输入参数,cmtr文件配置数据;
421: *
422: */