編寫高效的信號發(fā)生器自動化測試腳本需要兼顧代碼性能、可維護(hù)性和測試覆蓋率,同時適應(yīng)不同硬件接口和測試場景。以下是分步驟的詳細(xì)指南,涵蓋腳本設(shè)計、優(yōu)化技巧和最佳實踐:
一、腳本設(shè)計階段:模塊化與可擴(kuò)展性
1. 分層架構(gòu)設(shè)計
- 驅(qū)動層:封裝硬件操作(如SCPI命令發(fā)送、狀態(tài)查詢),屏蔽底層接口差異(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) |
| # 其他接口實現(xiàn)... |
|
| 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}") |
- 測試邏輯層:實現(xiàn)測試用例(如頻率掃描、調(diào)制測試),復(fù)用驅(qū)動層方法。
| 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) |
| # 驗證信號輸出... |
- 報告層:生成結(jié)構(gòu)化測試報告(HTML/CSV/JSON),支持?jǐn)?shù)據(jù)可視化。
2. 參數(shù)化設(shè)計
二、性能優(yōu)化技巧
1. 異步與并行處理
- 多線程/多進(jìn)程:對獨立測試任務(wù)(如多臺設(shè)備并行測試)使用
concurrent.futures。| from concurrent.futures import ThreadPoolExecutor |
|
| def test_device(driver): |
| # 單臺設(shè)備測試邏輯... |
|
| 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:對高延遲操作(如網(wǎng)絡(luò)通信)使用
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) |
| # 處理響應(yīng)... |
2. 批量操作與緩存
- 批量命令:合并多個SCPI命令為一條(如
FREQ 1MHz; AMPL 1Vpp),減少通信次數(shù)。 - 狀態(tài)緩存:緩存設(shè)備當(dāng)前狀態(tài)(如頻率、幅度),避免重復(fù)查詢。
| 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. 算法優(yōu)化
- 數(shù)值計算:使用NumPy進(jìn)行向量化操作,替代Python循環(huán)。
| import numpy as np |
|
| def generate_sine_wave(freq, samples): |
| t = np.linspace(0, 1, samples) |
| return np.sin(2 * np.pi * freq * t) |
- 查表法:預(yù)計算常用波形數(shù)據(jù),減少實時計算開銷。
三、硬件接口高效通信
1. 協(xié)議優(yōu)化
2. 錯誤處理與重試機(jī)制
- 實現(xiàn)指數(shù)退避重試,避免因臨時故障導(dǎo)致腳本崩潰。
| 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") |
四、測試數(shù)據(jù)管理與驗證
1. 數(shù)據(jù)采集優(yōu)化
- 觸發(fā)同步:使用外部觸發(fā)信號或軟件觸發(fā)(如
*TRG命令)確保測試與信號生成同步。 - 流式傳輸:對長時測試數(shù)據(jù),采用流式傳輸而非一次性讀取,減少內(nèi)存占用。
2. 自動化驗證
五、調(diào)試與日志
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. 遠(yuǎn)程調(diào)試
- 對嵌入式設(shè)備,通過SSH或串口實現(xiàn)遠(yuǎn)程日志查看和腳本控制。
六、完整腳本示例
| 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) |
七、關(guān)鍵優(yōu)化點總結(jié)
八、進(jìn)階建議
- 硬件加速:對計算密集型任務(wù)(如FFT分析),使用CUDA或OpenCL在GPU上并行處理。
- CI/CD集成:將腳本納入持續(xù)集成流程,自動觸發(fā)回歸測試。
- 機(jī)器學(xué)習(xí)輔助:利用歷史測試數(shù)據(jù)訓(xùn)練模型,預(yù)測潛在故障點(如信號漂移趨勢)。
通過以上方法,可顯著提升腳本的執(zhí)行效率、可維護(hù)性和測試覆蓋率,適應(yīng)從實驗室研發(fā)到工業(yè)產(chǎn)線的多樣化需求。