编写高效的信号发生器自动化测试脚本需要兼顾代码性能、可维护性和测试覆盖率,同时适应不同硬件接口和测试场景。以下是分步骤的详细指南,涵盖脚本设计、优化技巧和最佳实践:
一、脚本设计阶段:模块化与可扩展性
1. 分层架构设计
- 驱动层:封装硬件操作(如SCPI命令发送、状态查询),屏蔽底层接口差异(GPIB/USB/LAN)。
| class SignalGeneratorDriver: |
| def __init__(self, interface='LAN', ip='192.168.1.100'): |
| self.conn = self._connect(interface, ip) |
|
| def _connect(self, interface, ip): |
| if interface == 'LAN': |
| return socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
| # 其他接口实现... |
|
| def set_frequency(self, freq): |
| self.conn.send(f"FREQ {freq}Hzn".encode()) |
| response = self.conn.recv(1024) |
| if "ERROR" in response: |
| raise RuntimeError(f"Set frequency failed: {response}") |
- 测试逻辑层:实现测试用例(如频率扫描、调制测试),复用驱动层方法。
| class FrequencySweepTest: |
| def __init__(self, driver): |
| self.driver = driver |
|
| def run(self, start, stop, step): |
| for freq in range(start, stop, step): |
| self.driver.set_frequency(freq) |
| # 验证信号输出... |
- 报告层:生成结构化测试报告(HTML/CSV/JSON),支持数据可视化。
2. 参数化设计
二、性能优化技巧
1. 异步与并行处理
- 多线程/多进程:对独立测试任务(如多台设备并行测试)使用
concurrent.futures。| from concurrent.futures import ThreadPoolExecutor |
|
| def test_device(driver): |
| # 单台设备测试逻辑... |
|
| with ThreadPoolExecutor(max_workers=4) as executor: |
| drivers = [SignalGeneratorDriver(ip=f"192.168.1.{i}") for i in range(1, 5)] |
| executor.map(test_device, drivers) |
- 异步I/O:对高延迟操作(如网络通信)使用
asyncio。| import asyncio |
|
| async def set_freq_async(driver, freq): |
| await driver.conn.send(f"FREQ {freq}Hzn".encode()) |
| response = await driver.conn.recv(1024) |
| # 处理响应... |
2. 批量操作与缓存
- 批量命令:合并多个SCPI命令为一条(如
FREQ 1MHz; AMPL 1Vpp),减少通信次数。 - 状态缓存:缓存设备当前状态(如频率、幅度),避免重复查询。
| class CachedDriver(SignalGeneratorDriver): |
| def __init__(self): |
| super().__init__() |
| self._cache = {"freq": None, "ampl": None} |
|
| def set_frequency(self, freq): |
| if self._cache["freq"] != freq: |
| super().set_frequency(freq) |
| self._cache["freq"] = freq |
3. 算法优化
- 数值计算:使用NumPy进行向量化操作,替代Python循环。
| import numpy as np |
|
| def generate_sine_wave(freq, samples): |
| t = np.linspace(0, 1, samples) |
| return np.sin(2 * np.pi * freq * t) |
- 查表法:预计算常用波形数据,减少实时计算开销。
三、硬件接口高效通信
1. 协议优化
2. 错误处理与重试机制
- 实现指数退避重试,避免因临时故障导致脚本崩溃。
| import time |
| import random |
|
| def send_command_with_retry(driver, cmd, max_retries=3): |
| for attempt in range(max_retries): |
| try: |
| driver.conn.send(cmd) |
| return driver.conn.recv(1024) |
| except (ConnectionError, TimeoutError) as e: |
| wait_time = 2 ** attempt + random.uniform(0, 1) |
| time.sleep(wait_time) |
| raise RuntimeError("Command failed after retries") |
四、测试数据管理与验证
1. 数据采集优化
- 触发同步:使用外部触发信号或软件触发(如
*TRG命令)确保测试与信号生成同步。 - 流式传输:对长时测试数据,采用流式传输而非一次性读取,减少内存占用。
2. 自动化验证
五、调试与日志
1. 分级日志
- 使用
logging模块记录不同级别日志(DEBUG/INFO/ERROR),便于问题定位。| import logging |
|
| logging.basicConfig( |
| level=logging.INFO, |
| format="%(asctime)s - %(levelname)s - %(message)s", |
| handlers=[ |
| logging.FileHandler("test.log"), |
| logging.StreamHandler() |
| ] |
| ) |
2. 远程调试
- 对嵌入式设备,通过SSH或串口实现远程日志查看和脚本控制。
六、完整脚本示例
| import socket |
| import logging |
| from concurrent.futures import ThreadPoolExecutor |
|
| # 配置日志 |
| logging.basicConfig(level=logging.INFO) |
| logger = logging.getLogger(__name__) |
|
| class SignalGeneratorDriver: |
| def __init__(self, ip): |
| self.ip = ip |
| self.conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM) |
| self.conn.connect((ip, 5025)) |
|
| def set_frequency(self, freq): |
| cmd = f"FREQ {freq}Hzn".encode() |
| self.conn.send(cmd) |
| response = self.conn.recv(1024).decode() |
| if "ERROR" in response: |
| logger.error(f"Set freq failed on {self.ip}: {response}") |
| raise RuntimeError(response) |
| logger.info(f"Set freq {freq}Hz on {self.ip}") |
|
| def run_test(driver, freq): |
| try: |
| driver.set_frequency(freq) |
| # 其他测试逻辑... |
| except Exception as e: |
| logger.error(f"Test failed for {driver.ip}: {str(e)}") |
|
| if __name__ == "__main__": |
| device_ips = ["192.168.1.101", "192.168.1.102"] |
| frequencies = [1e6, 2e6, 5e6] |
|
| with ThreadPoolExecutor(max_workers=len(device_ips)) as executor: |
| for ip in device_ips: |
| driver = SignalGeneratorDriver(ip) |
| for freq in frequencies: |
| executor.submit(run_test, driver, freq) |
七、关键优化点总结
八、进阶建议
- 硬件加速:对计算密集型任务(如FFT分析),使用CUDA或OpenCL在GPU上并行处理。
- CI/CD集成:将脚本纳入持续集成流程,自动触发回归测试。
- 机器学习辅助:利用历史测试数据训练模型,预测潜在故障点(如信号漂移趋势)。
通过以上方法,可显著提升脚本的执行效率、可维护性和测试覆盖率,适应从实验室研发到工业产线的多样化需求。