这里模拟各种操作并断言结果
自动化模型框架搭建脚本,读取项目文件夹中的 XML 文件,提取出信号信息,创建模型的框架,然后根据输入信号和输出信号的数量添加对应的端口。 还能够动态更新XML文件,在原有模型基础上根据输入参数修改原有的模型,添加或删除对应的端口,最后将这些功能集成在一起,形成一个完整的自动化建模工具,提高模型构建的效率和准确性。 使用方法: 运行 model_builder_test 脚本即可对整个工具进行测试。 1、SignalsRecord 记录模型框架的输入输出信号名称和序号,这个模型搭建的基础。 2、当模型修改后,仍能够自动化更新模型接口,且不破环原有模型中的内容。 3、全部脚本皆开放,注释完整,同时分函数调用,是学习自动化Simulink建模的良好范例。 4、支持适当解惑。 5、详见说明文档
项目里需要频繁修改Simulink模型接口?手工操作容易出错还费时间?这个用Python写的自动化建模工具能让你彻底摆脱重复劳动。核心就三件事:解析XML信号配置、自动生成模型框架、动态维护接口一致性。

先看怎么吃透XML配置。用xml.etree.ElementTree模块解析文件时,关键要处理嵌套结构:
def parse_signals(xml_path):
tree = ET.parse(xml_path)
root = tree.getroot()
signals = {'input': [], 'output': []}
for port in root.findall('.//port'):
port_type = port.get('type')
name = port.find('name').text
index = int(port.find('index').text)
signals[port_type].append({'name': name, 'index': index})
return signals
这段代码特别处理了XML里的port标签,按输入输出分类存储信号名和序号。注意.findall()方法里的XPath表达式,这个.//port写法能穿透任意层级的嵌套,比写死路径更灵活。
生成的信号记录类SignalsRecord才是灵魂所在。它用两个OrderedDict分别存输入输出信号,保证顺序不会乱:
class SignalsRecord:
def __init__(self):
self.inputs = OrderedDict()
self.outputs = OrderedDict()
def add_signal(self, signal_type, name, index):
target = self.inputs if signal_type == 'input' else self.outputs
if name not in target:
target[name] = index
print(f"Added {signal_type} port: {name}[{index}]")
用OrderedDict而不用普通字典,是因为模型端口序号必须严格对应。这里有个小技巧——添加新信号时自动检查是否重名,避免重复添加。

自动化模型框架搭建脚本,读取项目文件夹中的 XML 文件,提取出信号信息,创建模型的框架,然后根据输入信号和输出信号的数量添加对应的端口。 还能够动态更新XML文件,在原有模型基础上根据输入参数修改原有的模型,添加或删除对应的端口,最后将这些功能集成在一起,形成一个完整的自动化建模工具,提高模型构建的效率和准确性。 使用方法: 运行 model_builder_test 脚本即可对整个工具进行测试。 1、SignalsRecord 记录模型框架的输入输出信号名称和序号,这个模型搭建的基础。 2、当模型修改后,仍能够自动化更新模型接口,且不破环原有模型中的内容。 3、全部脚本皆开放,注释完整,同时分函数调用,是学习自动化Simulink建模的良好范例。 4、支持适当解惑。 5、详见说明文档
动态更新模型最考验代码设计。看这个增量更新函数怎么玩转XML节点:
def update_xml_port(xml_path, new_port, operation='add'):
tree = ET.parse(xml_path)
root = tree.getroot()
ports_node = root.find('.//ports')
existing = [p for p in ports_node if p.find('name').text == new_port['name']]
if operation == 'add' and not existing:
port_node = ET.SubElement(ports_node, 'port', type=new_port['type'])
ET.SubElement(port_node, 'name').text = new_port['name']
ET.SubElement(port_node, 'index').text = str(new_port['index'])
elif operation == 'del' and existing:
ports_node.remove(existing[0])
tree.write(xml_path, encoding='utf-8', xml_declaration=True)
处理新增和删除操作时,先用XPath定位现有节点。有个坑要注意——ET模块默认不保留XML声明,所以write时要显式加上xml_declaration=True参数,否则再次读取可能报错。

测试环节建议用pytest搞个参数化测试,模拟各种边界情况。比如测试删除不存在的端口时会不会报错:
@pytest.mark.parametrize("port_data,expected", [
({'type':'input','name':'throttle','index':3}, "Add"),
({'type':'output','name':'RPM','index':2}, "DelFail")
])
def test_port_operations(port_data, expected):
assert operation_log.startswith(expected)
这种测试用例能有效防止手滑误删关键端口。建议用临时文件做测试沙盒,别直接动生产环境的配置文件。
实际用起来,先跑modelbuildertest.py看demo效果。注意系统环境变量可能需要配Python的PYTHONPATH,把项目目录加进去才能正确导入模块。遇到XML格式错误时,工具会抛出自定义的ConfigException,这时候去查说明文档里的XML模板示例最快。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐
所有评论(0)