1. 仿真数据基础:理解仿真输出格式与 Python 读取 .mat 文件
做仿真联调,第一关就是跟数据格式打交道。我刚开始带项目时,团队里有人把 .mat 文件当文本打开,结果满屏乱码,折腾了半天才发现是格式不对。说白了,搞懂数据怎么存、怎么读,后面所有分析才能站得住脚。
1.1 常见的仿真输出格式
仿真工具导出的数据,无非就这几种格式。我列个表,你一眼就能看明白差异:
| 格式 | 特点 | 典型场景 | 我踩过的坑 |
|---|---|---|---|
| CSV | 纯文本,逗号分隔,通用性极强 | Simulink 导出、Excel 预览 | 浮点数精度丢失,尤其是 1e-6 级别 |
| MAT | 二进制,保留变量名、维度、类型 | MATLAB 原生存储、复杂结构 | 版本不兼容(v5/v7/v7.3) |
| TXT | 自由格式,空格/制表符分隔 | 自定义日志、老旧工具 | 没有元数据,全靠猜 |
核心原则:能用 .mat 就别用 CSV,除非你要给非技术人员看。.mat 保留了数据类型和结构,省去大量解析工作。
1.2 CSV 格式——最通用也最坑
CSV 看起来简单,但坑不少。我记得有一次做雷达信号处理,仿真输出 100 万行数据,用 Excel 打开直接卡死。后来改用 Python 的 pandas.read_csv() 才搞定。
读取 CSV 的标准姿势:
import pandas as pd
# 最基础读取
df = pd.read_csv('sim_result.csv')
# 如果数据没有表头
df = pd.read_csv('sim_result.csv', header=None)
# 指定列名
df = pd.read_csv('sim_result.csv', names=['time', 'voltage', 'current'])
# 处理大文件——分块读取
chunk_iter = pd.read_csv('sim_result.csv', chunksize=10000)
for chunk in chunk_iter:
process(chunk) # 你的处理逻辑
我的习惯:CSV 文件第一行永远写列名。别偷懒,否则三个月后你自己都看不懂哪列是哪列。
1.3 MAT 格式——MATLAB 的看家本领
.mat 文件是 MATLAB 的二进制存储格式。它不像 CSV 那样能直接打开看,但好处是保留了所有信息:变量名、数据类型、维度、甚至结构体嵌套。
MAT 文件有 3 个版本,你想想看,版本不对就读不了:
- v5:最老,兼容性最好,但文件大
- v7:默认格式,支持压缩
- v7.3:支持 2GB 以上大文件,基于 HDF5
注意:Python 的 scipy.io.loadmat() 读不了 v7.3 格式。我曾经因为这个排查了半天,最后发现是版本问题。v7.3 要用 h5py 库来读。
1.4 Python 读取 .mat 文件——基础操作
用 Python 读 .mat 文件,最常用的就是 scipy.io。我一般这么写:
import scipy.io as sio
import numpy as np
# 读取 .mat 文件
mat_data = sio.loadmat('simulation_output.mat')
# 查看所有变量名
print(mat_data.keys())
# 提取具体变量
time = mat_data['time'] # 时间向量
signal = mat_data['signal'] # 信号数据
params = mat_data['params'] # 参数结构体
# 如果是结构体,需要进一步解包
fs = params['fs'][0][0] # 采样率
n_samples = params['N'][0][0] # 采样点数
这里有个细节:loadmat 返回的是字典,变量名就是键。但 MATLAB 的结构体在 Python 里会变成嵌套的 numpy 数组,取数据时要注意索引。
避坑指南:MATLAB 的字符串在 .mat 里存成 char 数组,读出来是 numpy 的 bytes 类型。我一般用 .decode('utf-8') 转成正常字符串。
1.5 实战:从 .mat 中提取仿真波形
举个实际例子。假设你有一个雷达回波仿真结果,里面存了 3 个变量:
time:时间轴,1×10000 向量echo:回波信号,1×10000 复数向量config:仿真参数结构体
读取并提取实部/虚部:
import scipy.io as sio
import numpy as np
import matplotlib.pyplot as plt
# 读取数据
data = sio.loadmat('radar_echo.mat')
time = data['time'].flatten()
echo = data['echo'].flatten()
config = data['config']
# 提取参数
prf = config['PRF'][0][0] # 脉冲重复频率
fc = config['fc'][0][0] # 载频
# 分离实部虚部
echo_real = np.real(echo)
echo_imag = np.imag(echo)
# 简单绘图
plt.figure(figsize=(10, 4))
plt.plot(time, echo_real, label='实部')
plt.plot(time, echo_imag, label='虚部', alpha=0.7)
plt.xlabel('时间 (s)')
plt.ylabel('幅度')
plt.legend()
plt.grid(True)
plt.show()
嗯,这里要注意:flatten() 是为了把二维数组拉平成一维,否则绘图时会报维度错误。
1.6 知识体系总览
我把本章的核心逻辑画成了一张图,方便你建立整体认知:
1.7 本章小结
说白了,仿真数据基础就三件事:
- 认清格式:CSV 通用但粗糙,MAT 完整但挑版本,TXT 灵活但费劲
- 选对工具:小数据用
pandas,大数据用scipy.io,超大文件用h5py - 注意细节:版本、精度、编码——这三个坑我每个都踩过不止一次
我个人习惯是:仿真阶段全部用 .mat 保存,分析阶段按需转 CSV 给其他工具。这样既保留了原始精度,又兼顾了通用性。你刚开始做联调时,建议也这么来,能省掉很多不必要的麻烦。