CSV to IEC61850 CID 转换器设计

1. 引言
1.1 项目背景
IEC 61850 是电力自动化领域的重要标准,其中 CID(Configured IED Description)文件描述了智能电子设备(IED)的配置信息,包括数据集、报告控制块、数据实例等。在工程实践中,往往需要从 CSV 表格导入配置数据,自动生成符合标准的 CID 文件,以提高配置效率和准确性。
1.2 目的与目标
本程序旨在提供一个图形化工具,通过解析用户定义的 CSV 文件,结合 IEC 61850 数据类型模板(DataTypeTemplates.xml),生成完整的 CID 文件。主要目标包括:
- 支持多逻辑设备(LDevice)配置,LDevice 实例名取自 CSV。
- 自动为每个数据集生成报告控制块(仅当数据集包含 ST/MX 类型数据)。
- 根据 CSV 中的描述(desc)填充 DOI 的 desc 属性和 dU 的值。
- 支持 CSV 中指定数据属性(DAI)的 sAddr 属性。
- 对 CSV 中出现的所有 DO/DA 路径进行模板存在性校验,确保配置与模板一致。
- 提供详细的调试日志窗口,方便用户排查问题。
2. 系统概述
2.1 功能简介
程序通过 PyQt6 构建图形界面,主要流程如下:
- 用户选择 CSV 文件(可自动检测编码)和数据类型模板 XML 文件。
- 点击“Parse CSV”按钮,预览 CSV 数据。
- 点击“Generate CID”按钮,程序解析 CSV、验证模板、生成 CID 文件,并弹出保存对话框。
- 底部的调试窗口实时显示解析过程中的警告、错误和统计信息。
2.2 技术栈
- 编程语言:Python 3
- GUI 框架:PyQt6
- 数据处理:csv 模块(标准库)、xml.etree.ElementTree(标准库)
- 编码检测:尝试常用编码(utf-8, gbk, gb2312, ansi, cp1252)
3. 功能需求
3.1 核心功能
- CSV 解析:读取 CSV 文件,支持多种编码,自动检测。
- 数据类型模板加载:解析 DataTypeTemplates.xml,提取 LNodeType、DOType、DAType、EnumType。
- 逻辑节点(LN)实例化:根据 CSV 中出现的 LNType 自动创建 LN 元素,并为每个 LN 下的 DO 生成 DOI 及其子 DAI。
- 数据集生成:根据 CSV 中 Type=Dataset 的行,为每个数据集名称收集 FCDA 列表,生成 DataSet 元素。
- 报告控制块生成:仅当数据集所有 FCDA 的 FC 为 ST 或 MX 时生成 ReportControl,并根据 FC 类型决定缓冲属性(ST→缓冲,MX→非缓冲,混合→缓冲并告警)。报告属性包括 intgPd="30000", rptID="NULL", bufTime="100" 等,TrgOps 和 OptFields 按示例固定。
- DOI 描述映射:将 CSV 中的 Desc 列设置为对应 DOI 的 desc 属性,并用于填充 dU 的值。
- sAddr 属性:将 CSV 中的 sAddr 列设置为对应 DAI 的 sAddr 属性(支持复合 DA 路径,如 mag.f)。
- 多 LDevice:根据 CSV 中的 LDName 列创建多个 LDevice,LDevice 顺序与 CSV 中首次出现顺序一致,每个 LDevice 下拥有独立的 LLN0。
- prefix 支持:CSV 中的 prefix 列应用到 FCDA 和 LN 元素。
- 模板存在性校验:对 CSV 中每一行(包括 Dataset 和 Control)的 DO 和 DA 路径,递归检查是否在模板中存在,若不存在则报错并终止生成。
- LN 重复性校验:同一 LDevice 下不允许出现相同的 (prefix, lnClass, lnInst) 组合。
- 数据集 FCDA 数量限制:单个数据集的 FCDA 数量超过 256 时报错。
- FCDA 简化:生成的 FCDA 中不包含 daName 属性。
3.2 高级特性
- 自动为 LLN0 创建默认实例(若 CSV 中未定义)。
- 报告按 LDevice 分组,每个 LDevice 内先放置所有 DataSet,再放置所有 ReportControl。
- 支持排除特定 DO(如 SV)和特定 DAI(如 subEna, subVal 等取代相关 DAI)的实例化。
- 跳过 fc=CF 的 DAI 实例化。
4. 系统架构
4.1 总体架构
程序采用 MVC 风格的单窗口架构,由以下几部分组成:
- 视图层:MainWindow 类(PyQt6),包含文件选择、按钮、表格、日志窗口。
- 控制层:MainWindow 的事件处理方法(parse_csv, generate_cid),负责协调数据流。
- 模型层:DataTypeResolver 类(模板解析与查询)、CSV 解析函数、CID 生成函数(generate_cid)。
4.2 模块划分
- CSV 解析模块:
parse_csv函数,自动检测编码,返回列表字典。 - 模板解析模块:
DataTypeResolver类,解析 XML 并构建类型字典,提供类型查询、默认值获取、路径验证等功能。 - 数据收集与验证模块:在
MainWindow.generate_cid中,分多步收集原始数据、验证 LN 重复性、验证模板路径、构建最终数据结构。 - CID 生成模块:
generate_cid函数,接收处理好的数据结构,构造 SCL 树并写入文件。 - 日志模块:通过
log_message回调,将信息输出到调试窗口。
5. 模块设计
5.1 DataTypeResolver 类
- 属性:
lnode_types,do_types,da_types,enum_types:字典,ID 到对应 XML 元素的映射。
- 方法:
_parse():遍历模板根节点,填充各字典。get_ln_type(type_id)、get_do_type(type_id)、get_da_type(type_id):返回对应元素,若不存在则记录警告。get_enum_default(enum_type_id):返回枚举类型中ord最小的枚举值文本。verify_do_da_path(ln_type_id, do_name, da_full_path):递归验证给定 LN 类型下是否存在指定 DO 的 DA 路径。利用_find_da_in_do_type和_find_bda_in_da_type实现。generate_doi_for_ln(...):核心方法,为指定 LN 生成所有 DOI。遍历 LNodeType 的 DO 元素,为每个 DO 创建 DOI,调用_generate_dai_for_do递归生成 DAI,并在控制 DO 时强制注入 ctlModel/sboTimeout。_generate_dai_for_do、_generate_bda_for_da_type、_create_dai:递归处理 DOType 和 DAType,生成 DAI 或 SDI,并根据模板默认值、CSV 描述、sAddr、控制标志等设置值。
5.2 数据收集与验证模块
位于 MainWindow.generate_cid 中,分为多个步骤:
- 收集原始数据:遍历所有 CSV 行(仅 Dataset 和 Control),提取:
raw_ln_info:键 (ld, prefix, ln_inst, ln_type) → True,用于后续 LN 实例收集。raw_fcda_list:仅 Dataset 行,存储数据集信息。raw_do_desc:键 (ld, prefix, ln_inst, ln_type, do_name) → desc,用于 DOI 描述。raw_dai_saddr:键 (ld, prefix, ln_inst, ln_type, do_name, da_name) → sAddr。validation_items:存储 (ld, prefix, ln_inst, ln_type, do_name, da_name) 用于模板验证。
- LN 解析与重复性校验:
- 遍历
raw_ln_info,通过dt_resolver.get_ln_type获取 lnClass,构建ln_candidates列表。 - 检查重复 LN(同一 LD 下 (prefix, ln_class, ln_inst) 是否重复),若重复则报错退出。
- 构建最终
ln_instances字典:键 (ld, prefix, ln_class, ln_inst) → ln_type。
- 遍历
- 模板存在性校验:
- 遍历
validation_items,利用dt_resolver.verify_do_da_path验证路径,失败则记录并最终报错。
- 遍历
- 构建 do_desc_map、dai_saddr_map:将原始键中的 ln_type 替换为 ln_class。
- 构建 control_do_by_ln:记录每个 LN 下的控制 DO 名称集合。
- 构建 datasets:将
raw_fcda_list转换为以数据集名称为键的字典,每个 fcda 包含 ldInst, prefix, lnClass, lnInst, doName, daName, fc。
5.3 CID 生成模块(generate_cid 函数)
- 创建 SCL 根元素,添加固定的 Header、Communication 块(模板化内容)。
- 添加 IED 元素,并在其中添加固定的 Services 块。
- 创建 AccessPoint(name="S1")和 Server,并添加 Authentication。
- 多 LDevice 处理:
- 收集所有出现的 LDevice 名称,按首次出现顺序构建列表。
- 为每个 LDevice 创建
<LDevice>元素,inst属性直接取 LDName。
- 创建 LN 元素:
- 先遍历所有 LDevice,为每个 LDevice 创建其下的 LLN0(若 CSV 中未定义,则自动创建默认 LLN0)。
- 再创建其他 LN,确保 LLN0 位于 LDevice 子节点最前面。
- 数据集与报告分组:
- 将数据集按 LDevice 分组(
ld_datasets)。 - 对每个 LDevice,先遍历所有数据集生成
<DataSet>元素,再遍历所有数据集生成<ReportControl>元素,实现所有数据集在前、所有报告在后的顺序。
- 将数据集按 LDevice 分组(
- 报告生成逻辑:
- 检查数据集所有 FCDA 的 FC 集合,若不为 {'ST'}、{'MX'} 或 {'ST','MX'} 则跳过。
- 根据 FC 集合确定缓冲属性、entryID 值。
- 设置报告属性:
name(brcb/urcb+数据集名首字母大写)、datSet、intgPd="30000"、rptID="NULL"、confRev="1"、buffered、bufTime="100"。 - 添加 TrgOps 和 OptFields 子元素(按示例固定)。
- DOI 生成:
- 遍历所有 LN 元素,调用
dt_resolver.generate_doi_for_ln,传入对应 LN 的 do_desc_map、dai_saddr_map 和控制 DO 集合。 - 在
generate_doi_for_ln内部,处理完模板中的 DAI 后,若 DO 在控制集合中,则强制添加/覆盖 ctlModel 和 sboTimeout。
- 遍历所有 LN 元素,调用
- 添加数据类型模板(深拷贝后附加)。
- 写入文件,使用 ET.indent 美化输出。
5.4 GUI 界面(MainWindow 类)
- 布局:垂直布局,包含文件选择、IED 名称输入、解析按钮、表格、生成按钮、调试窗口。
- 表格:用于预览 CSV 数据,自动调整列宽。
- 调试窗口:只读 QTextEdit,通过
log_message方法添加带时间戳的日志,自动滚动到底部。 - 按钮事件:
browse_file:选择 CSV 文件。browse_dt_file:选择 XML 模板文件,加载并初始化 DataTypeResolver。parse_csv:解析 CSV 并填充表格。generate_cid:执行上述数据收集、验证、生成流程,若出错则弹出消息框并记录日志。
6. 关键算法与数据结构
6.1 CSV 编码检测
尝试一系列常用编码(utf-8, gbk, gb2312, ansi, cp1252),直至成功读取。若全部失败,抛出异常。
6.2 模板路径验证算法
verify_do_da_path 采用递归下降方式:
- 首先在 LNodeType 中查找指定 DO,获取其 DOType ID。
- 然后在 DOType 中按路径段逐步查找:若当前段对应 SDO,则进入其引用的 DOType;若对应 DA 且 bType="Struct",则进入其引用的 DAType;若对应 DA 且为叶子,则返回成功;若对应 BDA,类似处理。
- 若任何一步查找失败,返回 False 并记录详细日志。
6.3 递归生成 DOI/DAI
generate_doi_for_ln 遍历 LNodeType 的 DO,为每个 DO 创建 DOI,然后调用 _generate_dai_for_do 处理 DOType 的 DA 和 SDO。_generate_dai_for_do 递归遍历 DA 和 SDO,对于结构体类型,创建 SDI 并进入子结构。此过程中,会利用传入的 dai_saddr_map(键为 (do_name, full_path))为叶子 DAI 设置 sAddr 属性,并根据是否控制 DO 和当前 DA 名称,决定是否覆盖值为固定值。
6.4 多 LDevice 顺序保持
使用 OrderedDict 和列表记录首次出现的 LDevice 名称,确保生成顺序与 CSV 中首次出现顺序一致。
6.5 数据集与报告顺序控制
在 generate_cid 中,对每个 LDevice 先循环生成所有 DataSet,再循环生成所有 ReportControl,不混合。
6.6 控制 DO 特殊 DAI 注入
在 generate_doi_for_ln 中,处理完模板中的 DAI 后,通过 doi.find 检查是否已存在 ctlModel 和 sboTimeout,若不存在则创建新的 DAI,并设置固定值的 <Val> 子元素。这保证了即使模板中未定义这些 DAI,最终 CID 中也会出现。
6.7 数据结构设计
ln_instances:{(ld, prefix, lnClass, lnInst): ln_type},用于快速查找 LN 类型。do_desc_map:{(ld, prefix, lnClass, lnInst, doName): desc},用于设置 DOI 的 desc。dai_saddr_map:{(ld, prefix, lnClass, lnInst, doName, fullDaPath): sAddr},用于设置 DAI 的 sAddr。control_do_by_ln:{(ld, prefix, lnClass, lnInst): set(doName)},用于识别控制 DO。datasets:{ds_name: {"desc": ds_desc, "fcda": [fcda_dict]}},其中 fcda_dict 包含 ldInst, prefix, lnClass, lnInst, doName, daName, fc。
7. 使用说明
7.1 环境准备
- 安装 Python 3.6+。
- 安装 PyQt6:
pip install PyQt6。 - 准备 CSV 文件和数据类型模板 XML 文件。
7.2 CSV 格式要求
- 必须包含以下列(大小写敏感):
Type:取值Dataset或Control。Name:数据集名称(仅 Dataset 行需要)。LDName:逻辑设备实例名(如LD0,LD1)。prefix:LN 前缀(可为空)。LNInst:LN 实例号(可为空,表示 0)。LNType:逻辑节点类型 ID,必须与模板中的 LNodeType id 匹配。DOName:数据对象名称。DAName:数据属性完整路径(如stVal,mag.f)。FC:功能约束(如ST,MX,CO)。Desc:描述(可选,用于 DOI 的 desc 和 dU 的值)。sAddr:sAddr 属性值(可选)。
- 示例:
csv
Type,Name,LDName,prefix,LNInst,LNType,DOName,DAName,FC,Desc,sAddr
Dataset,dsAlm,LD0,,1,SQTECH_GGIO_ALM,Alm1,stVal,ST,遥信1,yx004
Control,,LD0,,1,SQTECH_GGIO_SPC,SPCSO1,Oper.ctlVal,CO,遥控1,yk000
7.3 数据类型模板要求
- 必须是有效的 XML 文件,包含
<DataTypeTemplates>根元素(可位于<SCL>内或作为根)。 - 模板中必须包含所有 CSV 中引用的 LNType、DOType、DAType、EnumType。
- 每个 LNodeType 必须有
lnClass属性。
7.4 操作步骤
- 运行程序:
python csv_to_cid.py。 - 点击“Browse CSV”选择 CSV 文件。
- 点击“Browse XML”选择数据类型模板文件。
- 输入 IED 名称(默认 IED1)。
- 点击“Parse CSV”预览数据。
- 点击“Generate CID”,选择保存路径。
- 查看调试窗口中的日志,确认无错误后,CID 文件生成成功。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)