1. 项目概述
作为一名长期与Simulink打交道的工程师,我深知模型文档维护的痛苦。每次模型迭代后,手动更新文档的工作量往往比修改模型本身还要大。截图、复制备注、整理Excel表格...这些重复劳动不仅耗时耗力,还容易出错。经过多次实践,我总结出一套完整的Simulink模型自动化转PDF方案,现在分享给同样受此困扰的同仁们。
这个方案的核心价值在于:
- 自动提取模型中的注释说明
- 将Excel中的参数表格直接转换为PDF格式
- 按模块层级自动生成模型结构图
- 保持文档与模型的实时同步
- 完全开源的工作流程
2. 技术方案设计
2.1 整体架构设计
整个系统采用Matlab作为核心处理引擎,配合Python进行PDF生成,架构分为三个主要模块:
- 数据提取层:通过Matlab API获取Simulink模型信息
- 数据处理层:整理模型结构、注释和参数数据
- 文档生成层:使用Python生成结构化的PDF文档
提示:选择Matlab+Python组合是因为Matlab对Simulink有原生支持,而Python的PDF生成库更丰富成熟。
2.2 关键技术选型
- Matlab版本:建议R2020b及以上,确保API兼容性
- Python库:
- reportlab:核心PDF生成
- pandas:Excel数据处理
- matplotlib:图像处理(可选)
- 版本控制:Git管理代码,便于团队协作
3. 核心实现细节
3.1 模型注释提取
模型中的注释是理解设计意图的关键。我们通过以下代码完整提取注释信息:
matlab复制function notes = extractModelNotes(modelPath)
% 加载模型
load_system(modelPath);
% 获取所有模块
blocks = find_system(modelPath, 'LookUnderMasks', 'all',...
'FollowLinks', 'on',...
'SearchDepth', Inf);
% 提取注释
notes = struct();
for i = 1:length(blocks)
blockPath = blocks{i};
try
comment = get_param(blockPath, 'Description');
if ~isempty(comment)
notes.(strrep(blockPath, '/', '_')) = comment;
end
catch
continue
end
end
end
这段代码的关键点:
LookUnderMasks和FollowLinks确保获取所有子模块- 使用try-catch避免无效模块导致的错误
- 将路径中的/替换为_作为字段名
3.2 Excel数据处理
参数表格的自动化处理流程:
- Matlab读取Excel:
matlab复制function data = readExcelData(filePath, sheetName)
opts = detectImportOptions(filePath);
opts.Sheet = sheetName;
data = readtable(filePath, opts);
% 处理缺失值
data = standardizeMissing(data, {'NA', 'NaN', ''});
end
- Python生成PDF表格:
python复制def create_parameter_table(pdf_path, data_df):
from reportlab.lib import colors
from reportlab.lib.pagesizes import A4
from reportlab.platypus import Table, TableStyle
# 转换DataFrame为列表
data = [data_df.columns.values.tolist()] + data_df.values.tolist()
# 创建表格样式
style = TableStyle([
('BACKGROUND', (0,0), (-1,0), colors.HexColor('#0072BD')),
('TEXTCOLOR', (0,0), (-1,0), colors.white),
('ALIGN', (0,0), (-1,-1), 'CENTER'),
('FONTNAME', (0,0), (-1,0), 'Helvetica-Bold'),
('FONTSIZE', (0,0), (-1,0), 12),
('BOTTOMPADDING', (0,0), (-1,0), 12),
('BACKGROUND', (0,1), (-1,-1), colors.HexColor('#EDF2F7')),
('GRID', (0,0), (-1,-1), 1, colors.black)
])
# 创建表格对象
table = Table(data)
table.setStyle(style)
return table
3.3 模型截图生成
自动生成分层截图的关键函数:
matlab复制function captureSubsystems(modelPath, outputDir)
if ~exist(outputDir, 'dir')
mkdir(outputDir)
end
% 获取所有子系统
subsystems = find_system(modelPath, 'BlockType', 'SubSystem');
for i = 1:length(subsystems)
sys = subsystems{i};
% 设置打印选项
printOpts = struct(...
'Format', 'png',...
'Resolution', 300,...
'ShowHiddenHandles', 'on',...
'PaperPositionMode', 'auto');
% 生成截图
print(['-s' sys], fullfile(outputDir, ['subsys_' num2str(i) '.png']),...
['-d' printOpts.Format],...
['-r' num2str(printOpts.Resolution)]);
end
end
4. 系统集成与优化
4.1 自动化工作流
完整的自动化流程脚本:
matlab复制function generateModelDoc(modelPath, excelPath, outputPdf)
% 提取模型信息
notes = extractModelNotes(modelPath);
captureSubsystems(modelPath, 'temp_images');
% 处理Excel数据
paramData = readExcelData(excelPath, 'Parameters');
% 调用Python生成PDF
system(['python generate_pdf.py '...
'--notes "' jsonencode(notes) '" '...
'--images_dir temp_images '...
'--params "' jsonencode(table2struct(paramData)) '" '...
'--output ' outputPdf]);
% 清理临时文件
rmdir('temp_images', 's');
end
对应的Python处理脚本:
python复制# generate_pdf.py
import argparse
import json
from reportlab.platypus import SimpleDocTemplate, Paragraph, Image, Spacer
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.pagesizes import A4
def main():
parser = argparse.ArgumentParser()
parser.add_argument('--notes', type=str)
parser.add_argument('--images_dir', type=str)
parser.add_argument('--params', type=str)
parser.add_argument('--output', type=str)
args = parser.parse_args()
# 创建PDF文档
doc = SimpleDocTemplate(args.output, pagesize=A4)
story = []
# 添加内容
add_notes(story, json.loads(args.notes))
add_images(story, args.images_dir)
add_params(story, json.loads(args.params))
# 生成PDF
doc.build(story)
if __name__ == '__main__':
main()
4.2 性能优化技巧
- 并行处理截图:
matlab复制parfor i = 1:length(subsystems)
% 截图代码
end
- 缓存机制:
- 记录模型MD5值
- 仅在模型修改后重新生成文档
- 增量更新:
- 只更新修改部分的文档内容
5. 实际应用经验
5.1 常见问题解决
- 中文乱码问题:
- 在Python中指定中文字体:
python复制from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
pdfmetrics.registerFont(TTFont('SimSun', 'SimSun.ttf'))
- 复杂模型截图不全:
- 调整打印边界:
matlab复制set_param(0, 'PrintBorder', 'off')
set_param(0, 'PrintWhite', 'on')
- Excel数据格式问题:
- 在Matlab中预处理数据:
matlab复制data = standardizeMissing(data, {'NA', 'N/A', ''});
data = fillmissing(data, 'constant', 0);
5.2 团队协作建议
- 版本控制:
- 将脚本与模型一起纳入Git管理
- 使用Git hooks自动触发文档生成
- 标准化模板:
- 统一PDF样式模板
- 制定注释编写规范
- CI/CD集成:
- 在Jenkins/GitLab CI中设置自动文档生成
- 文档随模型更新自动发布
6. 扩展应用
6.1 自定义模板支持
通过JSON定义PDF模板:
json复制{
"titleStyle": {
"font": "Helvetica-Bold",
"size": 16,
"color": "#003366"
},
"sectionStyle": {
"font": "Helvetica",
"size": 12,
"color": "#333333"
}
}
在Python中加载模板:
python复制def load_template(template_path):
with open(template_path) as f:
return json.load(f)
6.2 多格式输出支持
扩展支持HTML/Markdown输出:
python复制def export_html(notes, images, params, output_path):
# 生成HTML文档
pass
def export_markdown(notes, images, params, output_path):
# 生成Markdown文档
pass
6.3 模型差异对比
集成模型版本对比功能:
matlab复制function diff = compareModels(model1, model2)
% 使用Simulink自带的比较工具
diff = visdiff(model1, model2);
% 生成差异报告
exportReport(diff, 'ModelComparison.pdf');
end
这套系统在实际项目中已经稳定运行两年多,为团队节省了数百小时的文档维护时间。特别是在敏捷开发环境中,模型频繁迭代时,自动化文档更新的优势更加明显。