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 知识体系总览

我把本章的核心逻辑画成了一张图,方便你建立整体认知:

仿真数据基础——知识体系 仿真输出数据 CSV 格式 MAT 格式 TXT 格式 pandas.read_csv() scipy.io.loadmat() np.loadtxt() 关键注意点 • CSV:浮点数精度、大文件分块、表头规范 • MAT:版本兼容(v5/v7/v7.3)、结构体解包、字符串编码 • TXT:无元数据、需自定义解析规则

1.7 本章小结

说白了,仿真数据基础就三件事:

  1. 认清格式:CSV 通用但粗糙,MAT 完整但挑版本,TXT 灵活但费劲
  2. 选对工具:小数据用 pandas,大数据用 scipy.io,超大文件用 h5py
  3. 注意细节:版本、精度、编码——这三个坑我每个都踩过不止一次

我个人习惯是:仿真阶段全部用 .mat 保存,分析阶段按需转 CSV 给其他工具。这样既保留了原始精度,又兼顾了通用性。你刚开始做联调时,建议也这么来,能省掉很多不必要的麻烦。