夜雨聆风学习资料网

ARTICLE · 1139893

开源版BPA电力系统分析软件解读-番外篇(一)BSE转CSV的python程序开发

开源版BPA电力系统分析软件解读-番外篇(一)BSE转CSV的python程序开发

从一堆乱码到一个 CSV 工具:BSE 转换程序诞生记

一、先搞清楚:BSE 到底是个什么东西

.BSE 不是普通文本文件。

它是 BPA 潮流程序(IPF)算完之后吐出来的二进制结果文件,里面存的是节点电压、支路功率、直流系统状态这些潮流计算的结果。

用记事本打开,只能看到一堆方块和问号。

所以第一件事,不是写代码,而是搞清楚它的格式。

二、第一关:Fortran 的"套娃"记录

打开二进制一看,发现这文件不是平铺直叙的,而是一段一段的。

每一段前面有个 4 字节的长度,后面跟着同样一个长度。这叫 Fortran 无格式记录(unformatted record),是 Fortran 写二进制时的老传统。

于是第一个模块诞生了:FortranRecordReader。

它干的活很朴素:

  • 读 4 字节,得到这一段的长度
  • 按这个长度把内容读出来
  • 再读末尾 4 字节,核对首尾长度是否一致

顺带还解决了一个大问题:大小端。

同一个文件,可能是小端机写的,也可能是大端机写的。程序不去猜,而是拿开头几个字节试一遍,哪种解释能自洽就用哪种。

这一步的意义:把"读文件"和"理解文件"拆开。读文件只负责搬运字节,理解交给后面。

三、第二关:把文件头读明白

字节能读了,接下来得知道每一段是什么。

文件开头是一段文件头,里面藏着:

  • 文件类型标记:必须是 PF DATA,不是就报错
  • 算例名、日期、标签、程序版本、用户
  • 一个 100 个整数的计数数组

这个计数数组很关键,它告诉程序:后面有多少母线、多少支路、多少直流、多少区域。

其中有一个字段叫 case_version,它决定了后面数据是老格式还是新格式。

这一下就分出了两条路:

  • _parse_old_body:老格式,数据分段打包,还要做一步"展开"和转换
  • 新格式路径:字段布局更规整,直接按结构读

这就是程序里第一个真正的分支。

四、第三关:老格式的"翻译工作"

老格式有个麻烦:它的数据不是按"一行一条记录"排的,而是按数组排的。

比如支路,先给你一串整数,再给你一串实数,得自己拼回去。

更麻烦的是,老格式里还有一些紧凑编码:几个浮点数其实是字符,几个整数其实是指针。

于是程序里出现了几个专门的"翻译官":

  • _convert_old_y_matrix:把打包的导纳矩阵展开成数组
  • _convert_old_branches:把紧凑的支路行还原成可读字段
  • int_from_float:把"存成浮点数的整数"还原成整数
  • decode_chars:把"存成浮点数的字符"还原成文字

这一步是整个程序最费脑子的地方,因为格式文档不全,很多细节只能靠对照结果反推。

五、第四关:把原始数据变成"人话"

字节读完了,格式也解开了,但拿到手的还是一堆数组。

数组是给机器看的,不是给人看的。

于是有了 build_xxx_rows 这一组函数:

  • build_bus_rows:一条母线一行,算出电压幅值和角度
  • build_branch_rows:一条支路一行,带首末端母线名
  • build_dc2t_rows:两端直流,带整流侧、逆变侧信息
  • build_dcmt_bus_rows:多端直流换流站
  • build_special_bus_rows:特殊母线
  • build_transformer_rows:变压器
  • build_owner_rows:设备所有者

它们的共同点是:把数组变成带列名的字典。

比如一条母线,不再是 [3, 525.0, 1.02, ...],而是:

bus_index, name, base_kv, voltage_pu, angle_deg, pload_mw ...

这一步的意义:让数据从"能读"变成"能看懂"。

六、第五关:一次导出十个文件

数据整理好了,最后一步是落盘。

write_outputs 负责把数据写成 CSV,一次生成十个文件:

  • summary.csv:算例概况,一眼看全局
  • buses.csv:母线结果
  • branches.csv:支路结果
  • dc2t.csv:两端直流
  • special_buses.csv:特殊母线
  • auto_transformers.csv:变压器
  • owners.csv:所有者
  • continuation_buses.csv:继续母线
  • switched_shunts.csv:可投切电抗器
  • parsed_records.csv:记录清单,方便排查格式

写文件时特意用了 UTF-8 BOM,这样中文用 Excel 双击打开不会乱码。

这是给"最终用户"的体贴。

七、第六关:让命令行"会说话"

工具能跑了,但用户不知道它跑到哪一步。

于是 main 里加了四步进度提示:

[1/4] Input BSE: ...[2/4] Reading Fortran records ...[2/4] Parsed 26 Fortran records[3/4] Writing CSV files ...[4/4] Conversion completed

出错时不是甩一堆堆栈,而是给一句人话:

error: not an IPF BSE file: header type is '...'

同时用退出码告诉调用方成功还是失败:

  • 0:成功
  • 1:文件格式或读写错误
  • 2:参数或路径错误

这一步的意义:工具不光要能用,还要好排查。

八、第七关:双击就能用

命令行虽好,但用户不一定习惯。

于是配了两样东西:

一个是 bse2csv.ini,把输入文件、输出目录、编码、精度都写进配置,改配置不用改代码:

ini
[DEFAULT]input_file = LCC-EXAM.BSEoutput_dir = outputencoding = utf-8-sigprecision = 8

一个是 bse2csv.bat,双击就能跑:

  • 自动找 python 或 py
  • 切到 UTF-8 代码页,避免中文乱码
  • 用 python -u 关闭缓冲,进度实时刷新
  • 跑完 pause,窗口不闪退
  • 失败时打印退出码,提示往上翻看错误

这一步的意义:把工具从"程序员能用"变成"谁都能用"。

九、回头看,这个程序的骨架其实很清晰

梳理下来,就六层:

  1. 读字节:FortranRecordReader
  2. 解格式:BseParser.parse,分老格式和新格式
  3. 转数据:_convert_old_*、int_from_float、decode_chars
  4. 建表格:build_xxx_rows
  5. 写文件:write_outputs
  6. 管交互:main + INI + BAT

一句话概括:

把"读二进制"和"看懂数据"分开,把"解析"和"展示"分开。


结尾

很多时候,工程工具就是这样:起点是一个具体的小问题,终点是一套能反复使用的流程,总体上还是:先读字节,再解格式,最后翻译成人话。


相关学习资料