第2章:测试系统架构设计
好,咱们接着聊。上一章我们搭好了环境,这一章,我来聊聊整个测试系统的骨架——架构设计。
很多人一上来就写代码,写到后面发现改一个功能要动全身。我早期也犯过这个错。后来我总结出一套四层架构,用了好多年,基本没大改过。
2.1 四层架构,各司其职
我把整个测试系统拆成四层:硬件层、驱动层、应用层、数据层。每一层只干自己的事,不越界。
| 层级 | 职责 | 典型组件 |
|---|---|---|
| 硬件层 | 物理连接、信号调理 | PXI机箱、射频开关矩阵、DUT板 |
| 驱动层 | 硬件抽象、指令封装 | VISA驱动、DLL封装、SCPI命令 |
| 应用层 | 测试流程、业务逻辑 | 测试序列、参数配置、结果判断 |
| 数据层 | 数据存储、统计分析 | SQLite、CSV导出、MES对接 |
核心原则:上层只能调用相邻下层,不能跨层调用。比如应用层不能直接操作硬件寄存器,必须通过驱动层。
2.2 硬件层:物理世界的接口
硬件层是最底层。说白了,就是你的仪器和DUT之间的物理连接。
我个人习惯把硬件层分成两部分:
- 仪器资源:万用表、频谱仪、信号源、射频开关等
- 接口适配:DUT板、探针卡、线缆、转接板
这里有个坑。我曾经遇到过,射频开关的寿命只有10万次,产线一天跑几千次,两个月就挂了。所以硬件层设计时,一定要考虑冗余和可替换性。
注意:硬件层的选型直接影响测试效率。比如用PXI比用GPIB快10倍以上。产线测试,时间就是钱。
2.3 驱动层:让硬件“说人话”
驱动层是硬件和软件之间的翻译官。你想想看,仪器返回的是电压值,应用层需要的是“通过/失败”,中间这层就是干这个的。
我一般这样设计驱动层:
class PowerSupply:
def __init__(self, resource_name):
self.rm = pyvisa.ResourceManager()
self.instr = self.rm.open_resource(resource_name)
def set_voltage(self, voltage):
self.instr.write(f"VOLT {voltage}")
def get_current(self):
return float(self.instr.query("MEAS:CURR?"))
看到没?每个仪器一个类,方法名统一。这样上层调用时,根本不用管底层是GPIB还是USB。
我的经验:驱动层一定要做超时处理和重试机制。产线环境复杂,偶尔通信失败很正常。我曾经因为没加重试,导致整条线停了半小时。
2.4 应用层:测试的大脑
应用层是核心。它负责调度测试流程、判断结果、处理异常。
我习惯把应用层拆成三个模块:
- 测试序列管理器:定义测试步骤的顺序和依赖关系
- 参数配置器:管理测试限值、频率、功率等参数
- 结果判断器:根据测试数据给出PASS/FAIL
举个例子,一个典型的TPMS测试序列:
test_sequence = [
{"name": "电流测试", "func": test_current, "limits": (0.5, 2.0)},
{"name": "频率测试", "func": test_frequency, "limits": (433.85, 433.95)},
{"name": "功率测试", "func": test_power, "limits": (5.0, 10.0)},
]
这样设计的好处是,新增一个测试项,只需要在列表里加一行,不用改任何逻辑代码。
模块化设计原则:每个模块只做一件事,并且做好。比如结果判断器,只负责比较数值,不负责存储数据。
2.5 数据层:让数据说话
数据层负责把测试结果存起来,方便后续分析。
我一般用两种方式:
- 本地存储:SQLite数据库,适合单机产线
- 云端对接:通过MES接口上传到服务器
数据层的设计要点:
class DataLogger:
def save_result(self, sn, test_name, value, result):
# 保存到SQLite
cursor.execute("INSERT INTO results VALUES (?,?,?,?)",
(sn, test_name, value, result))
# 同时生成CSV备份
with open("backup.csv", "a") as f:
f.write(f"{sn},{test_name},{value},{result}\n")
嗯,这里要注意。数据层一定要做缓冲。产线测试频率高,如果每次测试都直接写数据库,I/O会成为瓶颈。我建议用队列缓冲,批量写入。
避坑指南:我曾经遇到过,数据库文件损坏导致整批数据丢失。从那以后,我坚持“双写”策略——数据库和CSV同时写,互相备份。
2.6 模块化设计,灵活可扩展
四层架构的核心思想就是模块化。每一层内部也应该是模块化的。
我总结了几条原则:
- 高内聚:一个模块只做一件事
- 低耦合:模块之间通过接口通信,不直接依赖
- 可替换:换一个仪器,只改驱动层,不动应用层
- 可测试:每个模块都能单独测试
举个例子,如果产线要换频谱仪,从Keysight换成Rohde & Schwarz,我只需要写一个新的驱动类,继承同一个接口。应用层代码一行都不用改。
我的习惯:每个模块都写一个单元测试。虽然前期花点时间,但后期改代码时,心里踏实多了。
2.7 架构设计的取舍
说实话,四层架构不是万能的。小项目用这个架构,反而显得臃肿。
我个人建议:
- 产线超过2台测试工位,用四层架构
- 只有1台工位,可以简化成三层(硬件、逻辑、数据)
- 研发验证阶段,甚至两层就够了(硬件+脚本)
但不管怎么简化,模块化的思想不能丢。你想想看,如果代码写成一坨,后面改起来有多痛苦?
好,这一章就聊到这里。下一章我们开始动手,写一个完整的驱动层代码。